Added a 3D font loader that uses the Freetype2 library to
authorRob Haarsma <phaseIV@zonnet.nl>
Mon, 28 Apr 2003 21:16:27 +0000 (21:16 +0000)
committerRob Haarsma <phaseIV@zonnet.nl>
Mon, 28 Apr 2003 21:16:27 +0000 (21:16 +0000)
parse the vector data. Freetype2 supports many font formats
including Type1, TrueType and OpenType fonts.

Enable with the WITH_FREETYPE2 compile flag, in the
source/blender/blenkernel and source/blender/blenlib dirs.

source/blender/blenkernel/intern/font.c
source/blender/blenlib/BLI_vfontdata.h
source/blender/blenlib/intern/freetypefont.c [new file with mode: 0644]

index 5ea20224fb75052aa9f408dd5bb878dfc1ac600b..62463ef1307721575b93fd28d91c873ab5ee406a 100644 (file)
@@ -145,8 +145,11 @@ static VFontData *vfont_get_data(VFont *vfont)
                }
                
                if (pf) {
+#ifdef WITH_FREETYPE2
+                       vfont->data= BLI_vfontdata_from_freetypefont(pf);
+#else
                        vfont->data= BLI_vfontdata_from_psfont(pf);
-               
+#endif                 
                        if (pf != vfont->packedfile) {
                                freePackedFile(pf);
                        }
@@ -183,7 +186,11 @@ VFont *load_vfont(char *name)
                
                waitcursor(1);
 
+#ifdef WITH_FREETYPE2
+               vfd= BLI_vfontdata_from_freetypefont(pf);
+#else
                vfd= BLI_vfontdata_from_psfont(pf);
+#endif                 
                
                if (vfd) {
                        vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
index 86aab13e3bc969365b41ebf3fb3f71a3d635652b..b6ec749b50a43fc0795f2ddd15dd6ed4d79cea59 100644 (file)
@@ -63,5 +63,19 @@ typedef struct VFontData {
 BLI_vfontdata_from_psfont(
        struct PackedFile *pf);
 
+#ifdef WITH_FREETYPE2
+/**
+ * Construct a new VFontData structure from 
+ * Freetype font data in a PackedFile.
+ * 
+ * @param pf The font data.
+ * @retval A new VFontData structure, or NULL
+ * if unable to load.
+ */
+       VFontData*
+BLI_vfontdata_from_freetypefont(
+       struct PackedFile *pf);
+#endif
+
 #endif
 
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
new file mode 100644 (file)
index 0000000..fefcd80
--- /dev/null
@@ -0,0 +1,445 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is written by Rob Haarsma (phase)
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_FREETYPE2
+
+#ifdef WIN32
+#pragma warning (disable:4244)
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_vfontdata.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"  
+
+#include "BIF_toolbox.h"
+
+#include "DNA_packedFile_types.h"
+#include "DNA_curve_types.h"
+
+#define myMIN_ASCII    32
+#define myMAX_ASCII    126
+
+// should come from arithb.c
+#define MIN2(x,y)               ( (x)<(y) ? (x) : (y) )
+#define MAX2(x,y)               ( (x)>(y) ? (x) : (y) )
+
+/* local variables */
+static FT_Library      library;
+static FT_Error                err;
+
+#if 0
+// Freetype2 Outline struct
+
+typedef struct  FT_Outline_
+  {
+    short       n_contours;      /* number of contours in glyph        */
+    short       n_points;        /* number of points in the glyph      */
+
+    FT_Vector*  points;          /* the outline's points               */
+    char*       tags;            /* the points flags                   */
+    short*      contours;        /* the contour end points             */
+
+    int         flags;           /* outline masks                      */
+
+  } FT_Outline;
+#endif
+
+/***//*
+from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
+
+Vectorial representation of Freetype glyphs
+
+The source format of outlines is a collection of closed paths called "contours". Each contour is
+made of a series of line segments and bezier arcs. Depending on the file format, these can be
+second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
+they come from the TrueType format. The latter are called cubic arcs and mostly come from the
+Type1 format.
+
+Each arc is described through a series of start, end and control points. Each point of the outline
+has a specific tag which indicates wether it is used to describe a line segment or an arc.
+
+
+The following rules are applied to decompose the contour's points into segments and arcs :
+
+# two successive "on" points indicate a line segment joining them.
+
+# one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
+  the control point, and the "on" ones the start and end points.
+
+# Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
+  be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
+  "off" point between two "on" points is forbidden, for example).
+
+# finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
+  conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
+  greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
+  outlines are described in the TrueType specification.
+
+Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
+font driver produces such outlines.
+
+                                  *            # on      
+                                               * off
+                               __---__
+  #-__                      _--       -_
+      --__                _-            -
+          --__           #               \
+              --__                        #
+                  -#
+                           Two "on" points
+   Two "on" points       and one "conic" point
+                            between them
+
+
+
+                *
+  #            __      Two "on" points with two "conic"
+   \          -  -     points between them. The point
+    \        /    \    marked '0' is the middle of the
+     -      0      \   "off" points, and is a 'virtual'
+      -_  _-       #   "on" point where the curve passes.
+        --             It does not appear in the point
+                       list.
+        *
+
+
+
+
+        *                # on
+                   *     * off
+         __---__
+      _--       -_
+    _-            -
+   #               \
+                    #
+
+     Two "on" points
+   and two "cubic" point
+      between them
+
+
+Each glyph's original outline points are located on a grid of indivisible units. The points are stored
+in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
+range from -16384 to 16383.
+
+
+Convert conic to bezier arcs:
+Conic P0 P1 P2
+Bezier B0 B1 B2 B3
+B0=P0
+B1=(P0+2*P1)/3
+B2=(P2+2*P1)/3
+B3=P2
+
+*//****/
+
+static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
+{
+       // Blender
+       VFontData *vfd;
+       struct Nurb *nu;
+       struct BezTriple *bezt;
+
+       // Freetype2
+       FT_Face         face;
+       FT_GlyphSlot  glyph;
+       FT_UInt         glyph_index;
+       FT_Outline      ftoutline;
+
+       float scale= 1. / 1024.; //needs text_height from metrics to make a standard linedist
+       float dx, dy;
+       int i, j, k, l, m; /* uhoh, kiddie C loops */
+       /* i = characters, j = curves/contours, k = points, l = curvepoint, m = first point on curve */
+
+       // test is used for BIF_printf
+       char test[2];
+
+       
+       // load the freetype font
+       err = FT_New_Memory_Face( library,
+                                               pf->data,
+                                               pf->size,
+                                               0,
+                                               &face );
+
+       if(err) return NULL;
+
+       // allocate blender font
+       vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
+
+//FT_Set_Charmap(face, ft_encoding_symbol);
+
+       // extract generic ascii character range (needs international support, dynamic loading of chars, etcetc)
+       for(i = myMIN_ASCII; i <= myMAX_ASCII; i++) {
+               int  *npoints;  //total points of each contour
+               int  *onpoints; //num points on curve
+
+               test[0] = i;
+               test[1] = '\0'; //to print character
+
+               glyph_index = FT_Get_Char_Index( face, i );
+               err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE);
+               glyph = face->glyph;
+               ftoutline = glyph->outline;
+
+               vfd->width[i] = glyph->advance.x* scale;
+//             BIF_printf("sx %d sy %d", glyph->advance.x, face->glyph->metrics->text_height);
+
+               npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
+               onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
+
+               // calculate total points of each contour
+               for(j = 0; j < ftoutline.n_contours; j++) {
+                       if(j == 0)
+                               npoints[j] = ftoutline.contours[j] + 1;
+                       else
+                               npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
+               }
+
+               // get number of on-curve points for beziertriples (including conic virtual on-points) 
+               for(j = 0; j < ftoutline.n_contours; j++) {
+                       l = 0;
+                       for(k = 0; k < npoints[j]; k++) {
+                               if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
+
+//                             if(i == 67) BIF_printf("%d->%s : |k %2d|l %2d|t %2d|", i, test, k, l, ftoutline.n_points);
+
+                               if(ftoutline.tags[l] == FT_Curve_Tag_On)
+                                       onpoints[j]++;
+
+                               if(k < npoints[j] - 1 )
+                                       if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
+                                               ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
+                                               onpoints[j]++;
+                       }
+               }
+
+               //final contour loop, bezier & conic styles merged
+               for(j = 0; j < ftoutline.n_contours; j++) {
+                       // add new curve
+                       nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
+                       bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
+                       BLI_addtail(&vfd->nurbsbase[i], nu);
+                       nu->type= CU_BEZIER+CU_2D;
+                       nu->pntsu = onpoints[j];
+                       nu->resolu= 8;
+                       nu->flagu= 1;
+                       nu->bezt = bezt;
+
+                       //individual curve loop, start-end
+                       for(k = 0; k < npoints[j]; k++) {
+                               if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
+                               if(k == 0) m = l;
+                               
+                               //virtual conic on-curve points
+                               if(k < npoints[j] - 1 )
+                                       if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
+                                               dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
+                                               dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
+
+                                               //left handle
+                                               bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
+                                               bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
+
+                                               //midpoint (virtual on-curve point)
+                                               bezt->vec[1][0] = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
+                                               bezt->vec[1][1] = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
+
+                                               //right handle
+                                               bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
+                                               bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
+
+                                               bezt->h1= bezt->h2= HD_ALIGN;
+                                               bezt++;
+                                       }
+
+                               //on-curve points
+                               if(ftoutline.tags[l] == FT_Curve_Tag_On) {
+                                       //left handle
+                                       if(k > 0) {
+                                               if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
+                                                       bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
+                                                       bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
+                                                       bezt->h1= HD_FREE;
+                                               } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
+                                                       bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
+                                                       bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
+                                                       bezt->h1= HD_FREE;
+                                               } else {
+                                                       bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
+                                                       bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
+                                                       bezt->h1= HD_VECT;
+                                               }
+                                       } else { //first point on curve
+                                               if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
+                                                       bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
+                                                       bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
+                                                       bezt->h1= HD_FREE;
+                                               } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
+                                                       bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
+                                                       bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
+                                                       bezt->h1= HD_FREE;
+                                               } else {
+                                                       bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
+                                                       bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
+                                                       bezt->h1= HD_VECT;
+                                               }
+                                       }
+
+                                       //midpoint (on-curve point)
+                                       bezt->vec[1][0] = ftoutline.points[l].x* scale;
+                                       bezt->vec[1][1] = ftoutline.points[l].y* scale;
+
+                                       //right handle
+                                       if(k < (npoints[j] - 1)) {
+                                               if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
+                                                       bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
+                                                       bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
+                                                       bezt->h2= HD_FREE;
+                                               } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
+                                                       bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
+                                                       bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
+                                                       bezt->h2= HD_FREE;
+                                               } else {
+                                                       bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
+                                                       bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
+                                                       bezt->h2= HD_VECT;
+                                               }
+                                       } else { //last point on curve
+                                               if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
+//                                                     okee("hhuh");
+                                                       bezt->vec[2][0] = ftoutline.points[m].x* scale;
+                                                       bezt->vec[2][1] = ftoutline.points[m].y* scale;
+                                                       bezt->h2= HD_FREE;
+                                               } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
+                                                       bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
+                                                       bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
+                                                       bezt->h2= HD_FREE;
+                                               } else {
+                                                       bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
+                                                       bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
+                                                       bezt->h2= HD_VECT;
+                                               }
+                                       }
+
+                                       // get the handles that are aligned, tricky...
+                                       // DistVL2Dfl, check if the three beztriple points are on one line
+                                       // VecLenf, see if there's a distance between the three points
+                                       // VecLenf again, to check the angle between the handles 
+                                       // finally, check if one of them is a vector handle 
+                                       if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
+                                               (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
+                                               (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
+                                               (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
+                                               (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
+                                               bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
+                                       {
+                                               bezt->h1= bezt->h2= HD_ALIGN;
+                                       }
+                                       bezt++;
+                               }
+                       }
+               }
+
+               if(npoints) MEM_freeN(npoints);
+               if(onpoints) MEM_freeN(onpoints);
+       }
+       return vfd;
+}
+
+
+static int check_freetypefont(PackedFile * pf)
+{
+       FT_Face                 face;
+       FT_GlyphSlot    glyph;
+       FT_UInt                 glyph_index;
+
+       int success = 0;
+
+       err = FT_New_Memory_Face( library,
+                                                       pf->data,
+                                                       pf->size,
+                                                       0,
+                                                       &face );
+       if(err) {
+               success = 0;
+           error("This is not a valid font");
+       }
+       else {
+               glyph_index = FT_Get_Char_Index( face, 'A' );
+               err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP );
+               if(err) success = 0;
+               else {
+                       glyph = face->glyph;
+                       if (glyph->format == ft_glyph_format_outline ) {
+                               success = 1;
+                       } else {
+                               error("Selected Font has no outline data");
+                               success = 0;
+                       }
+               }
+       }
+       
+       return success;
+}
+
+
+VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
+{
+       VFontData *vfd= NULL;
+       int success = 0;
+
+       //init Freetype 
+       err = FT_Init_FreeType( &library);
+       if(err) {
+           error("Failed loading Freetype font library");
+               return 0;
+       }
+
+       success = check_freetypefont(pf);
+       
+       if (success) {
+               vfd= objfnt_to_ftvfontdata(pf);
+       }
+
+       //free Freetype
+       FT_Done_FreeType( library);
+       
+       return vfd;
+}
+
+#endif // WITH_FREETYPE2
\ No newline at end of file