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