GLBitmapFont.pas 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Bitmap Fonts management classes
  6. }
  7. unit GLBitmapFont;
  8. {$I GLScene.inc}
  9. interface
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. System.Types,
  14. Vcl.Graphics,
  15. Vcl.StdCtrls,
  16. OpenGLTokens,
  17. GLScene,
  18. GLVectorGeometry,
  19. GLContext,
  20. GLCrossPlatform,
  21. GLTexture,
  22. GLState,
  23. GLUtils,
  24. GLGraphics,
  25. GLColor,
  26. GLBaseClasses,
  27. GLRenderContextInfo,
  28. GLTextureFormat,
  29. GLVectorTypes,
  30. GLPersistentClasses;
  31. type
  32. { An individual character range in a bitmap font.
  33. A range allows mapping ASCII characters to character tiles in a font
  34. bitmap, tiles are enumerated line then column (raster). }
  35. TGLBitmapFontRange = class(TCollectionItem)
  36. private
  37. function GetStartASCII: WideString;
  38. function GetStopASCII: WideString;
  39. protected
  40. FStartASCII, FStopASCII: WideChar;
  41. FStartGlyphIdx, FStopGlyphIdx, FCharCount: Integer;
  42. procedure SetStartASCII(const val: WideString);
  43. procedure SetStopASCII(const val: WideString);
  44. procedure SetStartGlyphIdx(val: Integer);
  45. function GetDisplayName: string; override;
  46. public
  47. constructor Create(Collection: TCollection); override;
  48. destructor Destroy; override;
  49. procedure Assign(Source: TPersistent); override;
  50. procedure NotifyChange;
  51. published
  52. property StartASCII: WideString read GetStartASCII write SetStartASCII;
  53. property StopASCII: WideString read GetStopASCII write SetStopASCII;
  54. property StartGlyphIdx: Integer read FStartGlyphIdx write SetStartGlyphIdx;
  55. property StopGlyphIdx: Integer read FStopGlyphIdx;
  56. property CharCount: Integer read FCharCount;
  57. end;
  58. TGLBitmapFontRanges = class(TCollection)
  59. private
  60. FCharCount: Integer;
  61. protected
  62. FOwner: TComponent;
  63. function GetOwner: TPersistent; override;
  64. procedure SetItems(index: Integer; const val: TGLBitmapFontRange);
  65. function GetItems(index: Integer): TGLBitmapFontRange;
  66. function CalcCharacterCount: Integer;
  67. procedure Update(Item: TCollectionItem); override;
  68. public
  69. constructor Create(AOwner: TComponent);
  70. destructor Destroy; override;
  71. function Add: TGLBitmapFontRange; overload;
  72. function Add(const StartASCII, StopASCII: WideChar)
  73. : TGLBitmapFontRange; overload;
  74. function Add(const StartASCII, StopASCII: AnsiChar)
  75. : TGLBitmapFontRange; overload;
  76. function FindItemID(ID: Integer): TGLBitmapFontRange;
  77. property Items[index: Integer]: TGLBitmapFontRange read GetItems
  78. write SetItems; default;
  79. { Converts an ASCII character into a tile index.
  80. Return -1 if character cannot be rendered. }
  81. function CharacterToTileIndex(aChar: WideChar): Integer;
  82. function TileIndexToChar(aIndex: Integer): WideChar;
  83. procedure NotifyChange;
  84. { Total number of characters in the ranges; cached for performance }
  85. property CharacterCount: Integer read FCharCount;
  86. end;
  87. PCharInfo = ^TCharInfo;
  88. TCharInfo = record
  89. l, t, w: word;
  90. end;
  91. { Provides access to individual characters in a BitmapFont.
  92. Only fixed-width bitmap fonts are supported, the characters are enumerated
  93. in a raster fashion (line then column).
  94. Transparency is all or nothing, the transparent color being that of the
  95. top left pixel of the Glyphs bitmap.
  96. Performance note: as usual, for best performance, you base font bitmap
  97. dimensions should be close to a power of two, and have at least 1 pixel
  98. spacing between characters (horizontally and vertically) to avoid artefacts
  99. when rendering with linear filtering. }
  100. TGLCustomBitmapFont = class(TGLUpdateAbleComponent)
  101. private
  102. FRanges: TGLBitmapFontRanges;
  103. FGlyphs: TPicture;
  104. FCharWidth, FCharHeight: Integer;
  105. FGlyphsIntervalX, FGlyphsIntervalY: Integer;
  106. FHSpace, FVSpace, FHSpaceFix: Integer;
  107. FUsers: TList;
  108. FMinFilter: TGLMinFilter;
  109. FMagFilter: TGLMagFilter;
  110. FTextureWidth, FTextureHeight: Integer;
  111. FTextRows, FTextCols: Integer;
  112. FGlyphsAlpha: TGLTextureImageAlpha;
  113. FTextures: TList;
  114. FTextureModified: boolean;
  115. FLastTexture: TGLTextureHandle;
  116. protected
  117. FChars: array of TCharInfo;
  118. FCharsLoaded: boolean;
  119. procedure ResetCharWidths(w: Integer = -1);
  120. procedure SetCharWidths(index, value: Integer);
  121. procedure SetRanges(const val: TGLBitmapFontRanges);
  122. procedure SetGlyphs(const val: TPicture);
  123. procedure SetCharWidth(const val: Integer);
  124. procedure SetCharHeight(const val: Integer);
  125. procedure SetGlyphsIntervalX(const val: Integer);
  126. procedure SetGlyphsIntervalY(const val: Integer);
  127. procedure OnGlyphsChanged(Sender: TObject);
  128. procedure SetHSpace(const val: Integer);
  129. procedure SetVSpace(const val: Integer);
  130. procedure SetMagFilter(AValue: TGLMagFilter);
  131. procedure SetMinFilter(AValue: TGLMinFilter);
  132. procedure SetGlyphsAlpha(val: TGLTextureImageAlpha);
  133. procedure TextureChanged;
  134. procedure FreeTextureHandle; virtual;
  135. function TextureFormat: Integer; virtual;
  136. procedure InvalidateUsers;
  137. function CharactersPerRow: Integer;
  138. procedure GetCharTexCoords(Ch: WideChar;
  139. var TopLeft, BottomRight: TTexPoint);
  140. procedure GetICharTexCoords(var ARci: TGLRenderContextInfo; Chi: Integer;
  141. out TopLeft, BottomRight: TTexPoint);
  142. procedure PrepareImage(var ARci: TGLRenderContextInfo); virtual;
  143. procedure PrepareParams(var ARci: TGLRenderContextInfo);
  144. { A single bitmap containing all the characters.
  145. The transparent color is that of the top left pixel. }
  146. property Glyphs: TPicture read FGlyphs write SetGlyphs;
  147. { Nb of horizontal pixels between two columns in the Glyphs. }
  148. property GlyphsIntervalX: Integer read FGlyphsIntervalX
  149. write SetGlyphsIntervalX;
  150. { Nb of vertical pixels between two rows in the Glyphs. }
  151. property GlyphsIntervalY: Integer read FGlyphsIntervalY
  152. write SetGlyphsIntervalY;
  153. { Ranges allow converting between ASCII and tile indexes.
  154. See TGLCustomBitmapFontRange. }
  155. property Ranges: TGLBitmapFontRanges read FRanges write SetRanges;
  156. { Width of a single character. }
  157. property CharWidth: Integer read FCharWidth write SetCharWidth default 16;
  158. { Pixels in between rendered characters (horizontally). }
  159. property HSpace: Integer read FHSpace write SetHSpace default 1;
  160. { Pixels in between rendered lines (vertically). }
  161. property VSpace: Integer read FVSpace write SetVSpace default 1;
  162. { Horizontal spacing fix offset.
  163. This property is for internal use, and is added to the hspacing
  164. of each character when rendering, typically to fix extra spacing. }
  165. property HSpaceFix: Integer read FHSpaceFix write FHSpaceFix;
  166. property MagFilter: TGLMagFilter read FMagFilter write SetMagFilter
  167. default maLinear;
  168. property MinFilter: TGLMinFilter read FMinFilter write SetMinFilter
  169. default miLinear;
  170. property GlyphsAlpha: TGLTextureImageAlpha read FGlyphsAlpha
  171. write FGlyphsAlpha default tiaDefault;
  172. public
  173. constructor Create(AOwner: TComponent); override;
  174. destructor Destroy; override;
  175. procedure RegisterUser(anObject: TGLBaseSceneObject); virtual;
  176. procedure UnRegisterUser(anObject: TGLBaseSceneObject); virtual;
  177. { Renders the given string at current position or at position given by the optional position variable.
  178. The current matrix is blindly used, meaning you can render all kinds
  179. of rotated and linear distorted text with this method, OpenGL
  180. Enable states are also possibly altered. }
  181. procedure RenderString(var ARci: TGLRenderContextInfo;
  182. const aText: UnicodeString; aAlignment: TAlignment;
  183. aLayout: TTextLayout; const aColor: TColorVector;
  184. aPosition: PVector = nil; aReverseY: boolean = False); overload; virtual;
  185. { A simpler canvas-style TextOut helper for RenderString.
  186. The rendering is reversed along Y by default, to allow direct use
  187. with TGLCanvas }
  188. procedure TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
  189. const Text: UnicodeString; const Color: TColorVector); overload;
  190. procedure TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
  191. const Text: UnicodeString; const Color: TColor); overload;
  192. function TextWidth(const Text: UnicodeString): Integer;
  193. function CharacterToTileIndex(aChar: WideChar): Integer; virtual;
  194. function TileIndexToChar(aIndex: Integer): WideChar; virtual;
  195. function CharacterCount: Integer; virtual;
  196. { Get the actual width for this char. }
  197. function GetCharWidth(Ch: WideChar): Integer;
  198. { Get the actual pixel width for this string. }
  199. function CalcStringWidth(const aText: UnicodeString): Integer;
  200. overload; virtual;
  201. // make texture if needed
  202. procedure CheckTexture(var ARci: TGLRenderContextInfo);
  203. { Height of a single character. }
  204. property CharHeight: Integer read FCharHeight write SetCharHeight
  205. default 16;
  206. property TextureWidth: Integer read FTextureWidth write FTextureWidth;
  207. property TextureHeight: Integer read FTextureHeight write FTextureHeight;
  208. end;
  209. { See TGLCustomBitmapFont.
  210. This class only publuishes some of the properties. }
  211. TGLBitmapFont = class(TGLCustomBitmapFont)
  212. published
  213. property Glyphs;
  214. property GlyphsIntervalX;
  215. property GlyphsIntervalY;
  216. property Ranges;
  217. property CharWidth;
  218. property CharHeight;
  219. property HSpace;
  220. property VSpace;
  221. property MagFilter;
  222. property MinFilter;
  223. property GlyphsAlpha;
  224. end;
  225. TGLFlatTextOption = (ftoTwoSided);
  226. TGLFlatTextOptions = set of TGLFlatTextOption;
  227. { A 2D text displayed and positionned in 3D coordinates.
  228. The FlatText uses a character font defined and stored by a TGLBitmapFont
  229. component. Default character scale is 1 font pixel = 1 space unit. }
  230. TGLFlatText = class(TGLImmaterialSceneObject)
  231. private
  232. FBitmapFont: TGLCustomBitmapFont;
  233. FText: UnicodeString;
  234. FAlignment: TAlignment;
  235. FLayout: TTextLayout;
  236. FModulateColor: TGLColor;
  237. FOptions: TGLFlatTextOptions;
  238. protected
  239. procedure SetBitmapFont(const val: TGLCustomBitmapFont);
  240. procedure SetText(const val: UnicodeString);
  241. procedure SetAlignment(const val: TAlignment);
  242. procedure SetLayout(const val: TTextLayout);
  243. procedure SetModulateColor(const val: TGLColor);
  244. procedure SetOptions(const val: TGLFlatTextOptions);
  245. procedure Notification(AComponent: TComponent;
  246. Operation: TOperation); override;
  247. public
  248. constructor Create(AOwner: TComponent); override;
  249. destructor Destroy; override;
  250. procedure DoRender(var rci: TGLRenderContextInfo;
  251. renderSelf, renderChildren: boolean); override;
  252. procedure Assign(Source: TPersistent); override;
  253. published
  254. { Refers the bitmap font to use.
  255. The referred bitmap font component stores and allows access to
  256. individual character bitmaps. }
  257. property BitmapFont: TGLCustomBitmapFont read FBitmapFont
  258. write SetBitmapFont;
  259. { Text to render.
  260. Be aware that only the characters available in the bitmap font will
  261. be rendered. CR LF sequences are allowed. }
  262. property Text: UnicodeString read FText write SetText;
  263. { Controls the text alignment (horizontal).
  264. Possible values : taLeftJustify, taRightJustify, taCenter }
  265. property Alignment: TAlignment read FAlignment write SetAlignment;
  266. { Controls the text layout (vertical).
  267. Possible values : tlTop, tlCenter, tlBottom }
  268. property Layout: TTextLayout read FLayout write SetLayout;
  269. { Color modulation, can be used for fade in/out too. }
  270. property ModulateColor: TGLColor read FModulateColor write SetModulateColor;
  271. { Flat text options.
  272. ftoTwoSided : when set the text will be visible from its two
  273. sides even if faceculling is on (at the scene-level).
  274. }
  275. property Options: TGLFlatTextOptions read FOptions write SetOptions;
  276. end;
  277. // ------------------------------------------------------------------
  278. implementation
  279. // ------------------------------------------------------------------
  280. // ------------------
  281. // ------------------ TGLBitmapFontRange ------------------
  282. // ------------------
  283. constructor TGLBitmapFontRange.Create(Collection: TCollection);
  284. begin
  285. inherited Create(Collection);
  286. end;
  287. destructor TGLBitmapFontRange.Destroy;
  288. begin
  289. inherited;
  290. end;
  291. procedure TGLBitmapFontRange.Assign(Source: TPersistent);
  292. begin
  293. if Source is TGLBitmapFontRange then
  294. begin
  295. FStartASCII := TGLBitmapFontRange(Source).FStartASCII;
  296. FStopASCII := TGLBitmapFontRange(Source).FStopASCII;
  297. FStartGlyphIdx := TGLBitmapFontRange(Source).FStartGlyphIdx;
  298. NotifyChange;
  299. end
  300. else
  301. inherited;
  302. end;
  303. procedure TGLBitmapFontRange.NotifyChange;
  304. begin
  305. FCharCount := Integer(FStopASCII) - Integer(FStartASCII) + 1;
  306. FStopGlyphIdx := FStartGlyphIdx + FCharCount - 1;
  307. if Assigned(Collection) then
  308. (Collection as TGLBitmapFontRanges).NotifyChange;
  309. end;
  310. function TGLBitmapFontRange.GetDisplayName: string;
  311. begin
  312. Result := Format('ASCII [#%d, #%d] -> Glyphs [%d, %d]',
  313. [Integer(FStartASCII), Integer(FStopASCII), StartGlyphIdx, StopGlyphIdx]);
  314. end;
  315. function TGLBitmapFontRange.GetStartASCII: WideString;
  316. begin
  317. Result := FStartASCII;
  318. end;
  319. function TGLBitmapFontRange.GetStopASCII: WideString;
  320. begin
  321. Result := FStopASCII;
  322. end;
  323. procedure TGLBitmapFontRange.SetStartASCII(const val: WideString);
  324. begin
  325. if (Length(val) > 0) and (val[1] <> FStartASCII) then
  326. begin
  327. FStartASCII := val[1];
  328. if FStartASCII > FStopASCII then
  329. FStopASCII := FStartASCII;
  330. NotifyChange;
  331. end;
  332. end;
  333. procedure TGLBitmapFontRange.SetStopASCII(const val: WideString);
  334. begin
  335. if (Length(val) > 0) and (FStopASCII <> val[1]) then
  336. begin
  337. FStopASCII := val[1];
  338. if FStopASCII < FStartASCII then
  339. FStartASCII := FStopASCII;
  340. NotifyChange;
  341. end;
  342. end;
  343. procedure TGLBitmapFontRange.SetStartGlyphIdx(val: Integer);
  344. begin
  345. val := MaxInteger(0, val);
  346. if val <> FStartGlyphIdx then
  347. begin
  348. FStartGlyphIdx := val;
  349. NotifyChange;
  350. end;
  351. end;
  352. // ------------------
  353. // ------------------ TGLBitmapFontRanges ------------------
  354. // ------------------
  355. constructor TGLBitmapFontRanges.Create(AOwner: TComponent);
  356. begin
  357. FOwner := AOwner;
  358. inherited Create(TGLBitmapFontRange);
  359. end;
  360. destructor TGLBitmapFontRanges.Destroy;
  361. begin
  362. inherited;
  363. end;
  364. function TGLBitmapFontRanges.GetOwner: TPersistent;
  365. begin
  366. Result := FOwner;
  367. end;
  368. procedure TGLBitmapFontRanges.SetItems(index: Integer;
  369. const val: TGLBitmapFontRange);
  370. begin
  371. inherited Items[index] := val;
  372. end;
  373. function TGLBitmapFontRanges.GetItems(index: Integer): TGLBitmapFontRange;
  374. begin
  375. Result := TGLBitmapFontRange(inherited Items[index]);
  376. end;
  377. function TGLBitmapFontRanges.Add: TGLBitmapFontRange;
  378. begin
  379. Result := (inherited Add) as TGLBitmapFontRange;
  380. end;
  381. function TGLBitmapFontRanges.Add(const StartASCII, StopASCII: WideChar)
  382. : TGLBitmapFontRange;
  383. begin
  384. Result := Add;
  385. Result.StartASCII := StartASCII;
  386. Result.StopASCII := StopASCII;
  387. end;
  388. function TGLBitmapFontRanges.Add(const StartASCII, StopASCII: AnsiChar)
  389. : TGLBitmapFontRange;
  390. begin
  391. Result := Add(CharToWideChar(StartASCII), CharToWideChar(StopASCII));
  392. end;
  393. function TGLBitmapFontRanges.FindItemID(ID: Integer): TGLBitmapFontRange;
  394. begin
  395. Result := (inherited FindItemID(ID)) as TGLBitmapFontRange;
  396. end;
  397. function TGLBitmapFontRanges.CharacterToTileIndex(aChar: WideChar): Integer;
  398. var
  399. i: Integer;
  400. begin
  401. Result := -1;
  402. for i := 0 to Count - 1 do
  403. with Items[i] do
  404. begin
  405. if (aChar >= FStartASCII) and (aChar <= FStopASCII) then
  406. begin
  407. Result := StartGlyphIdx + Integer(aChar) - Integer(FStartASCII);
  408. Break;
  409. end;
  410. end;
  411. end;
  412. function TGLBitmapFontRanges.TileIndexToChar(aIndex: Integer): WideChar;
  413. var
  414. i: Integer;
  415. begin
  416. Result := #0;
  417. for i := 0 to Count - 1 do
  418. with Items[i] do
  419. begin
  420. if (aIndex >= StartGlyphIdx) and (aIndex <= StopGlyphIdx) then
  421. begin
  422. Result := WideChar(aIndex - StartGlyphIdx + Integer(FStartASCII));
  423. Break;
  424. end;
  425. end;
  426. end;
  427. procedure TGLBitmapFontRanges.Update(Item: TCollectionItem);
  428. begin
  429. inherited;
  430. NotifyChange;
  431. end;
  432. procedure TGLBitmapFontRanges.NotifyChange;
  433. begin
  434. FCharCount := CalcCharacterCount;
  435. if Assigned(FOwner) then
  436. begin
  437. if FOwner is TGLBaseSceneObject then
  438. TGLBaseSceneObject(FOwner).StructureChanged
  439. else if FOwner is TGLCustomBitmapFont then
  440. TGLCustomBitmapFont(FOwner).NotifyChange(Self);
  441. end;
  442. end;
  443. function TGLBitmapFontRanges.CalcCharacterCount: Integer;
  444. var
  445. i: Integer;
  446. begin
  447. Result := 0;
  448. for i := 0 to Count - 1 do
  449. with Items[i] do
  450. Inc(Result, Integer(FStopASCII) - Integer(FStartASCII) + 1);
  451. end;
  452. // ------------------
  453. // ------------------ TGLCustomBitmapFont ------------------
  454. // ------------------
  455. constructor TGLCustomBitmapFont.Create(AOwner: TComponent);
  456. begin
  457. inherited Create(AOwner);
  458. FRanges := TGLBitmapFontRanges.Create(Self);
  459. FGlyphs := TPicture.Create;
  460. FGlyphs.OnChange := OnGlyphsChanged;
  461. FCharWidth := 16;
  462. FCharHeight := 16;
  463. FHSpace := 1;
  464. FVSpace := 1;
  465. FUsers := TList.Create;
  466. FMinFilter := miLinear;
  467. FMagFilter := maLinear;
  468. FTextures := TList.Create;
  469. FTextureModified := true;
  470. end;
  471. destructor TGLCustomBitmapFont.Destroy;
  472. begin
  473. FreeTextureHandle;
  474. inherited Destroy;
  475. FTextures.Free;
  476. FRanges.Free;
  477. FGlyphs.Free;
  478. Assert(FUsers.Count = 0);
  479. FUsers.Free;
  480. end;
  481. function TGLCustomBitmapFont.GetCharWidth(Ch: WideChar): Integer;
  482. var
  483. chi: Integer;
  484. begin
  485. chi := CharacterToTileIndex(ch);
  486. if Length(FChars) = 0 then
  487. ResetCharWidths;
  488. if chi >= 0 then
  489. Result := FChars[chi].w
  490. else
  491. Result := 0;
  492. end;
  493. function TGLCustomBitmapFont.CalcStringWidth(const aText
  494. : UnicodeString): Integer;
  495. var
  496. i: Integer;
  497. begin
  498. if aText <> '' then
  499. begin
  500. Result := -HSpace + Length(aText) * (HSpaceFix + HSpace);
  501. for i := 1 to Length(aText) do
  502. Result := Result + GetCharWidth(aText[i]);
  503. end
  504. else
  505. Result := 0;
  506. end;
  507. procedure TGLCustomBitmapFont.ResetCharWidths(w: Integer = -1);
  508. var
  509. i: Integer;
  510. begin
  511. FCharsLoaded := False;
  512. i := CharacterCount;
  513. if Length(FChars) < i then
  514. SetLength(FChars, i);
  515. if w < 0 then
  516. w := CharWidth;
  517. for i := 0 to High(FChars) do
  518. FChars[i].w := w;
  519. end;
  520. procedure TGLCustomBitmapFont.SetCharWidths(index, value: Integer);
  521. begin
  522. if index >= 0 then
  523. FChars[index].w := value;
  524. end;
  525. procedure TGLCustomBitmapFont.SetRanges(const val: TGLBitmapFontRanges);
  526. begin
  527. FRanges.Assign(val);
  528. InvalidateUsers;
  529. end;
  530. procedure TGLCustomBitmapFont.SetGlyphs(const val: TPicture);
  531. begin
  532. FGlyphs.Assign(val);
  533. end;
  534. procedure TGLCustomBitmapFont.SetCharWidth(const val: Integer);
  535. begin
  536. if val <> FCharWidth then
  537. begin
  538. if val > 1 then
  539. FCharWidth := val
  540. else
  541. FCharWidth := 1;
  542. InvalidateUsers;
  543. end;
  544. end;
  545. procedure TGLCustomBitmapFont.SetCharHeight(const val: Integer);
  546. begin
  547. if val <> FCharHeight then
  548. begin
  549. if val > 1 then
  550. FCharHeight := val
  551. else
  552. FCharHeight := 1;
  553. InvalidateUsers;
  554. end;
  555. end;
  556. procedure TGLCustomBitmapFont.SetGlyphsIntervalX(const val: Integer);
  557. begin
  558. if val > 0 then
  559. FGlyphsIntervalX := val
  560. else
  561. FGlyphsIntervalX := 0;
  562. InvalidateUsers;
  563. end;
  564. procedure TGLCustomBitmapFont.SetGlyphsIntervalY(const val: Integer);
  565. begin
  566. if val > 0 then
  567. FGlyphsIntervalY := val
  568. else
  569. FGlyphsIntervalY := 0;
  570. InvalidateUsers;
  571. end;
  572. procedure TGLCustomBitmapFont.SetHSpace(const val: Integer);
  573. begin
  574. if val <> FHSpace then
  575. begin
  576. FHSpace := val;
  577. InvalidateUsers;
  578. end;
  579. end;
  580. procedure TGLCustomBitmapFont.SetVSpace(const val: Integer);
  581. begin
  582. if val <> FVSpace then
  583. begin
  584. FVSpace := val;
  585. InvalidateUsers;
  586. end;
  587. end;
  588. procedure TGLCustomBitmapFont.SetMagFilter(AValue: TGLMagFilter);
  589. begin
  590. if AValue <> FMagFilter then
  591. begin
  592. FMagFilter := AValue;
  593. TextureChanged;
  594. InvalidateUsers;
  595. end;
  596. end;
  597. procedure TGLCustomBitmapFont.SetMinFilter(AValue: TGLMinFilter);
  598. begin
  599. if AValue <> FMinFilter then
  600. begin
  601. FMinFilter := AValue;
  602. TextureChanged;
  603. InvalidateUsers;
  604. end;
  605. end;
  606. procedure TGLCustomBitmapFont.SetGlyphsAlpha(val: TGLTextureImageAlpha);
  607. begin
  608. if val <> FGlyphsAlpha then
  609. begin
  610. FGlyphsAlpha := val;
  611. TextureChanged;
  612. InvalidateUsers;
  613. end;
  614. end;
  615. procedure TGLCustomBitmapFont.OnGlyphsChanged(Sender: TObject);
  616. begin
  617. InvalidateUsers;
  618. // when empty, width is 0 and roundup give 1
  619. if not Glyphs.Graphic.Empty then
  620. begin
  621. if FTextureWidth = 0 then
  622. FTextureWidth := RoundUpToPowerOf2(Glyphs.Width);
  623. if FTextureHeight = 0 then
  624. FTextureHeight := RoundUpToPowerOf2(Glyphs.Height);
  625. end;
  626. end;
  627. procedure TGLCustomBitmapFont.RegisterUser(anObject: TGLBaseSceneObject);
  628. begin
  629. Assert(FUsers.IndexOf(anObject) < 0);
  630. FUsers.Add(anObject);
  631. end;
  632. procedure TGLCustomBitmapFont.UnRegisterUser(anObject: TGLBaseSceneObject);
  633. begin
  634. FUsers.Remove(anObject);
  635. end;
  636. procedure TGLCustomBitmapFont.PrepareImage(var ARci: TGLRenderContextInfo);
  637. var
  638. bitmap: TBitmap;
  639. bitmap32: TGLImage;
  640. cap: Integer;
  641. X, Y, w, h: Integer;
  642. t: TGLTextureHandle;
  643. begin
  644. // only check when really used
  645. if FTextureWidth = 0 then
  646. begin
  647. FTextureWidth := ARci.GLStates.MaxTextureSize;
  648. if FTextureWidth > 512 then
  649. FTextureWidth := 512;
  650. if FTextureWidth < 64 then
  651. FTextureWidth := 64;
  652. end;
  653. if FTextureHeight = 0 then
  654. begin
  655. FTextureHeight := ARci.GLStates.MaxTextureSize;
  656. if FTextureHeight > 512 then
  657. FTextureHeight := 512;
  658. if FTextureHeight < 64 then
  659. FTextureHeight := 64;
  660. end;
  661. X := 0;
  662. Y := 0;
  663. w := Glyphs.Width;
  664. h := Glyphs.Height;
  665. // was an error...
  666. FTextRows := 1 + (h - 1) div FTextureHeight;
  667. FTextCols := 1 + (w - 1) div FTextureWidth;
  668. bitmap := TBitmap.Create;
  669. with bitmap do
  670. begin
  671. {$IFDEF MSWINDOWS}
  672. // due to lazarus doesn't properly support pixel formats
  673. PixelFormat := pf32bit;
  674. {$ENDIF}
  675. SetSize(RoundUpToPowerOf2(FTextureWidth),
  676. RoundUpToPowerOf2(FTextureHeight));
  677. end;
  678. bitmap32 := TGLImage.Create;
  679. while (X < w) and (Y < h) do
  680. begin
  681. t := TGLTextureHandle.Create;
  682. FTextures.Add(t);
  683. // prepare handle
  684. t.AllocateHandle;
  685. // texture registration
  686. t.Target := ttTexture2D;
  687. ARci.GLStates.TextureBinding[0, ttTexture2D] := t.Handle;
  688. // copy data
  689. bitmap.Canvas.Draw(-X, -Y, Glyphs.Graphic);
  690. // Clipboard.Assign(bitmap);
  691. bitmap32.Assign(bitmap);
  692. bitmap32.Narrow;
  693. with bitmap32 do
  694. begin
  695. case FGlyphsAlpha of
  696. tiaAlphaFromIntensity:
  697. SetAlphaFromIntensity;
  698. tiaSuperBlackTransparent:
  699. SetAlphaTransparentForColor($000000);
  700. tiaLuminance:
  701. SetAlphaFromIntensity;
  702. tiaLuminanceSqrt:
  703. begin
  704. SetAlphaFromIntensity;
  705. SqrtAlpha;
  706. end;
  707. tiaOpaque:
  708. SetAlphaToValue(255);
  709. tiaDefault, tiaTopLeftPointColorTransparent:
  710. SetAlphaTransparentForColor(Data[Width * (Height - 1)]);
  711. else
  712. Assert(False);
  713. end;
  714. RegisterAsOpenGLTexture(t, not(FMinFilter in [miNearest, miLinear]),
  715. TextureFormat, cap, cap, cap);
  716. end;
  717. PrepareParams(ARci);
  718. t.NotifyDataUpdated;
  719. Inc(X, FTextureWidth);
  720. if X >= w then
  721. begin
  722. Inc(Y, FTextureHeight);
  723. X := 0;
  724. end;
  725. end;
  726. bitmap.Free;
  727. bitmap32.Free;
  728. end;
  729. procedure TGLCustomBitmapFont.PrepareParams(var ARci: TGLRenderContextInfo);
  730. const
  731. cTextureMagFilter: array [maNearest .. maLinear] of Cardinal = (GL_NEAREST, GL_LINEAR);
  732. cTextureMinFilter: array [miNearest .. miLinearMipmapLinear] of Cardinal =
  733. (GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
  734. GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR);
  735. begin
  736. with ARci.GLStates do
  737. begin
  738. UnpackAlignment := 4;
  739. UnpackRowLength := 0;
  740. UnpackSkipRows := 0;
  741. UnpackSkipPixels := 0;
  742. end;
  743. begin
  744. gl.Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  745. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  746. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  747. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, cTextureMinFilter[FMinFilter]);
  748. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, cTextureMagFilter[FMagFilter]);
  749. end;
  750. end;
  751. function TGLCustomBitmapFont.TileIndexToChar(aIndex: Integer): WideChar;
  752. begin
  753. Result := FRanges.TileIndexToChar(aIndex);
  754. end;
  755. function TGLCustomBitmapFont.CharacterToTileIndex(aChar: WideChar): Integer;
  756. begin
  757. Result := FRanges.CharacterToTileIndex(aChar);
  758. end;
  759. procedure TGLCustomBitmapFont.RenderString(var ARci: TGLRenderContextInfo;
  760. const aText: UnicodeString; aAlignment: TAlignment; aLayout: TTextLayout;
  761. const aColor: TColorVector; aPosition: PVector = nil;
  762. aReverseY: boolean = False);
  763. function AlignmentAdjustement(p: Integer): Single;
  764. var
  765. i: Integer;
  766. begin
  767. i := 0;
  768. while (p <= Length(aText)) and (aText[p] <> #13) do
  769. begin
  770. Inc(p);
  771. Inc(i);
  772. end;
  773. case aAlignment of
  774. taLeftJustify:
  775. Result := 0;
  776. taRightJustify:
  777. Result := -CalcStringWidth(Copy(aText, p - i, i))
  778. else // taCenter
  779. Result := Round(-CalcStringWidth(Copy(aText, p - i, i)) * 0.5);
  780. end;
  781. end;
  782. function LayoutAdjustement: Single;
  783. var
  784. i, n: Integer;
  785. begin
  786. n := 1;
  787. for i := 1 to Length(aText) do
  788. if aText[i] = #13 then
  789. Inc(n);
  790. case TTextLayout(aLayout) of
  791. tlTop: Result := 0;
  792. tlBottom: Result := (n * (CharHeight + VSpace) - VSpace);
  793. else // tlCenter
  794. Result := Round((n * (CharHeight + VSpace) - VSpace) * 0.5);
  795. end;
  796. end;
  797. var
  798. i, chi: Integer;
  799. pch: PCharInfo;
  800. TopLeft, BottomRight: TTexPoint;
  801. vTopLeft, vBottomRight: TVector;
  802. deltaV, spaceDeltaH: Single;
  803. currentChar: WideChar;
  804. begin
  805. if (aText = '') then
  806. Exit;
  807. // prepare texture if necessary
  808. CheckTexture(ARci);
  809. // precalcs
  810. if Assigned(aPosition) then
  811. MakePoint(vTopLeft, aPosition.X + AlignmentAdjustement(1),
  812. aPosition.Y + LayoutAdjustement, 0)
  813. else
  814. MakePoint(vTopLeft, AlignmentAdjustement(1), LayoutAdjustement, 0);
  815. deltaV := -(CharHeight + VSpace);
  816. if aReverseY then
  817. vBottomRight.Y := vTopLeft.Y + CharHeight
  818. else
  819. vBottomRight.Y := vTopLeft.Y - CharHeight;
  820. vBottomRight.Z := 0;
  821. vBottomRight.W := 1;
  822. spaceDeltaH := GetCharWidth(#32) + HSpaceFix + HSpace;
  823. // set states
  824. with ARci.GLStates do
  825. begin
  826. ActiveTextureEnabled[ttTexture2D] := true;
  827. Disable(stLighting);
  828. Enable(stBlend);
  829. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  830. FLastTexture := nil;
  831. end;
  832. // start rendering
  833. gl.Color4fv(@aColor);
  834. gl.Begin_(GL_QUADS);
  835. for i := 1 to Length(aText) do
  836. begin
  837. currentChar := WideChar(aText[i]);
  838. case currentChar of
  839. #0 .. #12, #14 .. #31:
  840. ; // ignore
  841. #13:
  842. begin
  843. if Assigned(aPosition) then
  844. vTopLeft.X := aPosition.X + AlignmentAdjustement(i + 1)
  845. else
  846. vTopLeft.X := AlignmentAdjustement(i + 1);
  847. vTopLeft.Y := vTopLeft.Y + deltaV;
  848. if aReverseY then
  849. vBottomRight.Y := vTopLeft.Y + CharHeight
  850. else
  851. vBottomRight.Y := vTopLeft.Y - CharHeight;
  852. end;
  853. #32:
  854. vTopLeft.X := vTopLeft.X + spaceDeltaH;
  855. else
  856. chi := CharacterToTileIndex(currentChar);
  857. if chi < 0 then
  858. continue; // not found
  859. pch := @FChars[chi];
  860. if pch.w > 0 then
  861. begin
  862. GetICharTexCoords(ARci, chi, TopLeft, BottomRight);
  863. vBottomRight.X := vTopLeft.X + pch.w;
  864. gl.TexCoord2fv(@TopLeft);
  865. gl.Vertex4fv(@vTopLeft);
  866. gl.TexCoord2f(TopLeft.S, BottomRight.t);
  867. gl.Vertex2f(vTopLeft.X, vBottomRight.Y);
  868. gl.TexCoord2fv(@BottomRight);
  869. gl.Vertex4fv(@vBottomRight);
  870. gl.TexCoord2f(BottomRight.S, TopLeft.t);
  871. gl.Vertex2f(vBottomRight.X, vTopLeft.Y);
  872. vTopLeft.X := vTopLeft.X + pch.w + HSpace;
  873. end;
  874. end;
  875. end;
  876. gl.End_;
  877. // unbind texture
  878. ARci.GLStates.TextureBinding[0, ttTexture2D] := 0;
  879. ARci.GLStates.ActiveTextureEnabled[ttTexture2D] := False;
  880. end;
  881. procedure TGLCustomBitmapFont.TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
  882. const Text: UnicodeString; const Color: TColorVector);
  883. var
  884. V: TVector;
  885. begin
  886. V.X := X;
  887. V.Y := Y;
  888. V.Z := 0;
  889. V.W := 1;
  890. RenderString(rci, Text, taLeftJustify, tlTop, Color, @V, true);
  891. end;
  892. procedure TGLCustomBitmapFont.TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
  893. const Text: UnicodeString; const Color: TColor);
  894. begin
  895. TextOut(rci, X, Y, Text, ConvertWinColor(Color));
  896. end;
  897. function TGLCustomBitmapFont.TextWidth(const Text: UnicodeString): Integer;
  898. begin
  899. Result := CalcStringWidth(Text);
  900. end;
  901. function TGLCustomBitmapFont.CharactersPerRow: Integer;
  902. begin
  903. if FGlyphs.Width > 0 then
  904. Result := (FGlyphs.Width + FGlyphsIntervalX)
  905. div (FGlyphsIntervalX + FCharWidth)
  906. else
  907. Result := 0;
  908. end;
  909. function TGLCustomBitmapFont.CharacterCount: Integer;
  910. begin
  911. Result := FRanges.CharacterCount;
  912. end;
  913. procedure TGLCustomBitmapFont.GetCharTexCoords(Ch: WideChar;
  914. var TopLeft, BottomRight: TTexPoint);
  915. var
  916. chi, tileIndex: Integer;
  917. ci: TCharInfo;
  918. r: Integer;
  919. begin
  920. chi := CharacterToTileIndex(ch);
  921. if not FCharsLoaded then
  922. begin
  923. ResetCharWidths;
  924. FCharsLoaded := true;
  925. r := CharactersPerRow;
  926. for tileIndex := 0 to CharacterCount - 1 do
  927. begin
  928. FChars[tileIndex].l := (tileIndex mod r) * (CharWidth + GlyphsIntervalX);
  929. FChars[tileIndex].t := (tileIndex div r) * (CharHeight + GlyphsIntervalY);
  930. end;
  931. end;
  932. if (chi < 0) or (chi >= CharacterCount) then
  933. begin
  934. // invalid char
  935. TopLeft := NullTexPoint;
  936. BottomRight := NullTexPoint;
  937. Exit;
  938. end;
  939. ci := FChars[chi];
  940. ci.l := ci.l mod FTextureWidth;
  941. ci.t := ci.t mod FTextureHeight;
  942. TopLeft.S := ci.l / FTextureWidth;
  943. TopLeft.t := 1 - ci.t / FTextureHeight;
  944. BottomRight.S := (ci.l + ci.w) / FTextureWidth;
  945. BottomRight.t := 1 - (ci.t + CharHeight) / FTextureHeight;
  946. end;
  947. // TileIndexToTexCoords it also activates the target texture
  948. procedure TGLCustomBitmapFont.GetICharTexCoords(var ARci: TGLRenderContextInfo;
  949. Chi: Integer; out TopLeft, BottomRight: TTexPoint);
  950. var
  951. tileIndex: Integer;
  952. ci: TCharInfo;
  953. t: TGLTextureHandle;
  954. r, c: Integer;
  955. begin
  956. if not FCharsLoaded then
  957. begin
  958. r := CharactersPerRow;
  959. if r = 0 then
  960. Exit;
  961. ResetCharWidths;
  962. FCharsLoaded := true;
  963. for tileIndex := 0 to CharacterCount - 1 do
  964. begin
  965. FChars[tileIndex].l := (tileIndex mod r) * (CharWidth + GlyphsIntervalX);
  966. FChars[tileIndex].t := (tileIndex div r) * (CharHeight + GlyphsIntervalY);
  967. end;
  968. end;
  969. if (chi < 0) or (chi >= CharacterCount) then
  970. begin
  971. // invalid char
  972. TopLeft := NullTexPoint;
  973. BottomRight := NullTexPoint;
  974. Exit;
  975. end;
  976. ci := FChars[chi];
  977. c := ci.l div FTextureWidth;
  978. r := ci.t div FTextureHeight;
  979. ci.l := ci.l mod FTextureWidth;
  980. ci.t := ci.t mod FTextureHeight;
  981. t := FTextures[r * FTextCols + c];
  982. TopLeft.S := ci.l / FTextureWidth;
  983. TopLeft.t := 1 - ci.t / FTextureHeight;
  984. BottomRight.S := (ci.l + ci.w) / FTextureWidth;
  985. BottomRight.t := 1 - (ci.t + CharHeight) / FTextureHeight;
  986. if t <> FLastTexture then
  987. begin
  988. FLastTexture := t;
  989. gl.End_;
  990. ARci.GLStates.TextureBinding[0, ttTexture2D] := t.Handle;
  991. gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  992. gl.Begin_(GL_QUADS);
  993. end;
  994. end;
  995. procedure TGLCustomBitmapFont.InvalidateUsers;
  996. var
  997. i: Integer;
  998. begin
  999. FCharsLoaded := False;
  1000. FTextureModified := true;
  1001. for i := FUsers.Count - 1 downto 0 do
  1002. TGLBaseSceneObject(FUsers[i]).NotifyChange(Self);
  1003. end;
  1004. procedure TGLCustomBitmapFont.FreeTextureHandle;
  1005. var
  1006. i: Integer;
  1007. begin
  1008. FTextureModified := true;
  1009. for i := 0 to FTextures.Count - 1 do
  1010. TObject(FTextures[i]).Free;
  1011. FTextures.Clear;
  1012. end;
  1013. procedure TGLCustomBitmapFont.TextureChanged;
  1014. begin
  1015. FTextureModified := true;
  1016. end;
  1017. // force texture when needed
  1018. procedure TGLCustomBitmapFont.CheckTexture(var ARci: TGLRenderContextInfo);
  1019. var
  1020. i: Integer;
  1021. begin
  1022. // important: IsDataNeedUpdate might come from another source!
  1023. for i := 0 to FTextures.Count - 1 do
  1024. FTextureModified := FTextureModified or TGLTextureHandle(FTextures[i])
  1025. .IsDataNeedUpdate;
  1026. if FTextureModified then
  1027. begin
  1028. FreeTextureHandle; // instances are recreated in prepare
  1029. PrepareImage(ARci);
  1030. FTextureModified := False;
  1031. end;
  1032. end;
  1033. function TGLCustomBitmapFont.TextureFormat: Integer;
  1034. begin
  1035. Result := GL_RGBA;
  1036. end;
  1037. // ------------------
  1038. // ------------------ TGLFlatText ------------------
  1039. // ------------------
  1040. constructor TGLFlatText.Create(AOwner: TComponent);
  1041. begin
  1042. inherited;
  1043. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  1044. FModulateColor := TGLColor.CreateInitialized(Self, clrWhite);
  1045. end;
  1046. destructor TGLFlatText.Destroy;
  1047. begin
  1048. FModulateColor.Free;
  1049. BitmapFont := nil;
  1050. inherited;
  1051. end;
  1052. procedure TGLFlatText.Notification(AComponent: TComponent;
  1053. Operation: TOperation);
  1054. begin
  1055. if (Operation = opRemove) and (AComponent = FBitmapFont) then
  1056. BitmapFont := nil;
  1057. inherited;
  1058. end;
  1059. procedure TGLFlatText.SetBitmapFont(const val: TGLCustomBitmapFont);
  1060. begin
  1061. if val <> FBitmapFont then
  1062. begin
  1063. if Assigned(FBitmapFont) then
  1064. FBitmapFont.UnRegisterUser(Self);
  1065. FBitmapFont := val;
  1066. if Assigned(FBitmapFont) then
  1067. begin
  1068. FBitmapFont.RegisterUser(Self);
  1069. FBitmapFont.FreeNotification(Self);
  1070. end;
  1071. StructureChanged;
  1072. end;
  1073. end;
  1074. procedure TGLFlatText.SetText(const val: UnicodeString);
  1075. begin
  1076. FText := val;
  1077. StructureChanged;
  1078. end;
  1079. procedure TGLFlatText.SetAlignment(const val: TAlignment);
  1080. begin
  1081. FAlignment := val;
  1082. StructureChanged;
  1083. end;
  1084. procedure TGLFlatText.SetLayout(const val: TTextLayout);
  1085. begin
  1086. FLayout := val;
  1087. StructureChanged;
  1088. end;
  1089. procedure TGLFlatText.SetModulateColor(const val: TGLColor);
  1090. begin
  1091. FModulateColor.Assign(val);
  1092. end;
  1093. procedure TGLFlatText.SetOptions(const val: TGLFlatTextOptions);
  1094. begin
  1095. if val <> FOptions then
  1096. begin
  1097. FOptions := val;
  1098. StructureChanged;
  1099. end;
  1100. end;
  1101. procedure TGLFlatText.DoRender(var rci: TGLRenderContextInfo;
  1102. renderSelf, renderChildren: boolean);
  1103. begin
  1104. if Assigned(FBitmapFont) and (Text <> '') then
  1105. begin
  1106. rci.GLStates.PolygonMode := pmFill;
  1107. if FModulateColor.Alpha <> 1 then
  1108. begin
  1109. rci.GLStates.Enable(stBlend);
  1110. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  1111. end;
  1112. if ftoTwoSided in FOptions then
  1113. rci.GLStates.Disable(stCullFace);
  1114. FBitmapFont.RenderString(rci, Text, FAlignment, FLayout,
  1115. FModulateColor.Color);
  1116. end;
  1117. if Count > 0 then
  1118. Self.renderChildren(0, Count - 1, rci);
  1119. end;
  1120. procedure TGLFlatText.Assign(Source: TPersistent);
  1121. begin
  1122. if Assigned(Source) and (Source is TGLFlatText) then
  1123. begin
  1124. BitmapFont := TGLFlatText(Source).BitmapFont;
  1125. Text := TGLFlatText(Source).Text;
  1126. Alignment := TGLFlatText(Source).Alignment;
  1127. Layout := TGLFlatText(Source).Layout;
  1128. ModulateColor := TGLFlatText(Source).ModulateColor;
  1129. Options := TGLFlatText(Source).Options;
  1130. end;
  1131. inherited Assign(Source);
  1132. end;
  1133. // ------------------------------------------------------------------
  1134. initialization
  1135. // ------------------------------------------------------------------
  1136. RegisterClasses([TGLBitmapFont, TGLFlatText]);
  1137. end.