when cyclic is enabled the knots would always be generated with uniform nurbs but...
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is written by Rob Haarsma (phase)
21  * All rights reserved.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
28  * Additional information can be found at the bottom of this file.
29  *
30  * Code that uses exotic character maps is present but commented out.
31  */
32
33 #ifdef WITH_FREETYPE2
34
35 #ifdef WIN32
36 #pragma warning (disable:4244)
37 #endif
38
39 #include <ft2build.h>
40 #include FT_FREETYPE_H
41 #include FT_GLYPH_H
42 #include FT_BBOX_H
43 #include FT_SIZES_H
44 #include <freetype/ttnameid.h>
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_vfontdata.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_arithb.h"  
51
52 #include "BIF_toolbox.h"
53
54 #include "BKE_global.h"
55 #include "BKE_utildefines.h"
56
57 #include "DNA_vfont_types.h"
58 #include "DNA_packedFile_types.h"
59 #include "DNA_curve_types.h"
60
61 #define myMIN_ASCII     32
62 #define myMAX_ASCII     255
63
64 /* local variables */
65 static FT_Library       library;
66 static FT_Error         err;
67
68
69 void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
70 {
71         // Blender
72         struct Nurb *nu;
73         struct VChar *che;
74         struct BezTriple *bezt;
75         
76         // Freetype2
77         FT_GlyphSlot glyph;
78         FT_UInt glyph_index;
79         FT_Outline ftoutline;
80         float scale, height;
81         float dx, dy;
82         int j,k,l,m=0;
83         
84         // adjust font size
85         height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
86         if(height != 0.0)
87                 scale = 1.0 / height;
88         else
89                 scale = 1.0 / 1000.0;
90         
91         //      
92         // Generate the character 3D data
93         //
94         // Get the FT Glyph index and load the Glyph
95         glyph_index= FT_Get_Char_Index(face, charcode);
96         err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
97         
98         // If loading succeeded, convert the FT glyph to the internal format
99         if(!err)
100         {
101                 int *npoints;
102                 int *onpoints;
103                 
104                 // First we create entry for the new character to the character list
105                 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
106                 BLI_addtail(&vfd->characters, che);
107                 
108                 // Take some data for modifying purposes
109                 glyph= face->glyph;
110                 ftoutline= glyph->outline;
111                 
112                 // Set the width and character code
113                 che->index= charcode;
114                 che->width= glyph->advance.x * scale;
115                 
116                 // Start converting the FT data
117                 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
118                 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
119
120                 // calculate total points of each contour
121                 for(j = 0; j < ftoutline.n_contours; j++) {
122                         if(j == 0)
123                                 npoints[j] = ftoutline.contours[j] + 1;
124                         else
125                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
126                 }
127
128                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
129                 for(j = 0; j < ftoutline.n_contours; j++) {
130                         l = 0;
131                         for(k = 0; k < npoints[j]; k++) {
132                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
133                                         if(ftoutline.tags[l] == FT_Curve_Tag_On)
134                                                 onpoints[j]++;
135
136                                 if(k < npoints[j] - 1 )
137                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
138                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
139                                                 onpoints[j]++;
140                         }
141                 }
142
143                 //contour loop, bezier & conic styles merged
144                 for(j = 0; j < ftoutline.n_contours; j++) {
145                         // add new curve
146                         nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
147                         bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
148                         BLI_addtail(&che->nurbsbase, nu);
149
150                         nu->type= CU_BEZIER+CU_2D;
151                         nu->pntsu = onpoints[j];
152                         nu->resolu= 8;
153                         nu->flagu= CU_CYCLIC;
154                         nu->bezt = bezt;
155
156                         //individual curve loop, start-end
157                         for(k = 0; k < npoints[j]; k++) {
158                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
159                                 if(k == 0) m = l;
160                                         
161                                 //virtual conic on-curve points
162                                 if(k < npoints[j] - 1 )
163                                 {
164                                         if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
165                                                 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
166                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
167
168                                                 //left handle
169                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
170                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
171
172                                                 //midpoint (virtual on-curve point)
173                                                 bezt->vec[1][0] = dx;
174                                                 bezt->vec[1][1] = dy;
175
176                                                 //right handle
177                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
178                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
179
180                                                 bezt->h1= bezt->h2= HD_ALIGN;
181                                                 bezt++;
182                                         }
183                                 }
184
185                                 //on-curve points
186                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
187                                         //left handle
188                                         if(k > 0) {
189                                                 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
190                                                         bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
191                                                         bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
192                                                         bezt->h1= HD_FREE;
193                                                 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
194                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
195                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
196                                                         bezt->h1= HD_FREE;
197                                                 } else {
198                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
199                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
200                                                         bezt->h1= HD_VECT;
201                                                 }
202                                         } else { //first point on curve
203                                                 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
204                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
205                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
206                                                         bezt->h1= HD_FREE;
207                                                 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
208                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
209                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
210                                                         bezt->h1= HD_FREE;
211                                                 } else {
212                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
213                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
214                                                         bezt->h1= HD_VECT;
215                                                 }
216                                         }
217
218                                         //midpoint (on-curve point)
219                                         bezt->vec[1][0] = ftoutline.points[l].x* scale;
220                                         bezt->vec[1][1] = ftoutline.points[l].y* scale;
221
222                                         //right handle
223                                         if(k < (npoints[j] - 1)) {
224                                                 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
225                                                         bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
226                                                         bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
227                                                         bezt->h2= HD_FREE;
228                                                 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
229                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
230                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
231                                                         bezt->h2= HD_FREE;
232                                                 } else {
233                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
234                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
235                                                         bezt->h2= HD_VECT;
236                                                 }
237                                         } else { //last point on curve
238                                                 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
239                                                         bezt->vec[2][0] = ftoutline.points[m].x* scale;
240                                                         bezt->vec[2][1] = ftoutline.points[m].y* scale;
241                                                         bezt->h2= HD_FREE;
242                                                 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
243                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
244                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
245                                                         bezt->h2= HD_FREE;
246                                                 } else {
247                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
248                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
249                                                         bezt->h2= HD_VECT;
250                                                 }
251                                         }
252
253                                         // get the handles that are aligned, tricky...
254                                         // DistVL2Dfl, check if the three beztriple points are on one line
255                                         // VecLenf, see if there's a distance between the three points
256                                         // VecLenf again, to check the angle between the handles 
257                                         // finally, check if one of them is a vector handle 
258                                         if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
259                                                 (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
260                                                 (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
261                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
262                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
263                                                 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
264                                         {
265                                                 bezt->h1= bezt->h2= HD_ALIGN;
266                                         }
267                                         bezt++;
268                                 }
269                         }
270                 }
271                 if(npoints) MEM_freeN(npoints);
272                 if(onpoints) MEM_freeN(onpoints);       
273         }
274 }
275
276 int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
277 {
278         // Freetype2
279         FT_Face face;
280         struct TmpFont *tf;
281         
282         // Find the correct FreeType font
283         tf= G.ttfdata.first;
284         while(tf)
285         {
286                 if(tf->vfont == vfont)
287                         break;
288                 tf= tf->next;           
289         }
290         
291         // What, no font found. Something strange here
292         if(!tf) return FALSE;
293         
294         // Load the font to memory
295         if(tf->pf)
296         {
297                 err= FT_New_Memory_Face( library,
298                         tf->pf->data,
299                         tf->pf->size,
300                         0,
301                         &face);                 
302         }
303         else
304                 err= TRUE;
305                 
306         // Read the char
307         freetypechar_to_vchar(face, charcode, vfont->data);
308         
309         // And everything went ok
310         return TRUE;
311 }
312
313
314 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
315 {
316         // Variables
317         FT_Face face;
318         FT_ULong charcode = 0, lcode;
319         FT_UInt glyph_index;
320         const char *fontname;
321         VFontData *vfd;
322
323 /*
324         FT_CharMap  found = 0;
325         FT_CharMap  charmap;
326         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
327         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
328         int         n;
329 */
330
331         // load the freetype font
332         err = FT_New_Memory_Face( library,
333                                                 pf->data,
334                                                 pf->size,
335                                                 0,
336                                                 &face );
337
338         if(err) return NULL;
339 /*
340         for ( n = 0; n < face->num_charmaps; n++ )
341         {
342                 charmap = face->charmaps[n];
343                 if ( charmap->platform_id == my_platform_id &&
344                         charmap->encoding_id == my_encoding_id )
345                 {
346                         found = charmap;
347                         break;
348                 }
349         }
350
351         if ( !found ) { return NULL; }
352
353         // now, select the charmap for the face object
354         err = FT_Set_Charmap( face, found );
355         if ( err ) { return NULL; }
356 */
357
358         // allocate blender font
359         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
360
361         // get the name
362         fontname = FT_Get_Postscript_Name(face);
363         strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
364
365         // Extract the first 256 character from TTF
366         lcode= charcode= FT_Get_First_Char(face, &glyph_index);
367
368         // No charmap found from the ttf so we need to figure it out
369         if(glyph_index == 0)
370         {
371                 FT_CharMap  found = 0;
372                 FT_CharMap  charmap;
373                 int n;
374
375                 for ( n = 0; n < face->num_charmaps; n++ )
376                 {
377                         charmap = face->charmaps[n];
378                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
379                         {
380                                 found = charmap;
381                                 break;
382                         }
383                 }
384
385                 err = FT_Set_Charmap( face, found );
386
387                 if( err ) 
388                         return NULL;
389
390                 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
391         }
392
393         // Load characters
394         while(charcode < 256)
395         {
396                 // Generate the font data
397                 freetypechar_to_vchar(face, charcode, vfd);
398
399                 // Next glyph
400                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
401
402                 // Check that we won't start infinite loop
403                 if(charcode <= lcode)
404                         break;
405                 lcode = charcode;
406         }
407         
408         err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE );
409
410         return vfd;     
411 }
412
413
414 static int check_freetypefont(PackedFile * pf)
415 {
416         FT_Face                 face;
417         FT_GlyphSlot    glyph;
418         FT_UInt                 glyph_index;
419 /*
420         FT_CharMap  charmap;
421         FT_CharMap  found;
422         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
423         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
424         int         n;
425 */
426         int success = 0;
427
428         err = FT_New_Memory_Face( library,
429                                                         pf->data,
430                                                         pf->size,
431                                                         0,
432                                                         &face );
433         if(err) {
434                 success = 0;
435             error("This is not a valid font");
436         }
437         else {
438 /*
439                 for ( n = 0; n < face->num_charmaps; n++ )
440                 {
441                   charmap = face->charmaps[n];
442                   if ( charmap->platform_id == my_platform_id &&
443                            charmap->encoding_id == my_encoding_id )
444                   {
445                         found = charmap;
446                         break;
447                   }
448                 }
449
450                 if ( !found ) { return 0; }
451
452                 // now, select the charmap for the face object 
453                 err = FT_Set_Charmap( face, found );
454                 if ( err ) { return 0; }
455 */
456                 glyph_index = FT_Get_Char_Index( face, 'A' );
457                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
458                 if(err) success = 0;
459                 else {
460                         glyph = face->glyph;
461                         if (glyph->format == ft_glyph_format_outline ) {
462                                 success = 1;
463                         } else {
464                                 error("Selected Font has no outline data");
465                                 success = 0;
466                         }
467                 }
468         }
469         
470         return success;
471 }
472
473
474 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
475 {
476         VFontData *vfd= NULL;
477         int success = 0;
478
479         //init Freetype 
480         err = FT_Init_FreeType( &library);
481         if(err) {
482                 error("Failed to load the Freetype font library");
483                 return 0;
484         }
485
486         success = check_freetypefont(pf);
487         
488         if (success) {
489                 vfd= objfnt_to_ftvfontdata(pf);
490         }
491
492         //free Freetype
493         FT_Done_FreeType( library);
494         
495         return vfd;
496 }
497
498 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
499 {
500         int success = FALSE;
501
502         if(!vfont) return FALSE;
503
504         // Init Freetype
505         err = FT_Init_FreeType(&library);
506         if(err) {
507                 error("Failed to load the Freetype font library");
508                 return 0;
509         }
510
511         // Load the character
512         success = objchr_to_ftvfontdata(vfont, character);
513         if(success == FALSE) return FALSE;
514
515         // Free Freetype
516         FT_Done_FreeType(library);
517
518         // Ahh everything ok
519         return TRUE;
520 }
521
522 #endif // WITH_FREETYPE2
523
524
525
526 #if 0
527
528 // Freetype2 Outline struct
529
530 typedef struct  FT_Outline_
531   {
532     short       n_contours;      /* number of contours in glyph        */
533     short       n_points;        /* number of points in the glyph      */
534
535     FT_Vector*  points;          /* the outline's points               */
536     char*       tags;            /* the points flags                   */
537     short*      contours;        /* the contour end points             */
538
539     int         flags;           /* outline masks                      */
540
541   } FT_Outline;
542
543 #endif
544
545 /***//*
546 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
547
548 Vectorial representation of Freetype glyphs
549
550 The source format of outlines is a collection of closed paths called "contours". Each contour is
551 made of a series of line segments and bezier arcs. Depending on the file format, these can be
552 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
553 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
554 Type1 format.
555
556 Each arc is described through a series of start, end and control points. Each point of the outline
557 has a specific tag which indicates wether it is used to describe a line segment or an arc.
558
559
560 The following rules are applied to decompose the contour's points into segments and arcs :
561
562 # two successive "on" points indicate a line segment joining them.
563
564 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
565   the control point, and the "on" ones the start and end points.
566
567 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
568   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
569   "off" point between two "on" points is forbidden, for example).
570
571 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
572   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
573   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
574   outlines are described in the TrueType specification.
575
576 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
577 font driver produces such outlines.
578
579                                   *            # on      
580                                                * off
581                                __---__
582   #-__                      _--       -_
583       --__                _-            -
584           --__           #               \
585               --__                        #
586                   -#
587                            Two "on" points
588    Two "on" points       and one "conic" point
589                             between them
590
591
592
593                 *
594   #            __      Two "on" points with two "conic"
595    \          -  -     points between them. The point
596     \        /    \    marked '0' is the middle of the
597      -      0      \   "off" points, and is a 'virtual'
598       -_  _-       #   "on" point where the curve passes.
599         --             It does not appear in the point
600                        list.
601         *
602
603
604
605
606         *                # on
607                    *     * off
608          __---__
609       _--       -_
610     _-            -
611    #               \
612                     #
613
614      Two "on" points
615    and two "cubic" point
616       between them
617
618
619 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
620 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
621 range from -16384 to 16383.
622
623 Convert conic to bezier arcs:
624 Conic P0 P1 P2
625 Bezier B0 B1 B2 B3
626 B0=P0
627 B1=(P0+2*P1)/3
628 B2=(P2+2*P1)/3
629 B3=P2
630
631 *//****/