Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is written by Rob Haarsma (phase) 00019 * All rights reserved. 00020 * 00021 * Contributor(s): none yet. 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 * 00025 * This code parses the Freetype font outline data to chains of Blender's beziertriples. 00026 * Additional information can be found at the bottom of this file. 00027 * 00028 * Code that uses exotic character maps is present but commented out. 00029 */ 00030 00036 #ifdef WIN32 00037 #pragma warning (disable:4244) 00038 #endif 00039 00040 #include <ft2build.h> 00041 #include FT_FREETYPE_H 00042 /* not needed yet */ 00043 // #include FT_GLYPH_H 00044 // #include FT_BBOX_H 00045 // #include FT_SIZES_H 00046 // #include <freetype/ttnameid.h> 00047 00048 #include "MEM_guardedalloc.h" 00049 00050 #include "BLI_vfontdata.h" 00051 #include "BLI_blenlib.h" 00052 #include "BLI_math.h" 00053 #include "BLI_utildefines.h" 00054 00055 //XXX #include "BIF_toolbox.h" 00056 00057 #include "BKE_font.h" 00058 00059 00060 #include "DNA_vfont_types.h" 00061 #include "DNA_packedFile_types.h" 00062 #include "DNA_curve_types.h" 00063 00064 #define myMIN_ASCII 32 00065 #define myMAX_ASCII 255 00066 00067 /* local variables */ 00068 static FT_Library library; 00069 static FT_Error err; 00070 00071 00072 static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) 00073 { 00074 // Blender 00075 struct Nurb *nu; 00076 struct VChar *che; 00077 struct BezTriple *bezt; 00078 00079 // Freetype2 00080 FT_GlyphSlot glyph; 00081 FT_UInt glyph_index; 00082 FT_Outline ftoutline; 00083 float scale, height; 00084 float dx, dy; 00085 int j,k,l,m=0; 00086 00087 // adjust font size 00088 height= ((double) face->bbox.yMax - (double) face->bbox.yMin); 00089 if(height != 0.0f) 00090 scale = 1.0f / height; 00091 else 00092 scale = 1.0f / 1000.0f; 00093 00094 // 00095 // Generate the character 3D data 00096 // 00097 // Get the FT Glyph index and load the Glyph 00098 glyph_index= FT_Get_Char_Index(face, charcode); 00099 err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); 00100 00101 // If loading succeeded, convert the FT glyph to the internal format 00102 if(!err) 00103 { 00104 int *npoints; 00105 int *onpoints; 00106 00107 // First we create entry for the new character to the character list 00108 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char"); 00109 BLI_addtail(&vfd->characters, che); 00110 00111 // Take some data for modifying purposes 00112 glyph= face->glyph; 00113 ftoutline= glyph->outline; 00114 00115 // Set the width and character code 00116 che->index= charcode; 00117 che->width= glyph->advance.x * scale; 00118 00119 // Start converting the FT data 00120 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ; 00121 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ; 00122 00123 // calculate total points of each contour 00124 for(j = 0; j < ftoutline.n_contours; j++) { 00125 if(j == 0) 00126 npoints[j] = ftoutline.contours[j] + 1; 00127 else 00128 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; 00129 } 00130 00131 // get number of on-curve points for beziertriples (including conic virtual on-points) 00132 for(j = 0; j < ftoutline.n_contours; j++) { 00133 for(k = 0; k < npoints[j]; k++) { 00134 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; 00135 if(ftoutline.tags[l] == FT_Curve_Tag_On) 00136 onpoints[j]++; 00137 00138 if(k < npoints[j] - 1 ) 00139 if( ftoutline.tags[l] == FT_Curve_Tag_Conic && 00140 ftoutline.tags[l+1] == FT_Curve_Tag_Conic) 00141 onpoints[j]++; 00142 } 00143 } 00144 00145 //contour loop, bezier & conic styles merged 00146 for(j = 0; j < ftoutline.n_contours; j++) { 00147 // add new curve 00148 nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); 00149 bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ; 00150 BLI_addtail(&che->nurbsbase, nu); 00151 00152 nu->type= CU_BEZIER; 00153 nu->pntsu = onpoints[j]; 00154 nu->resolu= 8; 00155 nu->flag= CU_2D; 00156 nu->flagu= CU_NURB_CYCLIC; 00157 nu->bezt = bezt; 00158 00159 //individual curve loop, start-end 00160 for(k = 0; k < npoints[j]; k++) { 00161 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; 00162 if(k == 0) m = l; 00163 00164 //virtual conic on-curve points 00165 if(k < npoints[j] - 1 ) 00166 { 00167 if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { 00168 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0f; 00169 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0f; 00170 00171 //left handle 00172 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0f; 00173 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0f; 00174 00175 //midpoint (virtual on-curve point) 00176 bezt->vec[1][0] = dx; 00177 bezt->vec[1][1] = dy; 00178 00179 //right handle 00180 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0f; 00181 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0f; 00182 00183 bezt->h1= bezt->h2= HD_ALIGN; 00184 bezt->radius= 1.0f; 00185 bezt++; 00186 } 00187 } 00188 00189 //on-curve points 00190 if(ftoutline.tags[l] == FT_Curve_Tag_On) { 00191 //left handle 00192 if(k > 0) { 00193 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { 00194 bezt->vec[0][0] = ftoutline.points[l-1].x* scale; 00195 bezt->vec[0][1] = ftoutline.points[l-1].y* scale; 00196 bezt->h1= HD_FREE; 00197 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { 00198 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0f; 00199 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0f; 00200 bezt->h1= HD_FREE; 00201 } else { 00202 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0f; 00203 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0f; 00204 bezt->h1= HD_VECT; 00205 } 00206 } else { //first point on curve 00207 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { 00208 bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; 00209 bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; 00210 bezt->h1= HD_FREE; 00211 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { 00212 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0f; 00213 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0f; 00214 bezt->h1= HD_FREE; 00215 } else { 00216 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0f; 00217 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0f; 00218 bezt->h1= HD_VECT; 00219 } 00220 } 00221 00222 //midpoint (on-curve point) 00223 bezt->vec[1][0] = ftoutline.points[l].x* scale; 00224 bezt->vec[1][1] = ftoutline.points[l].y* scale; 00225 00226 //right handle 00227 if(k < (npoints[j] - 1)) { 00228 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) { 00229 bezt->vec[2][0] = ftoutline.points[l+1].x* scale; 00230 bezt->vec[2][1] = ftoutline.points[l+1].y* scale; 00231 bezt->h2= HD_FREE; 00232 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { 00233 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0f; 00234 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0f; 00235 bezt->h2= HD_FREE; 00236 } else { 00237 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0f; 00238 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0f; 00239 bezt->h2= HD_VECT; 00240 } 00241 } else { //last point on curve 00242 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) { 00243 bezt->vec[2][0] = ftoutline.points[m].x* scale; 00244 bezt->vec[2][1] = ftoutline.points[m].y* scale; 00245 bezt->h2= HD_FREE; 00246 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) { 00247 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0f; 00248 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0f; 00249 bezt->h2= HD_FREE; 00250 } else { 00251 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0f; 00252 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0f; 00253 bezt->h2= HD_VECT; 00254 } 00255 } 00256 00257 // get the handles that are aligned, tricky... 00258 // dist_to_line_v2, check if the three beztriple points are on one line 00259 // len_squared_v2v2, see if there's a distance between the three points 00260 // len_squared_v2v2 again, to check the angle between the handles 00261 // finally, check if one of them is a vector handle 00262 if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001f) && 00263 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001f*0.0001f) && 00264 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001f*0.0001f) && 00265 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002f*0.0001f) && 00266 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > MAX2(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2]))) && 00267 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) 00268 { 00269 bezt->h1= bezt->h2= HD_ALIGN; 00270 } 00271 bezt->radius= 1.0f; 00272 bezt++; 00273 } 00274 } 00275 } 00276 if(npoints) MEM_freeN(npoints); 00277 if(onpoints) MEM_freeN(onpoints); 00278 } 00279 } 00280 00281 static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode) 00282 { 00283 // Freetype2 00284 FT_Face face; 00285 struct TmpFont *tf; 00286 00287 // Find the correct FreeType font 00288 tf= vfont_find_tmpfont(vfont); 00289 00290 // What, no font found. Something strange here 00291 if(!tf) return FALSE; 00292 00293 // Load the font to memory 00294 if(tf->pf) 00295 { 00296 err= FT_New_Memory_Face( library, 00297 tf->pf->data, 00298 tf->pf->size, 00299 0, 00300 &face); 00301 if (err) return FALSE; 00302 } 00303 else { 00304 err = TRUE; 00305 return FALSE; 00306 } 00307 00308 // Read the char 00309 freetypechar_to_vchar(face, charcode, vfont->data); 00310 00311 // And everything went ok 00312 return TRUE; 00313 } 00314 00315 00316 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) 00317 { 00318 // Variables 00319 FT_Face face; 00320 FT_ULong charcode = 0, lcode; 00321 FT_UInt glyph_index; 00322 const char *fontname; 00323 VFontData *vfd; 00324 00325 /* 00326 FT_CharMap found = 0; 00327 FT_CharMap charmap; 00328 FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT; 00329 FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; 00330 int n; 00331 */ 00332 00333 // load the freetype font 00334 err = FT_New_Memory_Face( library, 00335 pf->data, 00336 pf->size, 00337 0, 00338 &face ); 00339 00340 if(err) return NULL; 00341 /* 00342 for ( n = 0; n < face->num_charmaps; n++ ) 00343 { 00344 charmap = face->charmaps[n]; 00345 if ( charmap->platform_id == my_platform_id && 00346 charmap->encoding_id == my_encoding_id ) 00347 { 00348 found = charmap; 00349 break; 00350 } 00351 } 00352 00353 if ( !found ) { return NULL; } 00354 00355 // now, select the charmap for the face object 00356 err = FT_Set_Charmap( face, found ); 00357 if ( err ) { return NULL; } 00358 */ 00359 00360 // allocate blender font 00361 vfd= MEM_callocN(sizeof(*vfd), "FTVFontData"); 00362 00363 // get the name 00364 fontname = FT_Get_Postscript_Name(face); 00365 BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name)); 00366 00367 // Extract the first 256 character from TTF 00368 lcode= charcode= FT_Get_First_Char(face, &glyph_index); 00369 00370 // No charmap found from the ttf so we need to figure it out 00371 if(glyph_index == 0) 00372 { 00373 FT_CharMap found = NULL; 00374 FT_CharMap charmap; 00375 int n; 00376 00377 for ( n = 0; n < face->num_charmaps; n++ ) 00378 { 00379 charmap = face->charmaps[n]; 00380 if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) 00381 { 00382 found = charmap; 00383 break; 00384 } 00385 } 00386 00387 err = FT_Set_Charmap( face, found ); 00388 00389 if( err ) 00390 return NULL; 00391 00392 lcode= charcode= FT_Get_First_Char(face, &glyph_index); 00393 } 00394 00395 // Load characters 00396 while(charcode < 256) 00397 { 00398 // Generate the font data 00399 freetypechar_to_vchar(face, charcode, vfd); 00400 00401 // Next glyph 00402 charcode = FT_Get_Next_Char(face, charcode, &glyph_index); 00403 00404 // Check that we won't start infinite loop 00405 if(charcode <= lcode) 00406 break; 00407 lcode = charcode; 00408 } 00409 00410 return vfd; 00411 } 00412 00413 00414 static int check_freetypefont(PackedFile * pf) 00415 { 00416 FT_Face face; 00417 FT_GlyphSlot glyph; 00418 FT_UInt glyph_index; 00419 /* 00420 FT_CharMap charmap; 00421 FT_CharMap found; 00422 FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT; 00423 FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; 00424 int n; 00425 */ 00426 int success = 0; 00427 00428 err = FT_New_Memory_Face( library, 00429 pf->data, 00430 pf->size, 00431 0, 00432 &face ); 00433 if(err) { 00434 success = 0; 00435 //XXX error("This is not a valid font"); 00436 } 00437 else { 00438 /* 00439 for ( n = 0; n < face->num_charmaps; n++ ) 00440 { 00441 charmap = face->charmaps[n]; 00442 if ( charmap->platform_id == my_platform_id && 00443 charmap->encoding_id == my_encoding_id ) 00444 { 00445 found = charmap; 00446 break; 00447 } 00448 } 00449 00450 if ( !found ) { return 0; } 00451 00452 // now, select the charmap for the face object 00453 err = FT_Set_Charmap( face, found ); 00454 if ( err ) { return 0; } 00455 */ 00456 glyph_index = FT_Get_Char_Index( face, 'A' ); 00457 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); 00458 if(err) success = 0; 00459 else { 00460 glyph = face->glyph; 00461 if (glyph->format == ft_glyph_format_outline ) { 00462 success = 1; 00463 } else { 00464 //XXX error("Selected Font has no outline data"); 00465 success = 0; 00466 } 00467 } 00468 } 00469 00470 return success; 00471 } 00472 00473 00474 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf) 00475 { 00476 VFontData *vfd= NULL; 00477 int success = 0; 00478 00479 //init Freetype 00480 err = FT_Init_FreeType( &library); 00481 if(err) { 00482 //XXX error("Failed to load the Freetype font library"); 00483 return NULL; 00484 } 00485 00486 success = check_freetypefont(pf); 00487 00488 if (success) { 00489 vfd= objfnt_to_ftvfontdata(pf); 00490 } 00491 00492 //free Freetype 00493 FT_Done_FreeType( library); 00494 00495 return vfd; 00496 } 00497 00498 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) 00499 { 00500 int success = FALSE; 00501 00502 if(!vfont) return FALSE; 00503 00504 // Init Freetype 00505 err = FT_Init_FreeType(&library); 00506 if(err) { 00507 //XXX error("Failed to load the Freetype font library"); 00508 return 0; 00509 } 00510 00511 // Load the character 00512 success = objchr_to_ftvfontdata(vfont, character); 00513 if(success == FALSE) return FALSE; 00514 00515 // Free Freetype 00516 FT_Done_FreeType(library); 00517 00518 // Ahh everything ok 00519 return TRUE; 00520 } 00521 00522 #if 0 00523 00524 // Freetype2 Outline struct 00525 00526 typedef struct FT_Outline_ 00527 { 00528 short n_contours; /* number of contours in glyph */ 00529 short n_points; /* number of points in the glyph */ 00530 00531 FT_Vector* points; /* the outline's points */ 00532 char* tags; /* the points flags */ 00533 short* contours; /* the contour end points */ 00534 00535 int flags; /* outline masks */ 00536 00537 } FT_Outline; 00538 00539 #endif 00540 00541 /***//* 00542 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1 00543 00544 Vectorial representation of Freetype glyphs 00545 00546 The source format of outlines is a collection of closed paths called "contours". Each contour is 00547 made of a series of line segments and bezier arcs. Depending on the file format, these can be 00548 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and 00549 they come from the TrueType format. The latter are called cubic arcs and mostly come from the 00550 Type1 format. 00551 00552 Each arc is described through a series of start, end and control points. Each point of the outline 00553 has a specific tag which indicates wether it is used to describe a line segment or an arc. 00554 00555 00556 The following rules are applied to decompose the contour's points into segments and arcs : 00557 00558 # two successive "on" points indicate a line segment joining them. 00559 00560 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being 00561 the control point, and the "on" ones the start and end points. 00562 00563 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must 00564 be exactly two cubic control points and two on points for each cubic arc (using a single cubic 00565 "off" point between two "on" points is forbidden, for example). 00566 00567 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line 00568 conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This 00569 greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way 00570 outlines are described in the TrueType specification. 00571 00572 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current 00573 font driver produces such outlines. 00574 00575 * # on 00576 * off 00577 __---__ 00578 #-__ _-- -_ 00579 --__ _- - 00580 --__ # \ 00581 --__ # 00582 -# 00583 Two "on" points 00584 Two "on" points and one "conic" point 00585 between them 00586 00587 00588 00589 * 00590 # __ Two "on" points with two "conic" 00591 \ - - points between them. The point 00592 \ / \ marked '0' is the middle of the 00593 - 0 \ "off" points, and is a 'virtual' 00594 -_ _- # "on" point where the curve passes. 00595 -- It does not appear in the point 00596 list. 00597 * 00598 00599 00600 00601 00602 * # on 00603 * * off 00604 __---__ 00605 _-- -_ 00606 _- - 00607 # \ 00608 # 00609 00610 Two "on" points 00611 and two "cubic" point 00612 between them 00613 00614 00615 Each glyph's original outline points are located on a grid of indivisible units. The points are stored 00616 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus 00617 range from -16384 to 16383. 00618 00619 Convert conic to bezier arcs: 00620 Conic P0 P1 P2 00621 Bezier B0 B1 B2 B3 00622 B0=P0 00623 B1=(P0+2*P1)/3 00624 B2=(P2+2*P1)/3 00625 B3=P2 00626 00627 *//****/