GLBitmapFont.pas 36 KB

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