GLS.BitmapFont.pas 35 KB

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