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