00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include <string>
00029
00030 #include "nel/misc/types_nl.h"
00031 #include "nel/misc/debug.h"
00032 #include "nel/misc/common.h"
00033 #include "nel/misc/path.h"
00034
00035 #include "3d/font_generator.h"
00036
00037 using namespace std;
00038
00039 #ifndef NL_DONT_USE_EXTERNAL_CODE
00040
00041 #include <freetype/freetype.h>
00042
00043
00044 #ifdef FTERRORS_H
00045 #undef FTERRORS_H
00046 #endif
00047
00048
00049 #ifdef __FTERRORS_H__
00050 #undef __FTERRORS_H__
00051 #endif
00052
00053 #define FT_ERRORDEF( e, v, s ) { e, s },
00054 #define FT_ERROR_START_LIST {
00055 #define FT_ERROR_END_LIST { 0, 0 } };
00056
00057 const struct
00058 {
00059 int err_code;
00060 const char* err_msg;
00061 } ft_errors[] =
00062
00063 #include <freetype/fterrors.h>
00064
00065 using namespace NLMISC;
00066
00067 namespace NL3D {
00068
00069 FT_Library CFontGenerator::_Library;
00070 bool CFontGenerator::_LibraryInit = false;
00071
00072
00073 const char *CFontGenerator::getFT2Error(FT_Error fte)
00074 {
00075 NL_ALLOC_CONTEXT (FreeTyp);
00076
00077 static char ukn[1024];
00078
00079 for (uint32 i = 0; ft_errors[i].err_code != 0 || ft_errors[i].err_msg != 0; i++)
00080 {
00081 if (ft_errors[i].err_code == fte)
00082 return ft_errors[i].err_msg;
00083 }
00084 smprintf (ukn, 1024, "Unknown freetype2 error, errcode: 0x%x", fte);
00085 return ukn;
00086 }
00087
00088
00089
00090
00091
00092
00093 CFontGenerator::CFontGenerator (const std::string &fontFileName, const std::string &fontExFileName)
00094 {
00095 NL_ALLOC_CONTEXT (FreeTyp);
00096
00097 FT_Error error;
00098
00099 if (!_LibraryInit)
00100 {
00101 error = FT_Init_FreeType (&_Library);
00102 if (error)
00103 {
00104 nlerror ("FT_Init_FreeType() failed: %s", getFT2Error(error));
00105 }
00106 _LibraryInit = true;
00107 }
00108
00109 error = FT_New_Face (_Library, fontFileName.c_str (), 0, &_Face);
00110 if (error)
00111 {
00112 nlerror ("FT_New_Face() failed with file '%s': %s", fontFileName.c_str(), getFT2Error(error));
00113 }
00114
00115 string fontEx = fontExFileName;
00116 if (fontEx == "")
00117 {
00118
00119 fontEx = CPath::lookup(CFile::getFilenameWithoutExtension (fontFileName)+".afm", false, false);
00120 }
00121
00122 if (fontEx != "")
00123 {
00124 error = FT_Attach_File (_Face, fontEx.c_str ());
00125 if (error)
00126 {
00127 nlwarning ("FT_Attach_File() failed with file '%s': %s", fontEx.c_str(), getFT2Error(error));
00128 }
00129 }
00130
00131 error = FT_Select_Charmap (_Face, ft_encoding_unicode);
00132 if (error)
00133 {
00134 nlerror ("FT_Select_Charmap() failed with file '%s': %s", fontFileName.c_str(), getFT2Error(error));
00135 }
00136 }
00137
00138 CFontGenerator::~CFontGenerator ()
00139 {
00140 }
00141
00142 void CFontGenerator::getSizes (ucchar c, uint32 size, uint32 &width, uint32 &height)
00143 {
00144 NL_ALLOC_CONTEXT (FreeTyp);
00145
00146 FT_Error error;
00147
00148 error = FT_Set_Pixel_Sizes (_Face, size, size);
00149 if (error)
00150 {
00151 nlerror ("FT_Set_Pixel_Sizes() failed: %s", getFT2Error(error));
00152 }
00153
00154
00155 FT_UInt glyph_index = FT_Get_Char_Index (_Face, c);
00156
00157
00158 error = FT_Load_Glyph (_Face, glyph_index, FT_LOAD_DEFAULT);
00159 if (error)
00160 {
00161 nlerror ("FT_Load_Glyph() failed: %s", getFT2Error(error));
00162 }
00163
00164
00165 width = _Face->glyph->metrics.width >> 6;
00166 height = _Face->glyph->metrics.height >> 6;
00167 }
00168
00169 uint8 *CFontGenerator::getBitmap (ucchar c, uint32 size, uint32 &width, uint32 &height, uint32 &pitch, sint32 &left, sint32 &top, sint32 &advx, uint32 &glyphIndex)
00170 {
00171 NL_ALLOC_CONTEXT (FreeTyp);
00172
00173 FT_Error error;
00174
00175 error = FT_Set_Pixel_Sizes (_Face, size, size);
00176 if (error)
00177 {
00178 nlerror ("FT_Set_Pixel_Sizes() failed: %s", getFT2Error(error));
00179 }
00180
00181
00182 FT_UInt glyph_index = FT_Get_Char_Index (_Face, c);
00183
00184
00185 error = FT_Load_Glyph (_Face, glyph_index, FT_LOAD_DEFAULT);
00186 if (error)
00187 {
00188 nlerror ("FT_Load_Glyph() failed: %s", getFT2Error(error));
00189 }
00190
00191 if (size == 0)
00192 {
00193 width = 0;
00194 height = 0;
00195 pitch = 0;
00196 left = 0;
00197 top = 0;
00198 advx = 0;
00199 glyphIndex = glyph_index;
00200 return NULL;
00201 }
00202
00203
00204 error = FT_Render_Glyph (_Face->glyph, ft_render_mode_normal);
00205 if (error)
00206 {
00207 nlerror ("FT_Render_Glyph() failed: %s", getFT2Error(error));
00208 }
00209
00210 width = _Face->glyph->bitmap.width;
00211 height = _Face->glyph->bitmap.rows;
00212 pitch = _Face->glyph->bitmap.pitch;
00213
00214 left = _Face->glyph->bitmap_left;
00215 top = _Face->glyph->bitmap_top;
00216
00217 advx = _Face->glyph->advance.x >> 6;
00218
00219 glyphIndex = glyph_index;
00220
00221 return (uint8 *) _Face->glyph->bitmap.buffer;
00222 }
00223
00224
00225
00226 void CFontGenerator::getKerning (ucchar left, ucchar right, sint32 &kernx)
00227 {
00228 NL_ALLOC_CONTEXT (FreeTyp);
00229
00230 if (!FT_HAS_KERNING(_Face))
00231 {
00232 kernx = 0;
00233 }
00234 else
00235 {
00236 FT_Vector kerning;
00237 FT_Error error = FT_Get_Kerning (_Face, left, right, ft_kerning_default, &kerning);
00238 if (error)
00239 {
00240 nlerror ("FT_Get_Kerning() failed: %s", getFT2Error(error));
00241 }
00242 kernx = kerning.x;
00243 }
00244 }
00245
00246
00247
00248 uint32 CFontGenerator::getCharIndex (ucchar c)
00249 {
00250 NL_ALLOC_CONTEXT (FreeTyp);
00251
00252 return FT_Get_Char_Index (_Face, c);
00253 }
00254
00255 }
00256
00257 #else // NL_DONT_USE_EXTERNAL_CODE
00258
00259 #include <windows.h>
00260
00261 using namespace NLMISC;
00262
00263 namespace NL3D {
00264
00265 HBITMAP Dib;
00266 uint32 *Buffer;
00267 HDC hdcDib;
00268 int Width = 100;
00269 int Height = 100;
00270
00271
00272
00273
00274 CFontGenerator::CFontGenerator (const std::string &fontFileName, const std::string &fontExFileName)
00275 {
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 BITMAPINFO info;
00288 info.bmiHeader.biWidth = Width;
00289 info.bmiHeader.biHeight= -Height;
00290 info.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
00291 info.bmiHeader.biPlanes = 1;
00292 info.bmiHeader.biBitCount = 32;
00293 info.bmiHeader.biCompression = BI_RGB;
00294 info.bmiHeader.biSizeImage = 4*Width*Height;
00295 info.bmiHeader.biXPelsPerMeter = 1;
00296 info.bmiHeader.biYPelsPerMeter = 1;
00297 info.bmiHeader.biClrUsed = 0;
00298 info.bmiHeader.biClrImportant = 0;
00299
00300 HDC hdc = GetDC (NULL);
00301 nlassert (hdc);
00302 Dib = CreateDIBSection (hdc, &info, DIB_RGB_COLORS, (void**)&Buffer, NULL, NULL);
00303
00304 hdcDib = CreateCompatibleDC (hdc);
00305 nlassert (hdcDib);
00306
00307
00308 ReleaseDC (NULL, hdc);
00309
00310 SetTextAlign (hdcDib, TA_TOP | TA_LEFT | TA_NOUPDATECP);
00311 SetBkColor (hdcDib, RGB (0,0,0));
00312 SetTextColor (hdcDib, RGB (255, 255, 255));
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 }
00341
00342 CFontGenerator::~CFontGenerator ()
00343 {
00344 DeleteObject (Dib);
00345
00346 DeleteDC (hdcDib);
00347 }
00348
00349 void CFontGenerator::getSizes (ucchar c, uint32 size, uint32 &width, uint32 &height)
00350 {
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 }
00374
00375 HFONT hFont = NULL;
00376 uint32 CurrentFontSize = 0;
00377
00378 uint8 *CFontGenerator::getBitmap (ucchar c, uint32 size, uint32 &width, uint32 &height, uint32 &pitch, sint32 &left, sint32 &top, sint32 &advx, uint32 &glyphIndex)
00379 {
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 if (size == 0)
00432 {
00433 width = 0;
00434 height = 0;
00435 pitch = 0;
00436 left = 0;
00437 top = 0;
00438 advx = 0;
00439 glyphIndex = 0;
00440 return NULL;
00441 }
00442
00443
00444 if (hFont == NULL || CurrentFontSize != size)
00445 {
00446 if (hFont != NULL)
00447 {
00448 DeleteObject (hFont);
00449 }
00450
00451 hFont=CreateFont
00452 (
00453 size,
00454 0,
00455 0,
00456 0,
00457 FW_DONTCARE,
00458 FALSE,
00459 FALSE,
00460 FALSE,
00461 DEFAULT_CHARSET,
00462 OUT_DEVICE_PRECIS,
00463 CLIP_DEFAULT_PRECIS,
00464 DEFAULT_QUALITY,
00465 DEFAULT_PITCH|FF_DONTCARE,
00466 "Arial Unicode MS Normal"
00467 );
00468 nlassert (hFont);
00469
00470 CurrentFontSize = size;
00471 }
00472
00473 SelectObject (hdcDib, hFont);
00474 SelectObject (hdcDib, Dib);
00475
00476 const char cc = (char) c;
00477
00478 RECT rect;
00479 rect.bottom = Height;
00480 rect.top = 0;
00481 rect.left = 0;
00482 rect.right = Width;
00483
00484 int res = DrawText (hdcDib, &cc, 1, &rect, DT_LEFT | DT_TOP);
00485
00486 POINT point;
00487 point.y = res;
00488
00489 int w = res;
00490 BOOL rey = GetCharWidth32 (hdcDib, (uint8) cc, (uint8) cc, &w);
00491 nlassert (rey);
00492 point.x = w;
00493
00494
00495
00496
00497
00498
00499 SIZE s;
00500 GetTextExtentPoint32 (hdcDib, &cc, 1, &s);
00501
00502 BOOL ret = LPtoDP (hdcDib, &point, 1);
00503 nlassert (ret);
00504
00505 static uint8 buf[100*100];
00506
00507 sint32 _top = 0, _left = point.x;
00508 sint32 right = 0, bottom = point.y;
00509 bool emptyLine;
00510 for (sint y = 0; y < point.y; y++)
00511 {
00512 emptyLine = true;
00513 for (sint x = 0; x < point.x; x++)
00514 {
00515 buf[y*100+x] = (uint8) Buffer[y*100+x];
00516 if (buf[y*100+x])
00517 {
00518 emptyLine = false;
00519 if (x < _left)
00520 _left = x;
00521 if (x > right)
00522 right = x;
00523 }
00524
00525
00526 }
00527 if (!emptyLine)
00528 {
00529 if (_top == 0)
00530 _top = y;
00531
00532 bottom = y;
00533 }
00534
00535
00536 }
00537 width = right - _left + 1;
00538 if (right - _left + 1 < 0) width = 0;
00539 height = bottom - _top + 1;
00540 if (bottom - _top + 1 < 0) height = 0;
00541 pitch = 100;
00542 advx = point.x;
00543
00544 WORD ag = 0;
00545
00546
00547
00548
00549
00550
00551 glyphIndex = ag;
00552
00553 top = -_top;
00554 left = -_left;
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 _top = _left = top = left = 0;
00570 top = s.cy;
00571 width = s.cx;
00572 height = s.cy;
00573
00574 return buf + _top * 100 + _left;
00575 }
00576
00577
00578
00579
00580 void CFontGenerator::getKerning (ucchar left, ucchar right, sint32 &kernx)
00581 {
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 }
00597
00598
00599
00600 uint32 CFontGenerator::getCharIndex (ucchar c)
00601 {
00602
00603 return 0;
00604 }
00605
00606
00607 }
00608
00609 #endif // NL_DONT_USE_EXTERNAL_CODE
00610