GXS.BitmapFont.pas 35 KB

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