ecere/gfx/newFonts: Tweaks to build on OS X
[sdk] / ecere / src / gfx / newFonts / fmFontManager.ec
1 /* *****************************************************************************
2  * Original Version Copyright (c) 2007-2014 Alexis Naveros.
3  *
4  * Ecere Corporation has unlimited/unrestricted rights.
5  * *****************************************************************************/
6 #undef __BLOCKS__
7
8 import "LinkList"
9 import "File"
10 import "FontResource"
11 import "fontRenderer"
12
13 import "atlasBuilder"
14 import "imgDistMap"
15
16 #include "gl123es.h"
17
18 namespace gfx;
19
20 #include <math.h>
21
22 #define _Noreturn
23
24 #include "cc.h"
25
26 static inline uint32 decodeUTF8( uint32 b, uint32 *state, unichar *retCodePoint ) { return ccUtf8ToUnicode(b, state, (uint *)retCodePoint); }
27
28 ////
29
30 static void buildCursorGlyph( byte *dst, int glyphwidth, int glyphheight, int dststride )
31 {
32   int x, y, hbarheight, hgap, hline, vline;
33   byte *dstrow;
34
35   if( glyphwidth >= 3 )
36   {
37     hbarheight = 1 + ( glyphheight >> 6 );
38     hgap = ( glyphwidth - ( 1 + ( glyphheight >> 6 ) ) ) >> 1;
39     hline = hgap + glyphwidth - ( hgap << 1 );
40     vline = glyphheight - ( hbarheight << 1 );
41     for( y = 0 ; y < hbarheight ; y++ )
42     {
43       dstrow = dst;
44       for( x = 0 ; x < glyphwidth ; x++ )
45         dstrow[x] = 255;
46       dst += dststride;
47     }
48     for( y = 0 ; y < vline ; y++ )
49     {
50       dstrow = dst;
51       for( x = 0 ; x < hgap ; x++ )
52         dstrow[x] = 0;
53       for( ; x < hline ; x++ )
54         dstrow[x] = 255;
55       for( ; x < glyphwidth ; x++ )
56         dstrow[x] = 0;
57       dst += dststride;
58     }
59     for( y = 0 ; y < hbarheight ; y++ )
60     {
61       dstrow = dst;
62       for( x = 0 ; x < glyphwidth ; x++ )
63         dstrow[x] = 255;
64       dst += dststride;
65     }
66   }
67   else
68   {
69     for( y = 0 ; y < glyphheight ; y++ )
70     {
71       dstrow = dst;
72       for( x = 0 ; x < glyphwidth ; x++ )
73         dstrow[x] = 255;
74       dst += dststride;
75     }
76   }
77
78   return;
79 }
80
81 static inline void addGlyphAdvance( int *x, int *subpixel, FMGlyph *glyph )
82 {
83    *subpixel += glyph->advance;
84 #if FM_SUBPIXEL_ROUNDING_RANGE
85    *subpixel = ( *subpixel + (FM_SUBPIXEL_ROUNDING_RANGE>>1) ) & ~(FM_SUBPIXEL_ROUNDING_RANGE-1);
86 #endif
87    *x += *subpixel >> 6;
88    *subpixel &= 0x3f;
89 }
90
91 public class FontManagerRenderer
92 {
93 public:
94    FontManager fm;
95
96    virtual bool init(int channelCount);
97
98    // Create, resize or update texture data ; rect is [minx,maxx,miny,maxy]
99    virtual int createTexture( int width, int height );
100    virtual int resizeTexture( int width, int height );
101    virtual void updateTexture( int *rect, const byte *data );
102
103    // If the renderer does any buffering of drawImage(), flush it all right now (texture may change immediately after)
104    virtual void flush( );
105
106    // If the renderer records per-image data, return an imageIndex passed to drawImage()
107    virtual int registerImage( int offsetx, int offsety, int width, int height );
108    // Draw an image, imageIndex passed as the value previously returned by registerImage()
109    virtual void drawImage( int targetx, int targety, int imageIndex, bool useExtColor );
110    // Draw an image, called instead of drawImage() for text cursors, can point to exactly the same function
111    virtual void drawImageCursor( int targetx, int targety, int imageIndex );
112    // If drawImage is zero, then this alternate function is called, passing everything required to render the glyph
113    virtual void drawImageAlt( byte *texdata, int targetx, int targety, int offsetx, int offsety, int width, int height );
114    // Draw a non-aligned image, imageIndex passed as the value previously returned by registerImage()
115    virtual void drawImageFloat( float targetx, float targety, float angsin, float angcos, int imageIndex, bool useExtColor );
116
117    // The renderer must flush all recorded images, registerImage() will be called for new images
118    virtual void resetImages( );
119
120    virtual void setLayer( uint32 layerIndex );
121 };
122
123
124 ////
125
126
127 #include <ft2build.h>
128
129 #include FT_FREETYPE_H
130 #include FT_ADVANCES_H
131
132
133 ////
134
135
136 #define FM_SUPPORT_GLYPH_ROTATION (1)
137
138
139 ////
140
141
142 #define FM_ENABLE_HINTING (1)
143 #define FM_SUBPIXEL_ROUNDING_RANGE (16)
144
145
146 #define FM_HASH_TABLE_SIZE (4096)
147 #define FM_INIT_GLYPHS (1024)
148 #define FM_INIT_ATLAS_NODES (512)
149
150 #define FM_MAX_STATES (16)
151
152
153 ////
154
155 struct FMFreeTypeFont
156 {
157    FT_Face face;
158
159    static inline int ::init()
160    {
161      FT_Error ftError;
162      ftError = FT_Init_FreeType( &ftLibrary2 );
163      return ftError == 0;
164    }
165
166    static inline int loadFont( byte *data, int dataSize )
167    {
168      FT_Error ftError = FT_New_Memory_Face( ftLibrary2, (const FT_Byte*)data, dataSize, 0, &face );
169      return ftError == 0;
170    }
171
172    void free()
173    {
174       FT_Done_Face( face );
175    }
176
177    static inline void getFontVMetrics( float *ascent, float *descent, float *lineHeight, float *limitminy, float *limitmaxy )
178    {
179      *ascent = (float)face->ascender;
180      *descent = (float)face->descender;
181      *lineHeight = (float)face->height / (float)face->units_per_EM;
182      *limitminy = (float)face->bbox.yMin / (float)face->units_per_EM;
183      *limitmaxy = (float)face->bbox.yMax / (float)face->units_per_EM;
184    }
185
186    static inline int getGlyphIndex( unichar codepoint )
187    {
188      return FT_Get_Char_Index( this.face, codepoint );
189    }
190
191    static int buildGlyphBitmap( int glyph, int size, int subpixel, int *advance, int *x0, int *y0, int *x1, int *y1 )
192    {
193      FT_Error ftError;
194      FT_GlyphSlot glyphslot;
195      FT_Vector subvector;
196
197      ftError = FT_Set_Pixel_Sizes( this.face, 0, (FT_UInt)size );
198      if( ftError )
199        return 0;
200
201      subvector.x = subpixel;
202      subvector.y = 0;
203      FT_Set_Transform( face, 0, &subvector );
204
205    #if FM_ENABLE_HINTING
206      ftError = FT_Load_Glyph( face, glyph, FT_LOAD_RENDER );
207    #else
208      ftError = FT_Load_Glyph( face, glyph, FT_LOAD_RENDER | FT_LOAD_NO_HINTING );
209    #endif
210      if( ftError )
211        return 0;
212
213      glyphslot = face->glyph;
214      *advance = (int)glyphslot->metrics.horiAdvance;
215      *x0 = glyphslot->bitmap_left;
216      *x1 = glyphslot->bitmap_left + glyphslot->bitmap.width;
217      *y0 = -glyphslot->bitmap_top;
218      *y1 = -glyphslot->bitmap_top + glyphslot->bitmap.rows;
219
220      return 1;
221    }
222
223    static inline int getGlyphKernAdvance( int glyph1, int glyph2 )
224    {
225      FT_Vector ftKerning;
226      FT_Get_Kerning( face, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning );
227      return (int)ftKerning.x;
228    }
229
230    static inline byte *getGlyphBitmap( int glyphindex )
231    {
232      FT_GlyphSlot glyphslot;
233      glyphslot = face->glyph;
234      return glyphslot->bitmap.buffer;
235    }
236 };
237
238 class FMDefBits : uint64
239 {
240 public:
241    uint32 codePoint:32;
242    int size:11, subPixel:6;
243    bool outline:1;
244 }
245
246 static define FM_SIZE_MAX = (1<<11)-1;
247 static define FM_BLUR_RADIUS_MAX = (1<<6)-1;
248 static define FM_BLUR_SCALE_MAX = (1<<6)-1;
249
250 static define FM_GLYPH_CODEPOINT_CURSOR = 0x1;
251 static define FM_GLYPH_CODEPOINT_REPLACEMENT = 0xfffd;
252
253 public enum FMVerticalAlignment { baseline, top, middle, bottom };
254
255 public class FMTextAlignment : uint16
256 {
257 public:
258    Alignment horzAlignment:2;
259    FMVerticalAlignment vertAlignment:2;
260 };
261
262 public struct FMPathDraw
263 {
264   int prevGlyphIndex;
265   float middleAlign;
266 };
267
268 struct FMQuad { int x0, y0, x1, y1; };
269
270 struct FMGlyph
271 {
272    int glyphindex;
273    uint64 glyphdef;
274    short x0, y0, x1, y1;
275    short advance, offsetx, offsety;
276    int imageIndex;
277    int listnext;
278
279    static void getQuad( float x, float y, FMQuad q )
280    {
281       int rx = (int)(x + offsetx);
282       int ry = (int)(y + offsety);
283       q = { rx, ry, rx + x1 - x0, ry + y1 - y0 };
284    }
285 };
286
287 public class FMFont : struct
288 {
289    public LinkElement link;
290    FMFreeTypeFont ftFont;
291    void *fontdata;
292    float ascender;
293    float descender;
294    float middleAlign;
295    float lineHeight;
296    float limitminy, limitmaxy;
297    FMGlyph *glyphs;
298    int glyphalloc;
299    int glyphcount;
300    int hashtable[FM_HASH_TABLE_SIZE];
301    int glyphPaddingWidth;
302
303    void (*processImage)( void *opaquecontext, byte *image, int width, int height, int bytesperpixel, int bytesperline, int paddingwidth, int pass);
304    void *processImageContext;
305
306    /*
307    public void setFontImageProcessing(
308       void (*processImage)( byte *image, int width, int height, int bytesperpixel, int bytesperline, int paddingsize, void *opaquecontext ),
309       void *opaquecontext )
310    {
311      this.processImage = processImage;
312      this.processImageContext = opaquecontext;
313    }
314    */
315
316    float outlineRadius;
317    float outlineAlphaFactor;
318    float outlineIntensityFactor;
319
320    static void ::outlineProcessGlyphImage( FMFont font, byte *image, int width, int height, int bytesperpixel, int bytesperline, int paddingwidth, int isOutline )
321    {
322      int x, y;
323      byte *src, *dst, *dstrow;
324      float intensityfactor, alphafactor, range, alpha, intensity, rangeinv, rangebase;
325      float *distancemap, *dmap;
326
327      distancemap = new float[width * height];
328
329      src = &image[0];
330      imgDistMapBuild( distancemap, src, width, height, bytesperpixel, bytesperline );
331
332      alphafactor = font.outlineAlphaFactor; //2.0f;
333      intensityfactor = font.outlineIntensityFactor; // 0.2f;
334      range = (float)font.outlineRadius;
335      rangeinv = 1.0f / range;
336
337      dmap = distancemap;
338      dst = &image[0];
339      for( y = 0 ; y < height ; y++ )
340      {
341        dstrow = dst;
342        for( x = 0 ; x < width ; x++ )
343        {
344          rangebase = ( range - dmap[ x ] ) * rangeinv;
345          alpha = alphafactor * rangebase;
346          intensity = fmaxf( (float)dstrow[0] * (1.0f/255.0f), intensityfactor * rangebase );
347          if(bytesperpixel == 2)
348          {
349             /* Alpha channel */
350             dstrow[0] = (byte)roundf( fmaxf( 0.0f, fminf( 255.0f, alpha * 255.0f ) ) );
351             /* Intensity channel */
352             dstrow[1] = (byte)roundf( fmaxf( 0.0f, fminf( 255.0f, intensity * 255.0f ) ) );
353          }
354          else
355          {
356             if(isOutline)
357                dstrow[0] = (byte)roundf( fmaxf( 0.0f, fminf( 255.0f, alpha * 255.0f ) ) );
358             else
359                dstrow[0] = (byte)roundf( fmaxf( 0.0f, fminf( 255.0f, intensity * 255.0f ) ) );
360          }
361          dstrow += bytesperpixel;
362        }
363        dst += bytesperline;
364        dmap += width;
365      }
366      delete distancemap;
367    }
368
369    public void setOutline(float size, float fade)
370    {
371       outlineIntensityFactor = 1.0f / (0.2f + size);
372       outlineAlphaFactor = 1.0f / (0.2f + fade);
373       outlineRadius = size;
374       processImage = outlineProcessGlyphImage;
375       processImageContext = this;
376    }
377
378    ~FMFont()
379    {
380       ftFont.free();
381       delete fontdata;
382       delete glyphs;
383    }
384
385    static FMGlyph *allocGlyph( )
386    {
387       if( glyphcount >= glyphalloc )
388       {
389          glyphalloc <<= 1;
390          if( !(glyphs = renew glyphs FMGlyph[glyphalloc]) )
391             return null;
392       }
393       return &glyphs[ glyphcount++ ];
394    }
395
396    ////
397
398    static float getVertAlign( FMTextAlignment align, int size )
399    {
400       float sizef = size;
401      if( align.vertAlignment == top )
402        return ascender * sizef;
403      else if( align.vertAlignment == middle )
404        return middleAlign * sizef;
405      else if( align.vertAlignment == bottom )
406        return descender * sizef;
407      return 0.0f;
408    }
409
410    static inline void addKerning( int prevGlyphIndex, FMGlyph *glyph, int *x, int *subpixel )
411    {
412      if( prevGlyphIndex != -1 )
413      {
414        *subpixel += ftFont.getGlyphKernAdvance( prevGlyphIndex, glyph->glyphindex );
415    #if FM_SUBPIXEL_ROUNDING_RANGE
416        *subpixel = ( *subpixel + (FM_SUBPIXEL_ROUNDING_RANGE>>1) ) & ~(FM_SUBPIXEL_ROUNDING_RANGE-1);
417    #endif
418        *x += *subpixel >> 6;
419        *subpixel &= 0x3f;
420      }
421    }
422
423 };
424
425 struct FMState
426 {
427    FMFont font;
428    uint16 size;
429    FMTextAlignment align;
430 };
431
432 ////
433
434
435 static FT_Library ftLibrary2;
436
437 static void copyGlyphBitmap1( byte *dst, byte *src, int glyphwidth, int glyphheight, int dststride )
438 {
439   int x, y;
440   for( y = 0 ; y < glyphheight ; y++ )
441   {
442     byte *dstrow = &dst[ y * dststride ];
443     for( x = 0 ; x < glyphwidth ; x++ )
444       dstrow[ x ] = src[ x ];
445     src += glyphwidth;
446   }
447 }
448
449 static void copyGlyphBitmap2( byte *dst, byte *src, int glyphwidth, int glyphheight, int dststride )
450 {
451   int x, y;
452   for( y = 0 ; y < glyphheight ; y++ )
453   {
454     byte *dstrow = &dst[ y * dststride ];
455     for( x = 0 ; x < glyphwidth ; x++ )
456       dstrow[ x << 1 ] = src[ x ];
457     src += glyphwidth;
458   }
459 }
460
461 static void copyGlyphBitmap4( byte *dst, byte *src, int glyphwidth, int glyphheight, int dststride )
462 {
463   int x, y;
464   for( y = 0 ; y < glyphheight ; y++ )
465   {
466     byte *dstrow = &dst[ y * dststride ];
467     for( x = 0 ; x < glyphwidth ; x++ )
468       dstrow[ x << 2 ] = src[ x ];
469     src += glyphwidth;
470   }
471 }
472
473 public class FontManager
474 {
475    FontManagerRenderer renderer;
476    int width, height;
477    float widthinv, heightinv;
478    int bytesperpixel;
479    int bytesperline;
480    int channelindex;
481
482    AtlasBuilder atlas { };
483    byte *texdata;
484    int dirtyrect[4];
485
486    LinkList<FMFont, link = link> fontList { };
487
488    FMState states[FM_MAX_STATES];
489    int nstates;
490
491    void (*copyGlyphBitmap)( byte *dst, byte *src, int glyphwidth, int glyphheight, int dststride );
492
493
494    static FMGlyph *getGlyph( FMFont font, unichar codepoint, int size, int subpixel, bool outlinePass )
495    {
496      int i, glyphindex, advance, x0, y0, x1, y1, gx, gy;
497      int glyphwidth, glyphheight, glyphareawidth, glyphareaheight;
498      uint64 glyphdef;
499      FMGlyph *glyph;
500      uint32 hashindex;
501      int padding, added;
502      // byte *bdst;
503      byte *dst, *src;
504
505      glyph = 0;
506      if( size < 0.2 )
507        return 0;
508      padding = font.glyphPaddingWidth;
509
510      // Find code point and size.
511      glyphdef = FMDefBits { codepoint, size, subpixel, outlinePass };
512      hashindex = ccHash32Int64Inline( glyphdef ) & ( FM_HASH_TABLE_SIZE - 1 );
513      i = font.hashtable[hashindex];
514      while( i != -1 )
515      {
516        if( glyphdef == font.glyphs[i].glyphdef )
517          return &font.glyphs[i];
518        i = font.glyphs[i].listnext;
519      }
520
521      /* Could not find glyph, create it */
522      if( codepoint == FM_GLYPH_CODEPOINT_CURSOR )
523      {
524        glyphindex = -1;
525        advance = 0;
526    #if 0
527        x0 = 0;
528        x1 = 1;
529    #else
530        x0 = -2;
531        x1 = 3;
532    #endif
533        y0 = -(int)ceilf( font.limitmaxy * (float)size );
534        y1 = -(int)floorf( font.limitminy * (float)size );
535        i = ( (y1 - y0) - size ) / 3;
536        y0 += i;
537        y1 -= i;
538      }
539      else
540      {
541        glyphindex = font.ftFont.getGlyphIndex( codepoint );
542        if( !( font.ftFont.buildGlyphBitmap( glyphindex, size, subpixel, &advance, &x0, &y0, &x1, &y1 ) ) )
543        {
544          if( codepoint != FM_GLYPH_CODEPOINT_REPLACEMENT )
545            return getGlyph(font, FM_GLYPH_CODEPOINT_REPLACEMENT, size, subpixel, outlinePass );
546          return 0;
547        }
548      }
549      glyphwidth = ( x1 - x0 );
550      glyphheight = ( y1 - y0 );
551      glyphareawidth = glyphwidth + (padding << 1);
552      glyphareaheight = glyphheight + (padding << 1);
553
554      // Find free spot for the rect in the atlas
555      added = atlas.addRect( glyphareawidth, glyphareaheight, &gx, &gy );
556      if( !( added ) && ( onAtlasFull ) )
557      {
558        /* Atlas is full, let the user to resize the atlas (or not), and try again. */
559        onAtlasFull();
560        added = atlas.addRect( glyphareawidth, glyphareaheight, &gx, &gy );
561      }
562      if( !( added ) )
563        return 0;
564
565      /* Build the glyph */
566      glyph = font.allocGlyph();
567      glyph->glyphdef = glyphdef;
568      glyph->glyphindex = glyphindex;
569      glyph->x0 = (short)gx;
570      glyph->y0 = (short)gy;
571      glyph->x1 = (short)( glyph->x0 + glyphareawidth );
572      glyph->y1 = (short)( glyph->y0 + glyphareaheight );
573      glyph->advance = (short)advance;
574      glyph->offsetx = (short)( x0 - padding );
575      glyph->offsety = (short)( y0 - padding );
576      glyph->listnext = 0;
577      glyph->imageIndex = -1;
578      if( renderer.registerImage )
579      {
580         renderer.setLayer(outlinePass ? 3 : 6);
581         glyph->imageIndex = renderer.registerImage( gx, gy, glyphareawidth, glyphareaheight);
582      }
583
584      // Add char to hash table
585      glyph->listnext = font.hashtable[hashindex];
586      font.hashtable[hashindex] = font.glyphcount - 1;
587
588      // Clear glyph image area (TODO: wasteful when single channel without prepare callback?)
589      dst = &texdata[ ( glyph->x0 * bytesperpixel ) + ( glyph->y0 * bytesperline ) ];
590      for( i = 0 ; i < glyphareaheight ; i++, dst += bytesperline )
591        memset( dst, 0, glyphareawidth * bytesperpixel );
592
593      /* Rasterize */
594      dst = &texdata[ ( glyph->x0 + padding ) * bytesperpixel + ( ( glyph->y0 + padding ) * bytesperline ) + channelindex];
595      if( codepoint == FM_GLYPH_CODEPOINT_CURSOR )
596      {
597          src = new byte[ glyphwidth * glyphheight ];
598          buildCursorGlyph( src, glyphwidth, glyphheight, glyphwidth );
599          copyGlyphBitmap( dst, src, glyphwidth, glyphheight, bytesperline );
600          delete src;
601      }
602      else
603      {
604         src = font.ftFont.getGlyphBitmap(glyphindex);
605         copyGlyphBitmap( dst, src, glyphwidth, glyphheight, bytesperline );
606      }
607
608      // User custom font image processing
609      if(font.processImage)
610      {
611         dst = &texdata[ ( glyph->x0 * bytesperpixel ) + ( glyph->y0 * bytesperline ) ];
612         font.processImage( font.processImageContext, dst, glyphareawidth, glyphareaheight, bytesperpixel, bytesperline, font.glyphPaddingWidth, outlinePass );
613      }
614
615      dirtyrect[0] = Min( dirtyrect[0], glyph->x0 );
616      dirtyrect[1] = Min( dirtyrect[1], glyph->y0 );
617      dirtyrect[2] = Max( dirtyrect[2], glyph->x1 );
618      dirtyrect[3] = Max( dirtyrect[3], glyph->y1 );
619
620      return glyph;
621    }
622
623    static inline void drawTextGlyph( FMFont font, FMGlyph *glyph, int x, int y, bool useExtColor )
624    {
625       int ptx = x + glyph->offsetx;
626       int pty = y + glyph->offsety;
627       if( renderer.drawImage )
628          renderer.drawImage( ptx, pty, glyph->imageIndex, useExtColor );
629       else if( renderer.drawImageAlt )
630          renderer.drawImageAlt( texdata, ptx, pty, glyph->x0, glyph->y0, glyph->x1 - glyph->x0, glyph->y1 - glyph->y0 );
631    }
632
633    static inline void drawTextCursorGlyph( FMFont font, FMGlyph *glyph, int x, int y )
634    {
635      int ptx, pty;
636      ptx = x + glyph->offsetx;
637      pty = y + glyph->offsety;
638      if( renderer.drawImageCursor )
639        renderer.drawImageCursor( ptx, pty, glyph->imageIndex );
640      else if( renderer.drawImageAlt )
641        renderer.drawImageAlt( texdata, ptx, pty, glyph->x0, glyph->y0, glyph->x1 - glyph->x0, glyph->y1 - glyph->y0 );
642    }
643
644    static inline void drawTextGlyphFloat( FMFont font, FMGlyph *glyph, float x, float y, float vectorx, float vectory, float offsetx, float offsety, bool useExtColor )
645    {
646       float vectx = (float)glyph->offsetx + offsetx;
647       float vecty = (float)glyph->offsety + offsety;
648       float ptx = x + ( vectorx * vectx ) - ( vectory * vecty );
649       float pty = y + ( vectorx * vecty ) + ( vectory * vectx );
650       renderer.drawImageFloat( ptx, pty, vectory, vectorx, glyph->imageIndex, useExtColor );
651    }
652
653 public:
654
655    property FontManagerRenderer renderer { set { renderer = value; } get { return renderer; } }
656
657    // When notified of a full atlas, you should call fmExpandAtlas() or fmResetAtlas() within the callback
658    virtual void onAtlasFull()
659    {
660       renderer.flush();
661       atlas.reset(atlas.width, atlas.height);
662    }
663
664    // Create and destroy font manager
665    bool create( int width, int height, int channelCount, int channelIndex, FontManagerRenderer renderer)
666    {
667       bool result = false;
668
669      if( ( channelCount != 1 ) && ( channelCount != 2 ) && ( channelCount != 4 ) )
670        return 0;
671      if( ( width <= 0 ) || ( height <= 0 ) )
672        return 0;
673
674       this.renderer = renderer;
675       incref renderer;
676       renderer.init(channelCount);
677
678       // Initialize implementation library
679       if(FMFreeTypeFont::init() )
680       {
681          this.width = width;
682          this.height = height;
683          bytesperpixel = channelCount;
684          bytesperline = width * bytesperpixel;
685          this.channelindex = channelIndex;
686          if(renderer.createTexture( width, height ))
687          {
688             if((atlas.create( this.width, this.height, FM_INIT_ATLAS_NODES )))
689             {
690                // Create texture for the cache.
691                widthinv = 1.0f / width;
692                heightinv = 1.0f / height;
693                texdata = new byte[width * height * bytesperpixel];
694                if(texdata)
695                {
696                   memset( texdata, 0, height * bytesperline );
697
698                   dirtyrect[0] = this.width;
699                   dirtyrect[1] = this.height;
700                   dirtyrect[2] = 0;
701                   dirtyrect[3] = 0;
702
703                   if( bytesperpixel == 1 )
704                     copyGlyphBitmap = copyGlyphBitmap1;
705                   else if( bytesperpixel == 2 )
706                     copyGlyphBitmap = copyGlyphBitmap2;
707                   else
708                     copyGlyphBitmap = copyGlyphBitmap4;
709
710                  pushState();
711                  clearState();
712
713                  result = true;
714                }
715             }
716          }
717       }
718       return result;
719    }
720
721    ~FontManager()
722    {
723      delete renderer;
724
725      fontList.Free();
726
727      delete atlas;
728      delete texdata;
729    }
730
731
732    ////
733
734    // State setting
735    void setState( FMFont font, int size, int align)
736    {
737      FMState *state;
738      if( size >= FM_SIZE_MAX )
739        size = FM_SIZE_MAX;
740      state = &states[ nstates - 1 ];
741      state->font = font;
742      state->size = (uint16)size;
743      state->align = (uint16)align;
744    }
745
746    void setFont( FMFont font )
747    {
748      states[ nstates - 1 ].font = font;
749    }
750
751    void setSize( int size )
752    {
753      if( size >= FM_SIZE_MAX )
754        size = FM_SIZE_MAX;
755
756      states[ nstates - 1 ].size = (uint16)size;
757    }
758
759    void setAlign( int align )
760    {
761      states[ nstates - 1 ].align = (uint16)align;
762    }
763
764    // Set image manipuation callback
765    void setFontImageProcessing( FMFont font, void (*processImage)( byte *image, int width, int height, int bytesperpixel, int bytesperline, int paddingwidth, void *opaquecontext ), void *opaquecontext )
766    {
767
768    }
769
770    // State handling
771    void pushState( )
772    {
773       if(nstates < FM_MAX_STATES)
774       {
775          if( nstates > 0 )
776             memcpy( &states[nstates], &states[nstates-1], sizeof(FMState) );
777          nstates++;
778       }
779    }
780
781    void popState()
782    {
783       if(nstates > 1)
784          nstates--;
785    }
786
787    void clearState()
788    {
789      FMState *state = &states[ nstates - 1 ];
790      state->size = 12;
791      state->font = 0;
792      state->align = { left, baseline };
793    }
794
795
796    ////
797
798    static void freeFont(FMFont font)
799    {
800      if(font)
801      {
802         fontList.Remove((IteratorPointer)font);
803         delete font;
804      }
805    }
806
807    // Add font from FontResource
808    FMFont getFont(FontResource fontResource)
809    {
810       FMFont font = null;
811
812       Array<FaceInfo> infos = ResolveFont(fontResource.faceName, fontResource.size, fontResource.flags);
813       if(infos)
814       {
815          for(i : infos)
816          {
817             font = addFont(i.fileName, Max(2, (int)(1+fontResource.outlineSize)));
818             if(font)
819             {
820                font.setOutline(fontResource.outlineSize, fontResource.outlineFade);
821                break;
822             }
823          }
824          infos.Free();
825          delete infos;
826       }
827       return font;
828    }
829
830    // Add font from file
831    FMFont addFont(const String path, int glyphPaddingWidth )
832    {
833       FMFont font = null;
834       File f = FileOpen(path, read);
835       if(f)
836       {
837          // Read in the font data
838          int dataSize = f.GetSize();
839          byte *data = new byte[dataSize];
840          if(data)
841          {
842             f.Read(data, 1, dataSize);
843             font = addFontData(data, dataSize, glyphPaddingWidth);
844             if(!font)
845                delete data;
846          }
847          delete f;
848       }
849       return font;
850    }
851
852    // Add font from data ; do not free( data ), the font manager will do that when removing the font
853    FMFont addFontData( byte *data, int dataSize, int glyphPaddingWidth )
854    {
855      FMFont font
856      {
857         glyphs = new FMGlyph[FM_INIT_GLYPHS];
858         glyphalloc = FM_INIT_GLYPHS;
859         glyphPaddingWidth = glyphPaddingWidth;
860      };
861      if(font)
862      {
863          int i;
864          float ascent, descent, fontHeight;
865
866          fontList.Add(font);
867
868          // Init hash lookup
869          for( i = 0 ; i < FM_HASH_TABLE_SIZE ; i++ )
870             font.hashtable[i] = -1;
871
872          // Init font
873          if(!font.ftFont.loadFont(data, dataSize))
874          {
875             freeFont(font );
876             return 0;
877          }
878
879          // Store normalized line height. The real line height is got by multiplying by font size.
880          font.ftFont.getFontVMetrics( &ascent, &descent, &font.lineHeight, &font.limitminy, &font.limitmaxy );
881          fontHeight = ascent - descent;
882          font.ascender = ascent / fontHeight;
883          font.descender = descent / fontHeight;
884          font.middleAlign = 0.5f * ( font.ascender + font.descender );
885          font.fontdata = data;
886       }
887       return font;
888    }
889
890    // Free font
891    void removeFont( FMFont font )
892    {
893       freeFont(font );
894    }
895
896    // Draw text
897    int drawText( int x, int y, const char *string, int stringlength )
898    {
899      int subpixel, index;
900      FMState *state;
901      unichar codepoint;
902      uint32 utf8state;
903      FMGlyph *glyph;
904      int prevGlyphIndex;
905      FMFont font;
906
907      state = &states[ nstates - 1 ];
908      glyph = 0;
909      utf8state = 0;
910      prevGlyphIndex = -1;
911      if( !( state->font ) )
912        return x;
913      font = state->font;
914      if( !( stringlength ) )
915        stringlength = strlen( string );
916
917      // Align horizontally
918      if( state->align.horzAlignment == right )
919        x -= getTextWidth(string, stringlength );
920      else if( state->align.horzAlignment == center )
921        x -= getTextWidth(string, stringlength ) >> 1;
922
923      // Align vertically
924      y += roundf( font.getVertAlign(state->align, state->size ) );
925
926      subpixel = 0;
927      for( index = 0 ; index < stringlength ; index++ )
928      {
929        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
930          continue;
931        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
932        if( glyph )
933        {
934          font.addKerning(prevGlyphIndex, glyph, &x, &subpixel );
935          if(font.processImage)
936          {
937             FMGlyph *outlineGlyph = getGlyph(font, codepoint, state->size, subpixel, true );
938             if(outlineGlyph)
939                drawTextGlyph(font, outlineGlyph, x, y, true );
940          }
941          drawTextGlyph(font, glyph, x, y, false );
942          addGlyphAdvance( &x, &subpixel, glyph );
943        }
944        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
945      }
946
947      return x + ( subpixel >= 32 );
948    }
949
950    int drawTextWithCursor( int x, int y, const char *string, int stringlength, int cursoroffset )
951    {
952      int subpixel, index;
953      FMState *state;
954      unichar codepoint;
955      uint32 utf8state;
956      FMGlyph *glyph;
957      int prevGlyphIndex;
958      FMFont font;
959
960      state = &states[ nstates - 1 ];
961      glyph = 0;
962      utf8state = 0;
963      prevGlyphIndex = -1;
964      if( !( state->font ) )
965        return x;
966      font = state->font;
967      if( !( stringlength ) )
968        stringlength = strlen( string );
969
970      // Align horizontally
971      if( state->align.horzAlignment == right )
972        x -= getTextWidth(string, stringlength );
973      else if( state->align.horzAlignment == center )
974        x -= getTextWidth(string, stringlength ) >> 1;
975
976      // Align vertically
977      y += roundf( font.getVertAlign(state->align, state->size ) );
978
979      subpixel = 0;
980      for( index = 0 ; ; index++ )
981      {
982        if( index == cursoroffset )
983        {
984          glyph = getGlyph(font, FM_GLYPH_CODEPOINT_CURSOR, state->size, subpixel, false );
985          if( glyph )
986            drawTextCursorGlyph(font, glyph, x, y );
987        }
988        if( index >= stringlength )
989          break;
990        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
991          continue;
992        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
993        if( glyph )
994        {
995          font.addKerning(prevGlyphIndex, glyph, &x, &subpixel );
996          if(font.processImage)
997          {
998             FMGlyph *outlineGlyph = getGlyph(font, codepoint, state->size, subpixel, true );
999             if(outlineGlyph)
1000                drawTextGlyph(font, outlineGlyph, x, y, true );
1001          }
1002          drawTextGlyph(font, glyph, x, y, false );
1003          addGlyphAdvance( &x, &subpixel, glyph );
1004        }
1005        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
1006      }
1007
1008      return x + ( subpixel >= 32 );
1009    }
1010
1011    int drawTextTruncate( int x, int y, int truncatewidth, const char *string, int stringlength, char *extstring, int extwidth )
1012    {
1013      int subpixel, index, textwidth, truncatepoint;
1014      FMState *state;
1015      unichar codepoint;
1016      uint32 utf8state;
1017      FMGlyph *glyph;
1018      int prevGlyphIndex;
1019      FMFont font;
1020
1021      state = &states[ nstates - 1 ];
1022      glyph = 0;
1023      utf8state = 0;
1024      prevGlyphIndex = -1;
1025      if( !( state->font ) )
1026        return x;
1027      font = state->font;
1028      if( !( stringlength ) )
1029        stringlength = strlen( string );
1030      textwidth = getTextWidthTruncate(string, stringlength, truncatewidth );
1031
1032      truncatepoint = x + truncatewidth;
1033      if( textwidth <= truncatewidth )
1034        extstring = 0;
1035      else
1036      {
1037        if( extwidth >= truncatewidth )
1038          return x;
1039        truncatepoint -= extwidth;
1040      }
1041
1042      // Align horizontally
1043      if( state->align.horzAlignment == right )
1044        x -= textwidth;
1045      else if( state->align.horzAlignment == center )
1046        x -= textwidth >> 1;
1047
1048      // Align vertically
1049      y += roundf( font.getVertAlign(state->align, state->size ) );
1050
1051      subpixel = 0;
1052      for( index = 0 ; index < stringlength ; index++ )
1053      {
1054        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
1055          continue;
1056        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
1057        if( glyph )
1058        {
1059          font.addKerning(prevGlyphIndex, glyph, &x, &subpixel );
1060          if(font.processImage)
1061          {
1062             FMGlyph *outlineGlyph = getGlyph(font, codepoint, state->size, subpixel, true );
1063             if(outlineGlyph)
1064                drawTextGlyph(font, outlineGlyph, x, y, true );
1065          }
1066          drawTextGlyph(font, glyph, x, y, false );
1067          addGlyphAdvance( &x, &subpixel, glyph );
1068          if( x > truncatepoint )
1069            break;
1070        }
1071        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
1072      }
1073      x += ( subpixel >= 32 );
1074      if( extstring )
1075        drawText(x, y, extstring, 0 );
1076
1077      return x;
1078    }
1079
1080
1081    ////
1082
1083
1084    // Measure text
1085    int getTextWidth( const char *string, int stringlength )
1086    {
1087      return getTextWidthTruncate(string, stringlength, ( (unsigned)1 << ( ( sizeof(int) * CHAR_BIT ) - 1 ) ) - 1 );
1088    }
1089
1090
1091    int getTextWidthTruncate( const char *string, int stringlength, int truncatewidth )
1092    {
1093      int subpixel, index, advance;
1094      FMState *state;
1095      unichar codepoint;
1096      uint32 utf8state;
1097      FMGlyph *glyph;
1098      int prevGlyphIndex;
1099      FMFont font;
1100
1101      state = &states[ nstates - 1 ];
1102      glyph = 0;
1103      utf8state = 0;
1104      prevGlyphIndex = -1;
1105      if( !( state->font ) )
1106        return 0;
1107      font = state->font;
1108      if( !( stringlength ) )
1109        stringlength = strlen( string );
1110
1111      advance = 0;
1112      subpixel = 0;
1113      for( index = 0 ; index < stringlength ; index++ )
1114      {
1115        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
1116          continue;
1117        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
1118        if( glyph )
1119        {
1120          font.addKerning(prevGlyphIndex, glyph, &advance, &subpixel );
1121          addGlyphAdvance( &advance, &subpixel, glyph );
1122          if( advance > truncatewidth )
1123            break;
1124        }
1125        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
1126      }
1127
1128      return advance + ( subpixel >= 32 );
1129    }
1130
1131    int getTextBounds( int x, int y, const char *string, int stringlength, int *bounds )
1132    {
1133      int subpixel, index;
1134      FMState *state;
1135      unichar codepoint;
1136      uint32 utf8state;
1137      FMQuad q;
1138      FMGlyph *glyph;
1139      int prevGlyphIndex;
1140      FMFont font;
1141      int startx, advance;
1142      int minx, miny, maxx, maxy;
1143
1144      state = &states[ nstates - 1 ];
1145      glyph = 0;
1146      utf8state = 0;
1147      prevGlyphIndex = -1;
1148      if( !( state->font ) )
1149        return x;
1150      font = state->font;
1151      if( !( stringlength ) )
1152        stringlength = strlen( string );
1153
1154      // Align vertically
1155      y += font.getVertAlign(state->align, state->size );
1156
1157      minx = maxx = x;
1158      miny = maxy = y;
1159      startx = x;
1160
1161      subpixel = 0;
1162      for( index = 0 ; index < stringlength ; index++ )
1163      {
1164        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
1165          continue;
1166        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
1167        if( glyph )
1168        {
1169          font.addKerning(prevGlyphIndex, glyph, &x, &subpixel );
1170          glyph->getQuad(x, y, q);
1171          if( q.x0 < minx )
1172            minx = q.x0;
1173          if( q.x1 > maxx )
1174            maxx = q.x1;
1175          if( q.y0 < miny )
1176            miny = q.y0;
1177          if( q.y1 > maxy )
1178            maxy = q.y1;
1179          addGlyphAdvance( &x, &subpixel, glyph );
1180        }
1181        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
1182      }
1183
1184      advance = x - startx;
1185
1186      /* Align horizontally */
1187      if( state->align.horzAlignment == right )
1188      {
1189        minx -= advance;
1190        maxx -= advance;
1191      }
1192      else if( state->align.horzAlignment == center )
1193      {
1194        minx -= advance * 0.5f;
1195        maxx -= advance * 0.5f;
1196      }
1197
1198      if( bounds )
1199      {
1200        bounds[0] = minx;
1201        bounds[1] = maxx;
1202        bounds[2] = miny;
1203        bounds[3] = maxy;
1204      }
1205
1206      return advance + ( subpixel >= 32 );
1207    }
1208
1209    // Find text offset up to truncatewidth
1210    int getTextTruncateOffset( int truncatewidth, const char *string, int stringlength, int extwidth, int *retextflag, int *retfullwidth )
1211    {
1212      int subpixel, index, advance, truncatewidthext, truncateindex, extflag, fullwidth = 0;
1213      FMState *state;
1214      unichar codepoint;
1215      uint32 utf8state;
1216      FMGlyph *glyph;
1217      int prevGlyphIndex;
1218      FMFont font;
1219
1220      state = &states[ nstates - 1 ];
1221      if( retextflag )
1222        *retextflag = 0;
1223      if( retfullwidth )
1224        *retfullwidth = 0;
1225      if( extwidth >= truncatewidth )
1226        return 0;
1227      glyph = 0;
1228      utf8state = 0;
1229      prevGlyphIndex = -1;
1230      if( !( state->font ) )
1231        return 0;
1232      font = state->font;
1233      if( stringlength <= 0 )
1234        stringlength = strlen( string );
1235
1236      truncatewidthext = truncatewidth - extwidth;
1237
1238      advance = 0;
1239      subpixel = 0;
1240      truncateindex = 0;
1241      extflag = 0;
1242      for( index = 0 ; ; index++ )
1243      {
1244        if( index >= stringlength )
1245        {
1246          truncateindex = index;
1247          fullwidth = advance + ( subpixel >= 32 );
1248          break;
1249        }
1250        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
1251          continue;
1252        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
1253        if( glyph )
1254        {
1255          font.addKerning(prevGlyphIndex, glyph, &advance, &subpixel );
1256          addGlyphAdvance( &advance, &subpixel, glyph );
1257          if( advance > truncatewidth )
1258          {
1259            extflag = 1;
1260            break;
1261          }
1262          if( advance <= truncatewidthext )
1263          {
1264            truncateindex = index + 1;
1265            fullwidth = advance + ( subpixel >= 32 );
1266          }
1267        }
1268        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
1269      }
1270
1271      if( retfullwidth )
1272      {
1273        if( extflag )
1274          *retfullwidth = fullwidth;
1275        else
1276          *retfullwidth = fullwidth;
1277      }
1278      if( retextflag )
1279        *retextflag = extflag;
1280
1281      return truncateindex;
1282    }
1283
1284    // Find text offset nearest to the given width
1285    int getTextNearestOffset( int targetwidth, const char *string, int stringlength )
1286    {
1287      int subpixel, index, advance, truncateindex, distance, bestdistance;
1288      FMState *state;
1289      unichar codepoint;
1290      uint32 utf8state;
1291      FMGlyph *glyph;
1292      int prevGlyphIndex;
1293      FMFont font;
1294
1295      state = &states[ nstates - 1 ];
1296      glyph = 0;
1297      utf8state = 0;
1298      prevGlyphIndex = -1;
1299      if( !( state->font ) )
1300        return 0;
1301      font = state->font;
1302      if( stringlength <= 0 )
1303        stringlength = strlen( string );
1304
1305      advance = 0;
1306      subpixel = 0;
1307      truncateindex = 0;
1308      bestdistance = abs( targetwidth );
1309      for( index = 0 ; index < stringlength ; index++ )
1310      {
1311        if( decodeUTF8( (byte)string[index], &utf8state, &codepoint ) )
1312          continue;
1313        glyph = getGlyph(font, codepoint, state->size, subpixel, false );
1314        if( glyph )
1315        {
1316          font.addKerning(prevGlyphIndex, glyph, &advance, &subpixel );
1317          addGlyphAdvance( &advance, &subpixel, glyph );
1318          distance = abs( targetwidth - ( advance + ( subpixel >= 32 ) ) );
1319          if( distance > bestdistance )
1320            break;
1321          bestdistance = distance;
1322          truncateindex = index + 1;
1323        }
1324        prevGlyphIndex = ( glyph ? glyph->glyphindex : -1 );
1325      }
1326
1327      return truncateindex;
1328    }
1329
1330    ////
1331
1332    static void flush( bool rendererFlush )
1333    {
1334       // Flush texture updates
1335       if( ( dirtyrect[0] < dirtyrect[2] ) && ( dirtyrect[1] < dirtyrect[3] ) )
1336       {
1337          renderer.updateTexture( dirtyrect, texdata );
1338          // Reset dirty rect
1339          dirtyrect[0] = width;
1340          dirtyrect[1] = height;
1341          dirtyrect[2] = 0;
1342          dirtyrect[3] = 0;
1343       }
1344       // Flush buffered glyphs
1345       if( rendererFlush ) renderer.flush( );
1346    }
1347
1348    // Flush buffered texture updates, renderer->updateTexture()
1349    void flushUpdate( )
1350    {
1351       flush(false );
1352    }
1353
1354    ////
1355
1356    // Text metrics
1357
1358    void getFontExtent( int *retascent, int *retdescent )
1359    {
1360      FMFont font;
1361      FMState *state = &states[ nstates - 1 ];
1362      if(state->font)
1363      {
1364          font = state->font;
1365
1366          if( retascent )
1367             *retascent = -(int)ceilf( font.ascender * (float)state->size );
1368          if( retdescent )
1369             *retdescent = -(int)floorf( font.descender * (float)state->size );
1370       }
1371    }
1372
1373    void getFontLimits( int *retlimitminy, int *retlimitmaxy )
1374    {
1375      FMFont font;
1376      FMState *state;
1377
1378      state = &states[ nstates - 1 ];
1379      if( !( state->font ) )
1380        return;
1381      font = state->font;
1382
1383      if( retlimitminy )
1384        *retlimitminy = -(int)ceilf( font.limitmaxy * state->size );
1385      if( retlimitmaxy )
1386        *retlimitmaxy = -(int)floorf( font.limitminy * state->size );
1387
1388      return;
1389    }
1390
1391    int getFontLineHeight( )
1392    {
1393      FMFont font;
1394      FMState *state;
1395
1396      state = &states[ nstates - 1 ];
1397      if( !( state->font ) )
1398        return 0 ;
1399      font = state->font;
1400      return (int)ceilf( font.lineHeight * state->size );
1401    }
1402
1403
1404    ////
1405
1406    // Pull texture changes
1407    const byte *getTextureData( int *width, int *height )
1408    {
1409       if( width )
1410          *width = this.width;
1411       if( height )
1412          *height = this.height;
1413       return texdata;
1414    }
1415
1416    // Retrieve the dirty rectangle, telling fontmanager you will manually perform the update, returns 0 if no part of the texture requires an update
1417    bool validateTexture( int *retdirtyrect )
1418    {
1419       if( ( dirtyrect[0] < dirtyrect[2] ) && ( dirtyrect[1] < dirtyrect[3] ) )
1420       {
1421          retdirtyrect[0] = dirtyrect[0];
1422          retdirtyrect[1] = dirtyrect[1];
1423          retdirtyrect[2] = dirtyrect[2];
1424          retdirtyrect[3] = dirtyrect[3];
1425          // Reset dirty rect
1426          dirtyrect[0] = width;
1427          dirtyrect[1] = height;
1428          dirtyrect[2] = 0;
1429          dirtyrect[3] = 0;
1430          return true;
1431       }
1432       return false;
1433    }
1434
1435    // Returns current atlas size
1436    void getAtlasSize( int *retwidth, int *retheight )
1437    {
1438      *retwidth = this.width;
1439      *retheight = this.height;
1440      return;
1441    }
1442
1443    // Expands the atlas size
1444    bool expandAtlas( int width, int height )
1445    {
1446       width = Max( width, this.width );
1447       height = Max( height, this.height );
1448
1449       if( ( width == this.width ) && ( height == this.height ) )
1450          return true;
1451
1452       // Flush all pending glyphs
1453       flush(true);
1454
1455       // Create new texture
1456       if( renderer.resizeTexture( width, height ) )
1457       {
1458          byte *data;
1459          int i;
1460
1461          // Copy old texture data over.
1462          if( !( data = new byte[width * bytesperline] ) )
1463             return false;
1464          for( i = 0 ; i < this.height ; i++ )
1465          {
1466             byte * dst = &data[ (i * width) * bytesperpixel ];
1467             byte * src = &this.texdata[ i * this.bytesperline ];
1468             memcpy( dst, src, bytesperline);
1469             if( width > this.width )
1470                memset( dst+bytesperline, 0, (width - this.width) * bytesperpixel );
1471          }
1472          if( height > this.height )
1473             memset( &data[ width * this.height * bytesperpixel], 0, ( height - this.height ) *bytesperline );
1474
1475          delete this.texdata;
1476          texdata = data;
1477
1478          // Increase atlas size
1479          atlas.expand( width, height );
1480
1481          // Add existing data as dirty.
1482          dirtyrect[0] = 0;
1483          dirtyrect[1] = 0;
1484          dirtyrect[2] = this.width;
1485          dirtyrect[3] = atlas.getAtlasMaxHeight();
1486
1487          this.width = width;
1488          this.height = height;
1489          this.bytesperline = this.width * bytesperpixel;
1490          widthinv = 1.0f / this.width;
1491          heightinv = 1.0f / this.height;
1492
1493          return true;
1494       }
1495       return false;
1496    }
1497
1498    // Reset the whole fm
1499    bool resetAtlas( int width, int height )
1500    {
1501       // Flush all pending glyphs
1502       flush(true);
1503
1504       // Create new texture
1505       if(renderer.resizeTexture( width, height ) )
1506       {
1507          // Reset atlas
1508          atlas.reset( width, height );
1509
1510          // Clear texture data.
1511          texdata = renew texdata byte[width * height * bytesperpixel];
1512          if(!texdata) return 0;
1513          memset( this.texdata, 0, width * height );
1514
1515          // Reset dirty rect
1516          dirtyrect[0] = width;
1517          dirtyrect[1] = height;
1518          dirtyrect[2] = 0;
1519          dirtyrect[3] = 0;
1520
1521          // Reset cached glyphs
1522          for(font : fontList)
1523          {
1524             int i;
1525             font.glyphcount = 0;
1526             for( i = 0 ; i < FM_HASH_TABLE_SIZE ; i++ )
1527                font.hashtable[i] = -1;
1528          }
1529          renderer.resetImages( );
1530
1531          this.width = width;
1532          this.height = height;
1533          this.bytesperline = width * bytesperpixel;
1534          this.widthinv = 1.0f / this.width;
1535          this.heightinv = 1.0f / this.height;
1536
1537          return true;
1538       }
1539       return false;
1540    }
1541
1542    ////
1543    bool initPathDraw( FMPathDraw pathdraw )
1544    {
1545      FMState *state = &states[ nstates - 1 ];
1546      FMFont font = state->font;
1547      if(font)
1548      {
1549         pathdraw.prevGlyphIndex = -1;
1550         pathdraw.middleAlign = font.middleAlign * (float)state->size;
1551         return true;
1552      }
1553      return false;
1554    }
1555
1556    float pathDrawCharacter( FMPathDraw pathdraw, float x, float y, float vectorx, float vectory, int unicode )
1557    {
1558       int subpixel;
1559       FMState *state = &states[ nstates - 1 ];
1560       FMFont font = state->font;
1561       FMGlyph *glyph = getGlyph(font, unicode, state->size, 0, false );
1562       if( glyph )
1563       {
1564          subpixel = font.ftFont.getGlyphKernAdvance( pathdraw.prevGlyphIndex, glyph->glyphindex );
1565          if(font.processImage)
1566          {
1567             FMGlyph *outlineGlyph = getGlyph(font, unicode, state->size, 0, true );
1568             if(outlineGlyph)
1569                drawTextGlyphFloat(font, outlineGlyph, x, y, vectorx, vectory, (float)subpixel * (1.0f/64.0f), pathdraw.middleAlign, true );
1570          }
1571          drawTextGlyphFloat(font, glyph, x, y, vectorx, vectory, (float)subpixel * (1.0f/64.0f), pathdraw.middleAlign, false );
1572
1573          subpixel += glyph->advance;
1574          pathdraw.prevGlyphIndex = glyph->glyphindex;
1575       }
1576       else
1577       {
1578          subpixel = 0;
1579          pathdraw.prevGlyphIndex = -1;
1580       }
1581
1582       return (float)subpixel * (1.0f/64.0f);
1583    }
1584
1585    float pathDrawPredictAdvance( FMPathDraw pathdraw, unichar unicode )
1586    {
1587       int subpixel = 0;
1588       FMState *state = &states[ nstates - 1 ];
1589       FMFont font = state->font;
1590       FMGlyph *glyph = getGlyph(font, unicode, state->size, 0, false );
1591       if( glyph )
1592       {
1593          subpixel = font.ftFont.getGlyphKernAdvance( pathdraw.prevGlyphIndex, glyph->glyphindex );
1594          subpixel += glyph->advance;
1595       }
1596       return (float)subpixel * (1.0f/64.0f);
1597    }
1598 }