2 fegdk: FE Game Development Kit
3 Copyright (C) 2001-2008 Alexey "waker" Yakovenko
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 waker@users.sourceforge.net
26 #include "f_filesystem.h"
29 #include "f_baseviewport.h"
30 #include "f_texture.h"
31 #include "f_drawutil.h"
32 #include "f_baserenderer.h"
33 #include "f_resourcemgr.h"
42 #include FT_FREETYPE_H
44 //#include FT_INTERNAL_OBJECTS_H
45 //#include FT_INTERNAL_CALC_H
47 #include FT_TRIGONOMETRY_H
48 #include FT_SYNTHESIS_H
53 #define FT_BOLD_THRESHOLD 0x0100
56 /*************************************************************************/
57 /*************************************************************************/
59 /**** EXPERIMENTAL OBLIQUING SUPPORT ****/
61 /*************************************************************************/
62 /*************************************************************************/
65 FT_GlyphSlot_Oblique (FT_GlyphSlot slot
)
68 FT_Outline
* outline
= &slot
->outline
;
71 /* only oblique outline glyphs */
72 if (slot
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
75 /* we don't touch the advance width */
77 /* For italic, simply apply a shear transform, with an angle */
78 /* of about 12 degrees. */
80 transform
.xx
= 0x10000L
;
81 transform
.yx
= 0x00000L
;
83 transform
.xy
= 0x06000L
;
84 transform
.yy
= 0x10000L
;
86 FT_Outline_Transform (outline
, &transform
);
90 /*************************************************************************/
91 /*************************************************************************/
93 /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/
95 /*************************************************************************/
96 /*************************************************************************/
101 ft_test_extrema (FT_Outline
* outline
,
104 FT_Vector
*prev
, *cur
, *next
;
106 FT_Int c
, first
, last
;
109 /* we need to compute the `previous' and `next' point */
110 /* for these extrema. */
111 cur
= outline
->points
+ n
;
116 for (c
= 0; c
< outline
->n_contours
; c
++)
118 last
= outline
->contours
[c
];
121 prev
= outline
->points
+ last
;
124 next
= outline
->points
+ first
;
129 product
= FT_MulDiv (cur
->x
- prev
->x
, /* in.x */
130 next
->y
- cur
->y
, /* out.y */
133 FT_MulDiv (cur
->y
- prev
->y
, /* in.y */
134 next
->x
- cur
->x
, /* out.x */
138 product
= product
> 0 ? 1 : -1;
144 /* Compute the orientation of path filling. It differs between TrueType */
145 /* and Type1 formats. We could use the `FT_OUTLINE_REVERSE_FILL' flag, */
146 /* but it is better to re-compute it directly (it seems that this flag */
147 /* isn't correctly set for some weird composite glyphs currently). */
149 /* We do this by computing bounding box points, and computing their */
152 /* The function returns either 1 or -1. */
155 ft_get_orientation (FT_Outline
* outline
)
167 box
.xMin
= box
.yMin
= 32767;
168 box
.xMax
= box
.yMax
= -32768;
171 if (outline
->n_contours
< 1)
174 last
= outline
->contours
[outline
->n_contours
- 1];
176 for (n
= 0; n
<= last
; n
++)
181 x
= outline
->points
[n
].x
;
193 y
= outline
->points
[n
].y
;
206 /* test orientation of the xmin */
207 n
= ft_test_extrema (outline
, indices
.xMin
);
211 n
= ft_test_extrema (outline
, indices
.yMin
);
215 n
= ft_test_extrema (outline
, indices
.xMax
);
219 n
= ft_test_extrema (outline
, indices
.yMax
);
229 FT_GlyphSlot_Embolden (FT_GlyphSlot slot
)
232 FT_Vector v_prev
, v_first
, v_next
, v_cur
;
234 FT_Outline
* outline
= &slot
->outline
;
235 FT_Face face
= FT_SLOT_FACE (slot
);
236 FT_Angle rotate
, angle_in
, angle_out
;
237 FT_Int c
, n
, first
, orientation
;
240 /* only embolden outline glyph images */
241 if (slot
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
244 /* compute control distance */
245 distance
= FT_MulFix (face
->units_per_EM
/ 60,
246 face
->size
->metrics
.y_scale
);
248 orientation
= ft_get_orientation (outline
);
249 rotate
= FT_ANGLE_PI2
*orientation
;
251 points
= outline
->points
;
254 for (c
= 0; c
< outline
->n_contours
; c
++)
256 int last
= outline
->contours
[c
];
259 v_first
= points
[first
];
260 v_prev
= points
[last
];
263 for (n
= first
; n
<= last
; n
++)
271 if (n
< last
) v_next
= points
[n
+ 1];
272 else v_next
= v_first
;
274 /* compute the in and out vectors */
275 in
.x
= v_cur
.x
- v_prev
.x
;
276 in
.y
= v_cur
.y
- v_prev
.y
;
278 out
.x
= v_next
.x
- v_cur
.x
;
279 out
.y
= v_next
.y
- v_cur
.y
;
281 angle_in
= FT_Atan2 (in
.x
, in
.y
);
282 angle_out
= FT_Atan2 (out
.x
, out
.y
);
283 angle_diff
= FT_Angle_Diff (angle_in
, angle_out
);
284 scale
= FT_Cos (angle_diff
/2);
286 if (scale
< 0x400L
&& scale
> -0x400L
)
294 d
= FT_DivFix (distance
, scale
);
296 FT_Vector_From_Polar (&in
, d
, angle_in
+ angle_diff
/2 - rotate
);
298 outline
->points
[n
].x
= v_cur
.x
+ distance
+ in
.x
;
299 outline
->points
[n
].y
= v_cur
.y
+ distance
+ in
.y
;
308 slot
->metrics
.horiAdvance
= (slot
->metrics
.horiAdvance
+ distance
*4) & -64;
315 const int FontTextureSize
= 256;
318 const int fontFT::hAlignLeft
= 0x00000001; // could it be a default
319 const int fontFT::hAlignRight
= 0x00000002;
320 const int fontFT::hAlignCenter
= 0x00000004;
321 const int fontFT::hAlignStretch
= 0x00000008;
324 const int fontFT::vAlignTop
= 0x00000010;
325 const int fontFT::vAlignBottom
= 0x00000020;
326 const int fontFT::vAlignCenter
= 0x00000040;
329 const int fontFT::wordWrap
= 0x00000100;
331 // removes line gap before first line
332 const int fontFT::remove1stLineGap
= 0x00000200;
333 const int fontFT::useClipRect
= 0x00000400;
335 //fontFT::fontFT (const char *fname, const char *fontname, int size, bool antialias, bool bold, bool italic)
336 fontFT::fontFT (const char *name
)
343 char *buf
= new char[strlen (name
)+1];
354 colon
= strchr (tmp
, ':');
363 colon
= strchr (tmp
, ':');
367 mHeight
= atoi (tmp
);
372 colon
= strchr (tmp
, ':');
376 mbAntialias
= atoi (tmp
) ? true : false;
381 colon
= strchr (tmp
, ':');
385 mbBold
= atoi (tmp
) ? true : false;
390 colon
= strchr (tmp
, ':');
394 mbItalic
= atoi (tmp
) ? true : false;
399 mbItalic
= atoi (tmp
) ? true : false;
402 mbBold
= atoi (tmp
) ? true : false;
405 mbAntialias
= atoi (tmp
) ? true : false;
408 mHeight
= atoi (tmp
);
411 mFontFileName
= name
;
418 NOTE: oooooooold stuff from win32 gdi days
419 96 is the default windows value for LOGPIXELSY
420 72 is the value from formula from msdn article on LOGFONT structure
421 [q] For the MM_TEXT mapping mode, you can use the following formula to specify a height for a font with a specified point size:
422 lfHeight = -MulDiv (PointSize, GetDeviceCaps (hDC, LOGPIXELSY), 72); [/q]
425 // try to load the glyph name as-is
426 char fname
[100] = "fonts/";
427 strcat (fname
, mFontFileName
);
429 // open using fe filesystem
430 f
= g_engine
->getFileSystem ()->openFile (fname
, FS_MODE_READ
);
433 if (!strstr (fname
, ".ttf"))
434 strcat (fname
, ".ttf");
435 f
= g_engine
->getFileSystem ()->openFile (fname
, FS_MODE_READ
);
437 sys_error ("failed to open font file (%s)", name
);
440 mFntCacheSize
= f
->getSize ();
441 mpFntCache
= new FT_Byte
[mFntCacheSize
];
442 f
->read (mpFntCache
, mFntCacheSize
);
450 fontFT::fontFT (charParser
&parser
, const char *name
)
454 fontFT::~fontFT (void)
465 texturePtr
fontFT::allocTexture (void) const
468 texture_name
.printf ("empty:%d:%d:%s:%d", FontTextureSize
, FontTextureSize
, mName
.c_str (), mpTextures
.size ());
469 texturePtr t
= g_engine
->getResourceMgr ()->createTexture (texture_name
);
470 mpTextures
.push_back (t
);
473 lockedRect rc
= t
->lockRect (0, NULL
, false);
474 memset (rc
.pBits
, 0x00, rc
.pitch
* t
->getHeight ());
481 screenshot_write (const char *fname
, const char *bits
, int pitch
)
483 struct jpeg_compress_struct cinfo
;
484 struct jpeg_error_mgr jerr
;
486 FILE* fp
; //Target file
487 int nSampsPerRow
; //Physical row width in image buffer
490 cinfo
.err
= jpeg_std_error(&jerr
); //Use default error handling (ugly!)
492 jpeg_create_compress(&cinfo
);
494 fp
= fopen (fname
, "w+b");
496 jpeg_stdio_dest(&cinfo
, fp
);
498 cinfo
.image_width
= FontTextureSize
; //Image width and height, in pixels
499 cinfo
.image_height
= FontTextureSize
;
500 cinfo
.input_components
= 1; //Color components per pixel
501 //(RGB_PIXELSIZE - see jmorecfg.h)
502 cinfo
.in_color_space
= JCS_GRAYSCALE
; //Colorspace of input image
504 jpeg_set_defaults(&cinfo
);
506 jpeg_set_quality(&cinfo
,
507 100, //Quality: 0-100 scale
508 TRUE
); //Limit to baseline-JPEG values
510 jpeg_start_compress(&cinfo
, TRUE
);
512 //JSAMPLEs per row in output buffer
513 nSampsPerRow
= cinfo
.image_width
* cinfo
.input_components
;
515 //Write the array of scan lines to the JPEG file
516 for (i
= 0; i
< FontTextureSize
; i
++)
518 // unsigned char *c = &bits[i*width*3];
519 unsigned char *c
= new unsigned char[FontTextureSize
];
520 for (int k
= 0; k
< FontTextureSize
; k
++)
522 c
[k
] = bits
[i
* pitch
+ k
*4+2];
524 jpeg_write_scanlines(&cinfo
, &c
, 1);
528 jpeg_finish_compress(&cinfo
); //Always finish
532 jpeg_destroy_compress(&cinfo
); //Free resources
535 int fontFT::getGlyphIdx (wchar_t c
) const
537 int ptsize
= mHeight
;
539 FT_Encoding encoding
= ft_encoding_unicode
;
540 glyphMap::const_iterator it
= mGlyphMap
.find (c
);
541 if (it
== mGlyphMap
.end ())
543 int sx
= mCurrentX
, sy
= mCurrentY
;
545 if (mpTextures
.empty ())
548 t
= mpTextures
[mpTextures
.size () - 1];
549 lockedRect rc
= t
->lockRect (0, NULL
, 0);
552 g
.texture
= mpTextures
.size () - 1;
557 FT_UInt load_flags
= FT_LOAD_DEFAULT
;
558 error
= FT_Select_Charmap (mFace
, encoding
);
560 sys_error ("Invalid charmap");
561 g
.ft_glyph_index
= FT_Get_Char_Index (mFace
, (FT_ULong
)c
);
562 error
= FT_Load_Glyph (mFace
, g
.ft_glyph_index
, load_flags
);
564 sys_error ("FT_Load_Glyph failed!");
567 FT_GlyphSlot_Embolden (mFace->glyph);
569 FT_GlyphSlot_Oblique (mFace->glyph);*/
572 error
= FT_Get_Glyph (mFace
->glyph
, &gimage
);
574 sys_error ("FT_Get_Glyph failed!");
577 FT_Glyph_Get_CBox (gimage
, ft_glyph_bbox_truncate
, &bb
);
578 g
.origin
[0] = bb
.xMin
;
579 g
.origin
[1] = bb
.yMin
;
585 error
= FT_Glyph_Copy (gimage
, &image
);
588 error
= FT_Glyph_To_Bitmap (&image
, mbAntialias
? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO
, 0, 1);
591 // throw genericError ("FT_Glyph_To_Bitmap failed!");
592 FT_BitmapGlyph bitmap
= (FT_BitmapGlyph
)image
;
593 FT_Bitmap
* source
= &bitmap
->bitmap
;
596 int rows
= source
->rows
;
597 int width
= source
->width
;
598 int pitch
= source
->pitch
;
599 unsigned char *buffer
= source
->buffer
;
601 int max
= source
->num_grays
- 1;
614 if (sx
+ width
>= FontTextureSize
)
622 g
.maxs
[0] = sx
+ width
;
623 g
.maxs
[1] = sy
+ rows
;
625 g
.advance
[0] = mFace
->glyph
->advance
.x
>> 6;
626 g
.advance
[1] = mFace
->glyph
->advance
.y
>> 6;
628 // this hack was used for some crazy font which had tiny space symbol
631 // space may be to small
635 uchar
*dst
= (unsigned char *)rc
.pBits
;
636 write
= (ulong
*) (dst
+ sx
*4 + rc
.pitch
* sy
);
640 if (sy
+ (rows
-y
) >= FontTextureSize
)
642 // out of texture space
646 lockedRect rc
= t
->lockRect (0, NULL
, 0);
648 dst
= (unsigned char *)rc
.pBits
;
650 write
= (ulong
*) (dst
+ sx
*4 + rc
.pitch
* sy
);
653 g
.maxs
[0] = sx
+ width
;
654 g
.maxs
[1] = sy
+ rows
;
655 g
.texture
= mpTextures
.size () - 1;
658 unsigned char* _read
= read
;
659 uchar
* _write
= (uchar
*)write
;
670 val
= ( (val
& (1<<xx
))>>xx
) ? 0xff : 0x00;
683 /* compose gray value */
688 int d
, half
= max
>> 1;
690 pix
+= (unsigned char) ((val
*d
+ half
)/max
);
699 if (mbAntialias
|| xx
< 0)
708 write
= (ulong
*) (( (uchar
*)write
)+rc
.pitch
);
714 FT_Done_Glyph (image
);
718 FT_Done_Glyph (gimage
);
719 int idx
= mGlyphs
.size ();
721 mGlyphs
.push_back (g
);
722 if (sys_debug_freetype
->ivalue
)
725 sprintf (str
, "%s%d.jpg", name (), mpTextures
.size ()-1);
727 while (ptr
= strstr (str
, ":"))
731 screenshot_write (str
, (char *)rc
.pBits
, rc
.pitch
);
741 void fontFT::restore (void)
745 int antialias
= mbAntialias
;
750 int ptsize
= mHeight
;
752 error
= FT_Init_FreeType (&mLibrary
);
754 sys_error ("Could not initialize FreeType library");
756 error
= FT_New_Memory_Face (mLibrary
, mpFntCache
, mFntCacheSize
, 0, &mFace
);
758 sys_error ("FT_New_Memory_Face failed (%s)", mName
.c_str ());
760 // FIXME we should ALWAYS select from available font sizes instead of forcing font to scale
763 (void)FT_Set_Char_Size (mFace
,
771 mHeight
= (mFace
->available_sizes
[0].size
>>6)+1;
772 fprintf (stderr
, "INFO: autodetected %s font size is %d\n", mName
.c_str (), mHeight
);
775 mCurrentX
= mCurrentY
= 0;
777 mGlyphs
= std::vector
<glyph
> ();
778 mGlyphs
.reserve (128);
783 void fontFT::loose (void)
790 FT_Done_Face (mFace
);
795 FT_Done_FreeType (mLibrary
);
802 void fontFT::drawTextString (const char *text
, int sx
, int sy
, unsigned long color
) const
804 drawTextStringEx (text
, -1, sx
, sy
, color
, 0);
807 void fontFT::drawTextStringEx (const char *text
, int size
, int sx_
, int sy
, unsigned long color
, float spacing
, bool setProj
) const
811 int clrstackdepth
= 0;
812 char clrstack
[100] = { 0 };
814 unsigned long colortable
[] = {
827 // this will tell us size IN BYTES
836 float sx
= (float)sx_
;
838 // g_engine->getDrawUtil ()->fastDrawBegin ();
843 matrix4 mIdent (true);
844 mProj.orthoOffCenterLH (0, g_engine->getViewport ()->getWidth (), 0, g_engine->getViewport ()->getHeight (), .001f, 1.f);
845 g_engine->getEffectParms ()->setMatrix (effectParm_WorldMatrix, mIdent);
846 g_engine->getEffectParms ()->setMatrix (effectParm_ViewMatrix, mIdent);
847 g_engine->getEffectParms ()->setMatrix (effectParm_ProjMatrix, mProj);
850 g_engine
->getDrawUtil ()->allowTransforms (true);
854 const glyph
*gprev
= NULL
;
855 const char *c
= text
;
857 while (c
- text
< sz
)
865 else if (*c
== (char)-1)
868 if (clrstackdepth
> 0)
871 clr
= clrstack
[clrstackdepth
];
876 else if (*c
>= 1 && *c
<= 10)
880 clrstack
[clrstackdepth
] = clr
;
885 else if (*c
== 2 || *c
== 3)
898 sx
+= mGlyphs
[0].advance
[0] * 8;
901 else if (*c
< 32 && *c
> 0)
917 charcode
= u8_nextchar (c
, &incr
);
919 int gidx
= getGlyphIdx (charcode
);
920 const glyph
*g
= &mGlyphs
[gidx
];
922 int x
= (int)floor (sx
);
925 if (gprev
&& 32 != charcode
)
928 FT_Get_Kerning (mFace
, gprev
->ft_glyph_index
, g
->ft_glyph_index
,
938 // convert to upper left
939 y
-= (g
->maxs
[1] - g
->mins
[1]);
940 y
+= this->getTextHeight ();
942 if (g
->texture
!= fontpage
)
944 fontpage
= g
->texture
;
945 mpTextures
[fontpage
]->bind (0);
947 g_engine
->getDrawUtil ()->drawPic (x
, y
, g
->maxs
[0] - g
->mins
[0], g
->maxs
[1] - g
->mins
[1], (float)g
->mins
[0] / (float)FontTextureSize
, (float)g
->mins
[1] / (float)FontTextureSize
, (float)g
->maxs
[0] / (float)FontTextureSize
, (float)g
->maxs
[1] / (float)FontTextureSize
, colortable
[clr
], true);
949 sx
= sx
+ g
->advance
[0];
958 int fontFT::getLineGap (void) const
960 return mHeight
- ( (mFace
->size
->metrics
.ascender
+ mFace
->size
->metrics
.descender
) >> 6);
963 int fontFT::getTextHeight (void) const
968 char* fontFT::preformat (const char *text
969 , int wx
, int wy
, int ww
, int wh
// page window
970 , unsigned long format_flags
) const // flags
976 // determine number of '\n's
978 for (start
= text
; *start
; start
++)
980 if (*start
== '\\' && * (start
+1) == 'n')
984 size_t str_len
= strlen (text
)+1+numindents
* 4;
985 char *formatted
= new char[str_len
];
986 const char *end
= text
;
987 char *fptr
= formatted
;
990 char *indent_ptr
= fptr
;
995 fptr
= indent_ptr
+ 4;
1004 if (*end
< 32 && *end
> 0)
1018 else if (*end
== '\\') // pass '\' char
1024 else if (*end
== 'n')
1035 else if (*end
== 't')
1041 else if (*end
== 'c')
1049 *fptr
= 1; // color tag
1053 else if (*end
>= '0' && *end
<= '9')
1054 *fptr
= (*end
) - '0' + 1; // FIXME: is it the right way?
1065 else if (*end
== 'i') // newline indentation
1074 indent_ptr
[1] = *end
- '0' + 1;
1077 else if (*end
== 'I') // newline indentation
1086 indent_ptr
[3] = *end
- '0' + 1;
1090 /* else if (*end < 0)
1104 assert (fptr
- formatted
+ 1 <= (int)str_len
);
1108 int fontFT::getLineCnt (const char *text
1109 , int wx
, int wy
, int ww
, int wh
// page window
1110 , unsigned long flags
) const // flags
1114 // do precalc on numlines
1115 const char *start
= text
;
1119 int ix
= 0, ix2
= 0;
1122 // break on terminating zero
1130 while (*start
== 32)
1133 const char *end
= start
;
1134 const char *lastword
= start
;
1143 else if ('\n' == *end
)
1183 int gidx
= getGlyphIdx (*end
);
1184 const glyph
*g
= &mGlyphs
[gidx
];
1185 if (w
+ g
->advance
[0] >= ww
&& (flags
& wordWrap
))
1189 // window is less than word width
1201 if (* (end
-1) == 32)
1218 w
+= ix
* mGlyphs
[0].advance
[0];
1220 w
+= ix2
* mGlyphs
[0].advance
[0];
1233 void fontFT::freePreformatted (char *text
) const
1239 int fontFT::getNumberOfLines (const char *text
1240 , int wx
, int wy
, int ww
, int wh
// page window
1241 , unsigned long flags
) const // flags
1245 char *formatted
= preformat (text
, wx
, wy
, ww
, wh
, flags
);
1246 int lines
= getLineCnt (formatted
, wx
, wy
, ww
, wh
, flags
);
1247 freePreformatted (formatted
);
1251 void fontFT::drawTextStringPreformatted (const char *formatted
, int sx
, int sy
, int sw
, int sh
, int wx
, int wy
, int ww
, int wh
, unsigned long color
, unsigned long flags
) const
1253 bool vp_changed
= false;
1254 int H
= g_engine
->getViewport ()->getHeight ();
1256 if (flags
&useClipRect
)
1258 mProj
.orthoOffCenterLH (sx
, sx
+ sw
, H
- (sy
+ sh
), H
- sy
, .001f
, 1.f
);
1261 const char *start
= formatted
;
1269 if (flags
& remove1stLineGap
)
1271 line_gap
= getLineGap ();
1275 if ( (flags
& vAlignBottom
) || (flags
&vAlignCenter
))
1277 numlines
= getLineCnt (formatted
, wx
, wy
, ww
, wh
, flags
);
1278 if (flags
& vAlignBottom
)
1279 wy
= wy
+ wh
- (numlines
* getTextHeight () - line_gap
) - line_gap
;
1280 else if (flags
&vAlignCenter
)
1281 wy
= wy
+ wh
/ 2 - (numlines
* getTextHeight () - line_gap
) / 2 - line_gap
;
1295 // break on terminating zero
1301 while (*start
== 32)
1304 const char *end
= start
;
1305 const char *lastword
= start
;
1316 else if ('\n' == *end
)
1337 w
-= ix
* mGlyphs
[0].advance
[0];
1340 w
+= ix
* mGlyphs
[0].advance
[0];
1350 w
-= ix2
* mGlyphs
[0].advance
[0];
1353 w
+= ix2
* mGlyphs
[0].advance
[0];
1364 uint32 charcode
= 0;
1373 charcode
= u8_nextchar (end
, &incr
);
1374 fprintf (stderr
, "INFO: printing char %d, incr=%d\n", charcode
, incr
);
1376 int gidx
= getGlyphIdx (charcode
);
1377 const glyph
*g
= &mGlyphs
[gidx
];
1378 if (w
+ g
->advance
[0] >= ww
&& (flags
& wordWrap
))
1382 // window is less than word width
1411 w
+= ix
* mGlyphs
[0].advance
[0];
1413 w
+= ix2
* mGlyphs
[0].advance
[0];
1417 prevchar
= charcode
;
1422 // assert (w <= ww);
1424 // ok, we have a line between a 'start' and 'end'
1425 // width is 'w' (in pixels)
1427 // do alignment (relative to page window)
1431 // check if we've got a EOL
1432 const char *eol
= end
;
1433 while (*eol
&& *eol
<= 32)
1442 if (flags
& hAlignLeft
)
1444 // do nothing, it's aligned already
1448 else if (flags
& hAlignRight
)
1454 else if (flags
& hAlignCenter
)
1457 x
= wx
+ ww
/ 2 - w
/ 2;
1460 else if (flags
& hAlignStretch
)
1462 // stretch -- calc number of pixels required to fill a line (float value?)
1468 spacing
= wordcnt
> 1 ? (float) (ww
- w
) / (wordcnt
- 1) : 0;
1470 else // same as 'AlignLeft'
1476 int y
= /*g_engine->getViewport ()->getHeight () - getTextHeight () - */wy
;
1480 if (false == vp_changed
&& (flags
& useClipRect
))
1482 g_engine
->getRenderer ()->setViewport (sx
, sy
, sw
, sh
);
1487 matrix4
mIdent (true);
1488 g_engine
->getEffectParms ()->setMatrix (effectParm_WorldMatrix
, mIdent
);
1489 g_engine
->getEffectParms ()->setMatrix (effectParm_ViewMatrix
, mIdent
);
1490 g_engine
->getEffectParms ()->setMatrix (effectParm_ProjMatrix
, mProj
);
1492 drawTextStringEx (start
, end
-start
1493 , (i1
? mGlyphs
[0].advance
[0] * ix
: 0) + (i2
? mGlyphs
[0].advance
[0] * ix2
: 0) + x
1504 wy
+= getTextHeight ();
1509 g_engine
->getRenderer ()->setViewport (0, 0, g_engine
->getViewport ()->getWidth (), g_engine
->getViewport ()->getHeight ());
1513 void fontFT::drawTextStringFormatted (const char *text
1514 , int sx
, int sy
, int sw
, int sh
// display window
1515 , int wx
, int wy
, int ww
, int wh
// page window
1516 , unsigned long color
// outer color
1517 , unsigned long flags
) const // flags
1521 // NOTE: it is guaranteed that formatted line will be smaller
1522 // NOTE: in size than original, due to the fact that any
1523 // NOTE: formatting sequence will be converted into lesser
1524 // NOTE: or exactly the same number of string characters
1525 // NOTE: e.g.: \c0 = 0x0101, \n = 0x0a, \i5 = 0x0206
1526 // NOTE: though, each indented block is being prepended
1527 // NOTE: with 4 words of indentation parameters
1529 char *formatted
= preformat (text
, wx
, wy
, ww
, wh
, flags
);
1530 drawTextStringPreformatted (formatted
, sx
, sy
, sw
, sh
, wx
, wy
, ww
, wh
, color
, flags
);
1531 freePreformatted (formatted
);
1535 void fontFT::getTextExtent (const char *text
, size_t sz
, int &sx
, int &sy
) const
1537 const char *c
= text
;
1539 while (c
- text
< (int)sz
)
1543 wchar_t wc
= u8_nextchar (c
, &incr
);
1544 const glyph
*g
= &mGlyphs
[getGlyphIdx (wc
)];
1545 sx
= sx
+ g
->advance
[0];
1548 sy
= getTextHeight ();