zgl_font_gen.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. {
  2. * Copyright (c) 2012 Andrey Kemka
  3. *
  4. * This software is provided 'as-is', without any express or
  5. * implied warranty. In no event will the authors be held
  6. * liable for any damages arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute
  10. * it freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented;
  13. * you must not claim that you wrote the original software.
  14. * If you use this software in a product, an acknowledgment
  15. * in the product documentation would be appreciated but
  16. * is not required.
  17. *
  18. * 2. Altered source versions must be plainly marked as such,
  19. * and must not be misrepresented as being the original software.
  20. *
  21. * 3. This notice may not be removed or altered from any
  22. * source distribution.
  23. }
  24. unit zgl_font_gen;
  25. {.$DEFINE USE_PNG}
  26. interface
  27. uses
  28. Windows,
  29. {$IFDEF USE_PNG}
  30. SysUtils,
  31. Imaging,
  32. ImagingTypes,
  33. {$ENDIF}
  34. zgl_types,
  35. zgl_math_2d,
  36. zgl_font
  37. ;
  38. type
  39. zglPSymbolNode = ^zglTSymbolNode;
  40. zglTSymbolNode = record
  41. leaf : Boolean;
  42. ID : Integer;
  43. rect : zglTRect;
  44. child : array[0..1] of zglPSymbolNode;
  45. end;
  46. function fontgen_Init: Boolean;
  47. procedure fontgen_BuildFont(var Font: Byte; const FontName: String);
  48. procedure fontgen_SaveFont(Font: Byte; const FileName: String);
  49. var
  50. fg_Font : Byte = 0;
  51. fg_FontNodes : array of zglTSymbolNode;
  52. fg_CharsUse : array[0..65535] of Boolean;
  53. fg_CharsUID : array of WORD;
  54. fg_CharsSize : array of zglTRect;
  55. fg_CharsP : array of Integer;
  56. fg_CharsImage : array of array of Byte;
  57. fg_FontList : zglTStringList;
  58. fg_FontSize : Integer = 10;
  59. fg_FontBold : Boolean;
  60. fg_FontItalic : Boolean;
  61. fg_FontPack : Boolean = TRUE;
  62. fg_FontAA : Boolean = TRUE;
  63. fg_FontPadding : array[0..3] of Byte = (2, 2, 2, 2);
  64. fg_PageSize : Integer = 256;
  65. fg_PageChars : Integer = 17;
  66. implementation
  67. uses
  68. zgl_log,
  69. zgl_screen,
  70. zgl_window,
  71. zgl_textures,
  72. zgl_textures_tga,
  73. zgl_file,
  74. zgl_utils,
  75. math;
  76. procedure image_FlipVertically(var Data : Pointer; w, h, pixelSize : Integer);
  77. var
  78. i : Integer;
  79. scanLine : array of Byte;
  80. begin
  81. SetLength(scanLine, w * pixelSize);
  82. for i := 0 to h shr 1 - 1 do
  83. begin
  84. Move(Pointer(Ptr(Data) + i * w * pixelSize)^, scanLine[0], w * pixelSize);
  85. Move(Pointer(Ptr(Data) + (h - i - 1) * w * pixelSize)^, Pointer(Ptr(Data) + i * w * pixelSize)^, w * pixelSize);
  86. Move(scanLine[0], Pointer(Ptr(Data) + (h - i - 1) * w * pixelSize)^, w * pixelSize);
  87. end;
  88. end;
  89. function fontgen_InsertSymbol(node : zglPSymbolNode; const r : zglTRect; ID : Integer): zglPSymbolNode;
  90. var
  91. dw, dh : Single;
  92. c1, c2 : zglPSymbolNode;
  93. begin
  94. if not node.leaf Then
  95. begin
  96. Result := fontgen_InsertSymbol(node.child[0], r, ID);
  97. if not Assigned(Result) Then
  98. Result := fontgen_InsertSymbol(node.child[1], r, ID);
  99. end else
  100. begin
  101. if node.ID <> -1 Then
  102. begin
  103. Result := nil;
  104. exit;
  105. end;
  106. if (r.W > node.rect.W) or (r.H > node.rect.H) Then
  107. begin
  108. Result := nil;
  109. exit;
  110. end;
  111. if (r.W = node.rect.W) and (r.H = node.rect.H) Then
  112. begin
  113. Result := node;
  114. node.ID := ID;
  115. exit;
  116. end;
  117. zgl_GetMem(Pointer(node.child[0]), SizeOf(zglTSymbolNode));
  118. zgl_GetMem(Pointer(node.child[1]), SizeOf(zglTSymbolNode));
  119. node.leaf := FALSE;
  120. c1 := node.child[0];
  121. c2 := node.child[1];
  122. dw := node.rect.w - r.w;
  123. dh := node.rect.h - r.h;
  124. if dw > dh Then
  125. begin
  126. c1.leaf := TRUE;
  127. c1.ID := -1;
  128. c1.rect.X := node.rect.X;
  129. c1.rect.Y := node.rect.Y;
  130. c1.rect.W := r.W;
  131. c1.rect.H := node.rect.H;
  132. c2.leaf := TRUE;
  133. c2.ID := -1;
  134. c2.rect.X := node.rect.X + r.W;
  135. c2.rect.Y := node.rect.Y;
  136. c2.rect.W := node.rect.W - r.W;
  137. c2.rect.H := node.rect.H;
  138. end else
  139. begin
  140. c1.leaf := TRUE;
  141. c1.ID := -1;
  142. c1.rect.X := node.rect.X;
  143. c1.rect.Y := node.rect.Y;
  144. c1.rect.W := node.rect.W;
  145. c1.rect.H := r.H;
  146. c2.leaf := TRUE;
  147. c2.ID := -1;
  148. c2.rect.X := node.rect.X;
  149. c2.rect.Y := node.rect.Y + r.H;
  150. c2.rect.W := node.rect.W;
  151. c2.rect.H := node.rect.H - r.H;
  152. end;
  153. Result := fontgen_InsertSymbol(Pointer(node.child[0]), r, ID);
  154. end;
  155. end;
  156. procedure fontgen_FreeSymbolNode(node : zglPSymbolNode; root : Boolean);
  157. begin
  158. if Assigned(node.child[0]) Then
  159. fontgen_FreeSymbolNode(node.child[0], FALSE);
  160. if Assigned(node.child[1]) Then
  161. fontgen_FreeSymbolNode(node.child[1], FALSE);
  162. if not root Then
  163. FreeMem(node);
  164. end;
  165. {$IFDEF WIN32}
  166. {$IFNDEF FPC}
  167. type NEWTEXTMETRICEX = NEWTEXTMETRICEXW;
  168. {$ENDIF}
  169. function FontEnumProc(var _para1:ENUMLOGFONTEX;var _para2:NEWTEXTMETRICEX; _para3:longint; _para4:LPARAM):longint;stdcall;
  170. begin
  171. if not (_para1.elfLogFont.lfFaceName[0] in ['A'..'Z', 'a'..'z', '0'..'9']) Then exit;
  172. INC(fg_FontList.Count);
  173. SetLength(fg_FontList.Items, fg_FontList.Count);
  174. fg_FontList.Items[fg_FontList.Count - 1] := _para1.elfLogFont.lfFaceName;
  175. if fg_FontList.Count - 2 >= 0 Then
  176. if fg_FontList.Items[fg_FontList.Count - 1] = fg_FontList.Items[fg_FontList.Count - 2] Then
  177. begin
  178. SetLength(fg_FontList.Items, fg_FontList.Count - 1);
  179. DEC(fg_FontList.Count);
  180. end;
  181. Result := 1;
  182. end;
  183. procedure FontGetSize(pData : Pointer; W, H : Integer; var nW, nH, mX, mY : Integer);
  184. var
  185. i, j : Integer;
  186. maxX, minX : Integer;
  187. maxY, minY : Integer;
  188. begin
  189. maxX := 0;
  190. minX := W;
  191. maxY := 0;
  192. minY := H;
  193. for i := 0 to W - 1 do
  194. for j := 0 to H - 1 do
  195. if PByte(Ptr(pData) + i * 4 + j * W * 4)^ > 0 Then
  196. begin
  197. if i < minX Then minX := i;
  198. if i > maxX Then maxX := i;
  199. if j < minY Then minY := j;
  200. if j > maxY Then maxY := j;
  201. end;
  202. nW := maxX - minX;
  203. nH := maxY - minY;
  204. if nW < 0 Then nW := 0;
  205. if nH < 0 Then nH := 0;
  206. mX := minX;
  207. mY := minY;
  208. if mX = W Then mX := 0;
  209. if mY = H Then mY := 0;
  210. end;
  211. {$ENDIF}
  212. function fontgen_Init : Boolean;
  213. var
  214. i : Integer;
  215. LFont : LOGFONT;
  216. begin
  217. Result := FALSE;
  218. FillChar(LFont, SizeOf(LFont), 0);
  219. LFont.lfCharSet := DEFAULT_CHARSET;
  220. EnumFontFamiliesEx(wndDC, LFont, @FontEnumProc, 0, 0);
  221. u_SortList(fg_FontList, 0, fg_FontList.Count - 1);
  222. Result := TRUE;
  223. end;
  224. procedure fontgen_PutChar(var pData : Pointer; X, Y, ID : Integer);
  225. var
  226. i, j : Integer;
  227. fw, fh : Integer;
  228. pixel : PByte;
  229. begin
  230. if length(fg_CharsImage[ID]) = 0 Then
  231. exit;
  232. fw := Round(fg_CharsSize[ID].W);
  233. fh := Round(fg_CharsSize[ID].H);
  234. for i := 0 to fw - 1 do
  235. for j := 0 to fh - 1 do
  236. begin
  237. pixel := PByte(Ptr(pData) + (i + X) * 4 + (j + Y) * fg_PageSize * 4);
  238. pixel^ := 255; INC(pixel);
  239. pixel^ := 255; INC(pixel);
  240. pixel^ := 255; INC(pixel);
  241. pixel^ := fg_CharsImage[ID, i + j * fw];
  242. end;
  243. end;
  244. procedure fontgen_BuildFont(var Font: Byte; const FontName: String);
  245. var
  246. pData : Pointer;
  247. i, j : Integer;
  248. CharID : Integer;
  249. CharUID : WORD;
  250. cx, cy : Integer;
  251. sx, sy : Integer;
  252. cs : Integer;
  253. u, v : Single;
  254. MaxWidth : Integer;
  255. sn : zglPSymbolNode;
  256. sr : zglTRect;
  257. WDC : HDC;
  258. WFont : HFONT;
  259. Bitmap : BITMAPINFO;
  260. DIB : DWORD;
  261. CharSize : TSize;
  262. TextMetric : TTextMetricW;
  263. Rect : TRect;
  264. minX, minY : Integer;
  265. begin
  266. if (managerFont.Font[Font].Flags and Enable) > 0 then
  267. begin
  268. for i := 0 to Length(managerFont.Font[Font].Pages) - 1 do
  269. tex_Del(managerFont.Font[Font].Pages[i]);
  270. for i := 0 to 65535 do
  271. if Assigned(managerFont.Font[Font].CharDesc[i]) then
  272. begin
  273. Freememory(managerFont.Font[Font].CharDesc[i]);
  274. managerFont.Font[Font].CharDesc[i] := nil;
  275. end;
  276. SetLength(managerFont.Font[Font].Pages, 0);
  277. end;
  278. MaxWidth := 0;
  279. SetLength(fg_CharsSize, managerFont.Font[Font].Count.Chars);
  280. SetLength(fg_CharsUID, managerFont.Font[Font].Count.Chars);
  281. SetLength(fg_CharsImage, managerFont.Font[Font].Count.Chars);
  282. SetLength(fg_CharsP, managerFont.Font[Font].Count.Chars);
  283. j := 0;
  284. for i := 0 to 65535 do
  285. if fg_CharsUse[i] Then
  286. begin
  287. SetLength(fg_CharsUID, j + 1);
  288. fg_CharsUID[j] := i;
  289. INC(j);
  290. end;
  291. {$IFDEF WIN32}
  292. if fg_FontBold Then
  293. cs := FW_BOLD
  294. else
  295. cs := FW_NORMAL;
  296. WFont := CreateFont(- MulDiv(fg_FontSize, GetDeviceCaps(wndDC, LOGPIXELSY), 72), 0, 0, 0,
  297. cs, Byte(fg_FontItalic), 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  298. 5 * Byte(fg_FontAA) or ANTIALIASED_QUALITY * Byte(not fg_FontAA),
  299. DEFAULT_PITCH, PChar(FontName));
  300. WDC := CreateCompatibleDC(0);
  301. SelectObject(WDC, WFont);
  302. SetTextAlign(WDC, TA_LEFT or TA_TOP or TA_NOUPDATECP);
  303. SetTextColor(WDC, $FFFFFF);
  304. SetBkColor (WDC, $000000);
  305. GetTextMetricsW(WDC, TextMetric);
  306. FillChar(Bitmap, SizeOf(BITMAPINFO), 0);
  307. Bitmap.bmiHeader.biWidth := TextMetric.tmMaxCharWidth * 2;
  308. Bitmap.bmiHeader.biHeight := -TextMetric.tmHeight * 2;
  309. Bitmap.bmiHeader.biBitCount := 32;
  310. Bitmap.bmiHeader.biCompression := BI_RGB;
  311. Bitmap.bmiHeader.biPlanes := 1;
  312. Bitmap.bmiHeader.biSize := Sizeof(BITMAPINFOHEADER);
  313. DIB := CreateDIBSection(WDC, Bitmap, DIB_RGB_COLORS, pData, 0, 0);
  314. SelectObject(WDC, DIB);
  315. SetRect(Rect, 0, 0, Bitmap.bmiHeader.biWidth, -Bitmap.bmiHeader.biHeight);
  316. for i := 0 to managerFont.Font[Font].Count.Chars - 1 do
  317. begin
  318. Windows.FillRect(WDC, Rect, GetStockObject(BLACK_BRUSH));
  319. TextOutW(WDC, TextMetric.tmMaxCharWidth div 2, TextMetric.tmHeight div 2, @fg_CharsUID[i], 1);
  320. GetTextExtentPoint32W(WDC, @fg_CharsUID[i], 1, CharSize);
  321. // Microsoft Sucks...
  322. FontGetSize(pData, Bitmap.bmiHeader.biWidth, -Bitmap.bmiHeader.biHeight, cx, cy, minX, minY);
  323. INC(cx, 1 + Byte(fg_FontAA));
  324. INC(cy, 1 + Byte(fg_FontAA));
  325. fg_CharsSize[i].X := minX - TextMetric.tmMaxCharWidth div 2;
  326. fg_CharsSize[i].Y := cy - (TextMetric.tmAscent - (minY - TextMetric.tmHeight div 2));
  327. fg_CharsSize[i].W := cx;
  328. fg_CharsSize[i].H := cy;
  329. fg_CharsP [i] := CharSize.cx;
  330. SetLength(fg_CharsImage[i], cx * cy);
  331. FillChar(fg_CharsImage[i, 0], cx * cy, $FF);
  332. MaxWidth := Trunc(Max(MaxWidth, fg_CharsSize[i].W + fg_FontPadding[0] + fg_FontPadding[2] + Byte(fg_FontAA)));
  333. MaxWidth := Trunc(Max(MaxWidth, fg_CharsSize[i].H + fg_FontPadding[1] + fg_FontPadding[3] + Byte(fg_FontAA)));
  334. for sx := minX to cx + minX - 1 do
  335. for sy := minY to cy + minY - 1 do
  336. fg_CharsImage[i, sx - minX + (sy - minY) * cx] :=
  337. (PByte(Ptr(pData) + sx * 4 + sy * Bitmap.bmiHeader.biWidth * 4 + 0)^ +
  338. PByte(Ptr(pData) + sx * 4 + sy * Bitmap.bmiHeader.biWidth * 4 + 1)^ +
  339. PByte(Ptr(pData) + sx * 4 + sy * Bitmap.bmiHeader.biWidth * 4 + 2)^) div 3;
  340. end;
  341. DeleteObject(DIB);
  342. DeleteDC(WDC);
  343. DeleteObject(WFont);
  344. {$ENDIF}
  345. if fg_FontPack Then
  346. begin
  347. for i := 0 to length(fg_FontNodes) - 1 do
  348. fontgen_FreeSymbolNode(@fg_FontNodes[i], TRUE);
  349. managerFont.Font[Font].Count.Pages := 1;
  350. zgl_GetMem(pData, sqr(fg_PageSize) * 4);
  351. SetLength(managerFont.Font[Font].Pages, managerFont.Font[Font].Count.Pages);
  352. managerFont.Font[Font].Pages[0] := tex_Add;
  353. managerFont.Font[Font].Pages[0].Format := TEX_FORMAT_RGBA;
  354. managerFont.Font[Font].Pages[0].Width := fg_PageSize;
  355. managerFont.Font[Font].Pages[0].Height := fg_PageSize;
  356. managerFont.Font[Font].Pages[0].U := 1;
  357. managerFont.Font[Font].Pages[0].V := 1;
  358. managerFont.Font[Font].Pages[0].Flags := TEX_CLAMP or TEX_FILTER_LINEAR;
  359. SetLength(fg_FontNodes, managerFont.Font[Font].Count.Pages);
  360. fg_FontNodes[0].leaf := TRUE;
  361. fg_FontNodes[0].ID := -1;
  362. fg_FontNodes[0].rect.X := 0;
  363. fg_FontNodes[0].rect.Y := 0;
  364. fg_FontNodes[0].rect.W := fg_PageSize;
  365. fg_FontNodes[0].rect.H := fg_PageSize;
  366. u := 1 / fg_PageSize;
  367. v := 1 / fg_PageSize;
  368. managerFont.Font[Font].MaxHeight := 0;
  369. managerFont.Font[Font].MaxShiftY := 0;
  370. i := 0;
  371. sr.X := 0;
  372. sr.Y := 0;
  373. while i < managerFont.Font[Font].Count.Chars do
  374. begin
  375. CharUID := fg_CharsUID[i];
  376. sr.W := fg_CharsSize[i].W + fg_FontPadding[0] + fg_FontPadding[2];
  377. sr.H := fg_CharsSize[i].H + fg_FontPadding[1] + fg_FontPadding[3];
  378. sn := fontgen_InsertSymbol(@fg_FontNodes[managerFont.Font[Font].Count.Pages - 1], sr, CharUID);
  379. if not Assigned(sn) Then
  380. begin
  381. image_FlipVertically(pData, fg_PageSize, fg_PageSize, 4);
  382. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1] := tex_Create(PByteArray(pData), fg_PageSize, fg_PageSize, TEX_FORMAT_RGBA, TEX_DEFAULT_2D);
  383. zgl_FreeMem(pData);
  384. zgl_GetMem(pData, sqr(fg_PageSize) * 4);
  385. INC(managerFont.Font[Font].Count.Pages);
  386. SetLength(managerFont.Font[Font].Pages, managerFont.Font[Font].Count.Pages);
  387. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1] := tex_Add();
  388. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1].Format := TEX_FORMAT_RGBA;
  389. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1].Width := fg_PageSize;
  390. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1].Height := fg_PageSize;
  391. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1].U := 1;
  392. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1].V := 1;
  393. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1].Flags := TEX_CLAMP or TEX_FILTER_LINEAR;
  394. SetLength(fg_FontNodes, managerFont.Font[Font].Count.Pages);
  395. fg_FontNodes[managerFont.Font[Font].Count.Pages - 1].leaf := TRUE;
  396. fg_FontNodes[managerFont.Font[Font].Count.Pages - 1].ID := -1;
  397. fg_FontNodes[managerFont.Font[Font].Count.Pages - 1].rect.X := 0;
  398. fg_FontNodes[managerFont.Font[Font].Count.Pages - 1].rect.Y := 0;
  399. fg_FontNodes[managerFont.Font[Font].Count.Pages - 1].rect.W := fg_PageSize;
  400. fg_FontNodes[managerFont.Font[Font].Count.Pages - 1].rect.H := fg_PageSize;
  401. end else
  402. begin
  403. fontgen_PutChar(pData, Round(sn.rect.X + fg_FontPadding[0]), Round(sn.rect.Y + fg_FontPadding[1]), i);
  404. SetLength(fg_CharsImage[i], 0);
  405. zgl_GetMem(Pointer(managerFont.Font[Font].CharDesc[CharUID]), SizeOf(zglTCharDesc));
  406. managerFont.Font[Font].CharDesc[CharUID].Page := managerFont.Font[Font].Count.Pages - 1;
  407. managerFont.Font[Font].CharDesc[CharUID].Width := Round(fg_CharsSize[i].W);
  408. managerFont.Font[Font].CharDesc[CharUID].Height := Round(fg_CharsSize[i].H);
  409. managerFont.Font[Font].CharDesc[CharUID].ShiftX := Round(fg_CharsSize[i].X);
  410. managerFont.Font[Font].CharDesc[CharUID].ShiftY := Round(fg_CharsSize[i].Y);
  411. managerFont.Font[Font].CharDesc[CharUID].ShiftP := fg_CharsP[i];
  412. managerFont.Font[Font].CharDesc[CharUID].TexCoords[0].X := (sn.rect.X) * u;
  413. managerFont.Font[Font].CharDesc[CharUID].TexCoords[0].Y := 1 - (sn.rect.Y) * v;
  414. managerFont.Font[Font].CharDesc[CharUID].TexCoords[1].X := (sn.rect.X + sn.rect.W) * u;
  415. managerFont.Font[Font].CharDesc[CharUID].TexCoords[1].Y := 1 - (sn.rect.Y) * v;
  416. managerFont.Font[Font].CharDesc[CharUID].TexCoords[2].X := (sn.rect.X + sn.rect.W) * u;
  417. managerFont.Font[Font].CharDesc[CharUID].TexCoords[2].Y := 1 - (sn.rect.Y + sn.rect.H) * v;
  418. managerFont.Font[Font].CharDesc[CharUID].TexCoords[3].X := (sn.rect.X) * u;
  419. managerFont.Font[Font].CharDesc[CharUID].TexCoords[3].Y := 1 - (sn.rect.Y + sn.rect.H) * v;
  420. managerFont.Font[Font].MaxHeight := Round(Max(managerFont.Font[Font].MaxHeight, fg_CharsSize[i].H));
  421. managerFont.Font[Font].MaxShiftY := Round(Max(managerFont.Font[Font].MaxShiftY, managerFont.Font[Font].CharDesc[CharUID].ShiftY));
  422. INC(i);
  423. end;
  424. end;
  425. image_FlipVertically(pData, fg_PageSize, fg_PageSize, 4);
  426. managerFont.Font[Font].Pages[managerFont.Font[Font].Count.Pages - 1] := tex_Create(PByteArray(pData), fg_PageSize, fg_PageSize, TEX_FORMAT_RGBA, TEX_DEFAULT_2D);
  427. zgl_FreeMem(pData);
  428. end else
  429. begin
  430. if MaxWidth = 0 Then
  431. MaxWidth := 1;
  432. fg_PageChars := fg_PageSize div MaxWidth;
  433. cs := fg_PageSize div fg_PageChars;
  434. managerFont.Font[Font].Count.Pages := managerFont.Font[Font].Count.Chars div sqr(fg_PageChars) + 1;
  435. SetLength(managerFont.Font[Font].Pages, managerFont.Font[Font].Count.Pages);
  436. managerFont.Font[Font].MaxHeight := 0;
  437. managerFont.Font[Font].MaxShiftY := 0;
  438. for i := 0 to managerFont.Font[Font].Count.Pages - 1 do
  439. begin
  440. u := 1 / fg_PageSize;
  441. v := 1 / fg_PageSize;
  442. zgl_GetMem(pData, sqr(fg_PageSize) * 4);
  443. for j := 0 to sqr(fg_PageChars) - 1 do
  444. begin
  445. CharID := j + i * sqr(fg_PageChars);
  446. if CharID > managerFont.Font[Font].Count.Chars - 1 Then
  447. break;
  448. cy := j div fg_PageChars;
  449. cx := j - cy * fg_PageChars;
  450. fontgen_PutChar(pData, cx * cs + (cs - Round(fg_CharsSize[CharID].W)) div 2,
  451. cy * cs + (cs - Round(fg_CharsSize[CharID].H)) div 2, CharID);
  452. SetLength(fg_CharsImage[CharID], 0);
  453. CharUID := fg_CharsUID[CharID];
  454. zgl_GetMem(Pointer(managerFont.Font[Font].CharDesc[CharUID]), SizeOf(zglTCharDesc));
  455. managerFont.Font[Font].CharDesc[CharUID].Page := i;
  456. managerFont.Font[Font].CharDesc[CharUID].Width := Round(fg_CharsSize[CharID].W);
  457. managerFont.Font[Font].CharDesc[CharUID].Height := Round(fg_CharsSize[CharID].H);
  458. managerFont.Font[Font].CharDesc[CharUID].ShiftX := Round(fg_CharsSize[CharID].X);
  459. managerFont.Font[Font].CharDesc[CharUID].ShiftY := Round(fg_CharsSize[CharID].Y);
  460. managerFont.Font[Font].CharDesc[CharUID].ShiftP := fg_CharsP[CharID];
  461. sx := Round(fg_CharsSize[CharID].W);
  462. sy := Round(fg_CharsSize[CharID].H);
  463. managerFont.Font[Font].CharDesc[CharUID].TexCoords[0].X := (cx * cs + (cs - sx) div 2 - fg_FontPadding[0]) * u;
  464. managerFont.Font[Font].CharDesc[CharUID].TexCoords[0].Y := 1 - (cy * cs + (cs - sy) div 2 - fg_FontPadding[1]) * v;
  465. managerFont.Font[Font].CharDesc[CharUID].TexCoords[1].X := (cx * cs + (cs - sx) div 2 + sx + fg_FontPadding[2]) * u;
  466. managerFont.Font[Font].CharDesc[CharUID].TexCoords[1].Y := 1 - (cy * cs + (cs - sy) div 2 - fg_FontPadding[1]) * v;
  467. managerFont.Font[Font].CharDesc[CharUID].TexCoords[2].X := (cx * cs + (cs - sx) div 2 + sx + fg_FontPadding[2]) * u;
  468. managerFont.Font[Font].CharDesc[CharUID].TexCoords[2].Y := 1 - (cy * cs + (cs - sy) div 2 + sy + fg_FontPadding[3]) * v;
  469. managerFont.Font[Font].CharDesc[CharUID].TexCoords[3].X := (cx * cs + (cs - sx) div 2 - fg_FontPadding[0]) * u;
  470. managerFont.Font[Font].CharDesc[CharUID].TexCoords[3].Y := 1 - (cy * cs + (cs - sy) div 2 + sy + fg_FontPadding[3]) * v;
  471. managerFont.Font[Font].MaxHeight := Round(Max(managerFont.Font[Font].MaxHeight, fg_CharsSize[CharID].H));
  472. managerFont.Font[Font].MaxShiftY := Round(Max(managerFont.Font[Font].MaxShiftY, managerFont.Font[Font].CharDesc[CharUID].ShiftY));
  473. end;
  474. image_FlipVertically(pData, fg_PageSize, fg_PageSize, 4);
  475. managerFont.Font[Font].Pages[i] := tex_Create(PByteArray(pData), fg_PageSize, fg_PageSize, TEX_FORMAT_RGBA, TEX_DEFAULT_2D);
  476. zgl_FreeMem(pData);
  477. end;
  478. end;
  479. managerFont.Font[Font].Padding[0] := fg_FontPadding[0];
  480. managerFont.Font[Font].Padding[1] := fg_FontPadding[1];
  481. managerFont.Font[Font].Padding[2] := fg_FontPadding[2];
  482. managerFont.Font[Font].Padding[3] := fg_FontPadding[3];
  483. end;
  484. procedure fontgen_SaveFont(Font: Byte; const FileName: String);
  485. type
  486. zglPTGAHeader = ^zglTTGAHeader;
  487. zglTTGAHeader = packed record
  488. IDLength : Byte;
  489. CPalType : Byte;
  490. ImageType : Byte;
  491. CPalSpec : packed record
  492. FirstEntry : Word;
  493. Length : Word;
  494. EntrySize : Byte;
  495. end;
  496. ImgSpec : packed record
  497. X : Word;
  498. Y : Word;
  499. Width : Word;
  500. Height : Word;
  501. Depth : Byte;
  502. Desc : Byte;
  503. end;
  504. end;
  505. var
  506. TGA : zglTTGAHeader;
  507. F : zglTFile;
  508. i, c : Integer;
  509. Data : Pointer;
  510. {$IFDEF USE_PNG}
  511. Image : TImageData;
  512. {$ENDIF}
  513. begin
  514. file_Open(F, FileName + '.zfi', FOM_CREATE);
  515. file_Write(F, ZGL_FONT_INFO, 13);
  516. file_Write(F, managerFont.Font[Font].Count.Pages, 2);
  517. file_Write(F, managerFont.Font[Font].Count.Chars, 2);
  518. file_Write(F, managerFont.Font[Font].MaxHeight, 4);
  519. file_Write(F, managerFont.Font[Font].MaxShiftY, 4);
  520. file_Write(F, fg_FontPadding[0], 4);
  521. for i := 0 to managerFont.Font[Font].Count.Chars - 1 do
  522. begin
  523. c := fg_CharsUID[i];
  524. file_Write(F, c, 4);
  525. file_Write(F, managerFont.Font[Font].CharDesc[c].Page, 4);
  526. file_Write(F, managerFont.Font[Font].CharDesc[c].Width, 1);
  527. file_Write(F, managerFont.Font[Font].CharDesc[c].Height, 1);
  528. file_Write(F, managerFont.Font[Font].CharDesc[c].ShiftX, 4);
  529. file_Write(F, managerFont.Font[Font].CharDesc[c].ShiftY, 4);
  530. file_Write(F, managerFont.Font[Font].CharDesc[c].ShiftP, 4);
  531. file_Write(F, managerFont.Font[Font].CharDesc[c].TexCoords[0], SizeOf(zglTPoint2D) * 4);
  532. end;
  533. file_Close(F);
  534. for i := 0 to managerFont.Font[Font].Count.Pages - 1 do
  535. begin
  536. FillChar(TGA, SizeOf(zglTTGAHeader), 0);
  537. TGA.ImageType := 2;
  538. TGA.ImgSpec.Width := fg_PageSize;
  539. TGA.ImgSpec.Height := fg_PageSize;
  540. TGA.ImgSpec.Depth := 32;
  541. TGA.ImgSpec.Desc := 8;
  542. tex_GetData(managerFont.Font[Font].Pages[i], PByteArray(Data));
  543. file_Open(F, FileName + '-page' + u_IntToStr(i) + '.tga', FOM_CREATE);
  544. file_Write(F, TGA, SizeOf(zglTTGAHeader));
  545. file_Write(F, Data^, sqr(fg_PageSize) * 4);
  546. file_Close(F);
  547. FreeMemory(Data);
  548. {$IFDEF USE_PNG}
  549. LoadImageFromFile(FileName + '-page' + u_IntToStr(i) + '.tga', Image);
  550. ConvertImage(Image, ifA8R8G8B8);
  551. SaveImageToFile(FileName + '-page' + u_IntToStr(i) + '.png', Image);
  552. DeleteFile(FileName + '-page' + u_IntToStr(i) + '.tga');
  553. {$ENDIF}
  554. end;
  555. end;
  556. end.