2
0

GXS.SpaceText.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.SpaceText;
  5. (*
  6. 3D Text component.
  7. Note: You can get valid extents (including AABB's) of this component only
  8. after it has been rendered for the first time. It means if you ask its
  9. extents during / after its creation, you will get zeros.
  10. Also extents are valid only when SpaceText has one line.
  11. *)
  12. interface
  13. {$I Stage.Defines.inc}
  14. uses
  15. Winapi.OpenGL,
  16. Winapi.Windows,
  17. WinApi.Messages,
  18. System.Classes,
  19. System.UITypes,
  20. System.SysUtils,
  21. FMX.Graphics,
  22. Stage.VectorGeometry,
  23. Stage.Strings,
  24. Stage.VectorTypes,
  25. GXS.Scene,
  26. GXS.Texture,
  27. GXS.Context,
  28. GXS.RenderContextInfo,
  29. GXS.State;
  30. type
  31. TgxSpaceTextCharRange = (stcrDefault, stcrAlphaNum, stcrNumbers, stcrWide);
  32. // Note: haAligned, haCentrically, haFitIn have not been implemented!
  33. TgxTextHorzAdjust = (haLeft, haCenter, haRight, haAligned,
  34. haCentrically, haFitIn);
  35. TgxTextVertAdjust = (vaTop, vaCenter, vaBottom, vaBaseLine);
  36. TgxTextAdjust = class(TPersistent)
  37. private
  38. FHorz: TgxTextHorzAdjust;
  39. FVert: TgxTextVertAdjust;
  40. FOnChange: TNotifyEvent;
  41. procedure SetHorz(const Value: TgxTextHorzAdjust);
  42. procedure SetVert(const Value: TgxTextVertAdjust);
  43. public
  44. constructor Create;
  45. procedure Assign(Source: TPersistent); override;
  46. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  47. published
  48. property Horz: TgxTextHorzAdjust read FHorz write SetHorz default haLeft;
  49. property Vert: TgxTextVertAdjust read FVert write SetVert default vaBaseLine;
  50. end;
  51. // Holds an entry in the font manager list (used in TgxSpaceText)
  52. PFontEntry = ^TFontEntry;
  53. TFontEntry = record
  54. Name: string;
  55. FVirtualHandle: TgxVirtualHandleTransf;
  56. Styles: TFontStyles;
  57. Extrusion: Single;
  58. RefCount: Integer;
  59. allowedDeviation: Single;
  60. firstChar, lastChar: Integer;
  61. glyphMetrics: array of TGlyphMetricsFloat;
  62. FClients: TList;
  63. end;
  64. // Renders a text in 3D.
  65. TgxSpaceText = class(TgxSceneObject)
  66. private
  67. FFont: TFont;
  68. FExtrusion: Single;
  69. FAllowedDeviation: Single;
  70. FCharacterRange: TgxSpaceTextCharRange;
  71. FAdjust: TgxTextAdjust;
  72. FAspectRatio: Single;
  73. FOblique: Single;
  74. FTextHeight: Single;
  75. FLines: TStringList;
  76. procedure SetCharacterRange(const val: TgxSpaceTextCharRange);
  77. procedure SetAllowedDeviation(const val: Single);
  78. procedure SetExtrusion(AValue: Single);
  79. procedure SetFont(AFont: TFont);
  80. function GetText: WideString;
  81. procedure SetLines(const Value: TStringList);
  82. procedure SetText(const AText: WideString);
  83. procedure SetAdjust(const Value: TgxTextAdjust);
  84. procedure SetAspectRatio(const Value: Single);
  85. procedure SetOblique(const Value: Single);
  86. procedure SetTextHeight(const Value: Single);
  87. protected
  88. FTextFontEntry: PFontEntry;
  89. FontChanged: Boolean;
  90. procedure DestroyHandle; override;
  91. procedure OnFontChange(sender: TObject);
  92. procedure GetFirstAndLastChar(var firstChar, lastChar: Integer);
  93. procedure DoOnLinesChange(sender: TObject); virtual;
  94. public
  95. constructor Create(AOwner: TComponent); override;
  96. destructor Destroy; override;
  97. procedure Assign(Source: TPersistent); override;
  98. procedure BuildList(var rci: TgxRenderContextInfo); override;
  99. procedure DoRender(var ARci: TgxRenderContextInfo;
  100. ARenderSelf, ARenderChildren: Boolean); override;
  101. function TextWidth(const str: WideString = ''): Single;
  102. function TextMaxHeight(const str: WideString = ''): Single;
  103. function TextMaxUnder(const str: WideString = ''): Single;
  104. (* Note: this fuction is valid only after text has been rendered
  105. the first time. Before that it returns zeros. *)
  106. procedure TextMetrics(const str: WideString; out width, maxHeight, maxUnder: Single);
  107. procedure NotifyFontChanged;
  108. procedure NotifyChange(sender: TObject); override;
  109. procedure DefaultHandler(var Message); override;
  110. function AxisAlignedDimensionsUnscaled: TVector4f; override;
  111. function BarycenterAbsolutePosition: TVector4f; override;
  112. published
  113. (* Adjusts the 3D font extrusion.
  114. If Extrusion=0, the characters will be flat (2D), values >0 will
  115. give them a third dimension. *)
  116. property Extrusion: Single read FExtrusion write SetExtrusion;
  117. property Font: TFont read FFont write SetFont;
  118. property Text: WideString read GetText write SetText stored False;
  119. property Lines: TStringList read FLines write SetLines;
  120. // Quality related, see Win32 help for wglUseFontOutlines
  121. property allowedDeviation: Single read FAllowedDeviation write SetAllowedDeviation;
  122. // Character range to convert. Converting less characters saves time and memory...
  123. property CharacterRange: TgxSpaceTextCharRange read FCharacterRange
  124. write SetCharacterRange default stcrDefault;
  125. property AspectRatio: Single read FAspectRatio write SetAspectRatio;
  126. property TextHeight: Single read FTextHeight write SetTextHeight;
  127. property Oblique: Single read FOblique write SetOblique;
  128. property Adjust: TgxTextAdjust read FAdjust write SetAdjust;
  129. end;
  130. // Manages a list of fonts for which display lists were created.
  131. TFontManager = class(TList)
  132. private
  133. FCurrentBase: Integer;
  134. protected
  135. procedure NotifyClients(Clients: TList);
  136. procedure VirtualHandleAlloc(sender: TgxVirtualHandle; var handle: Cardinal);
  137. procedure VirtualHandleDestroy(sender: TgxVirtualHandle; var handle: Cardinal);
  138. public
  139. constructor Create;
  140. destructor Destroy; override;
  141. function FindFont(AName: string; FStyles: TFontStyles; FExtrusion: Single;
  142. FAllowedDeviation: Single; FFirstChar, FLastChar: Integer): PFontEntry;
  143. function GetFontBase(AName: string; FStyles: TFontStyles; FExtrusion: Single;
  144. allowedDeviation: Single; firstChar, lastChar: Integer; client: TObject): PFontEntry;
  145. procedure Release(entry: PFontEntry; client: TObject);
  146. end;
  147. function FontManager: TFontManager;
  148. procedure ReleaseFontManager;
  149. var
  150. vFontManagerMsgID: Cardinal;
  151. // ------------------------------------------------------------------
  152. implementation
  153. // ------------------------------------------------------------------
  154. const
  155. cFontManagerMsg = 'Scene FontManagerMessage';
  156. var
  157. vFontManager: TFontManager;
  158. function FontManager: TFontManager;
  159. begin
  160. if not Assigned(vFontManager) then
  161. vFontManager := TFontManager.Create;
  162. Result := vFontManager;
  163. end;
  164. procedure ReleaseFontManager;
  165. begin
  166. if Assigned(vFontManager) then
  167. begin
  168. vFontManager.Free;
  169. vFontManager := nil;
  170. end;
  171. end;
  172. // ------------------
  173. // ------------------ TgxTextAdjust ------------------
  174. // ------------------
  175. constructor TgxTextAdjust.Create;
  176. begin
  177. inherited;
  178. FHorz := haLeft;
  179. FVert := vaBaseLine;
  180. end;
  181. procedure TgxTextAdjust.Assign(Source: TPersistent);
  182. begin
  183. if Source is TgxTextAdjust then
  184. begin
  185. FHorz := TgxTextAdjust(Source).Horz;
  186. FVert := TgxTextAdjust(Source).Vert;
  187. if Assigned(FOnChange) then
  188. FOnChange(Self);
  189. end
  190. else
  191. inherited Assign(Source);
  192. end;
  193. procedure TgxTextAdjust.SetHorz(const Value: TgxTextHorzAdjust);
  194. begin
  195. if FHorz <> Value then
  196. begin
  197. FHorz := Value;
  198. if Assigned(FOnChange) then
  199. FOnChange(Self);
  200. end;
  201. end;
  202. procedure TgxTextAdjust.SetVert(const Value: TgxTextVertAdjust);
  203. begin
  204. if Value <> FVert then
  205. begin
  206. FVert := Value;
  207. if Assigned(FOnChange) then
  208. FOnChange(Self);
  209. end;
  210. end;
  211. // ------------------
  212. // ------------------ TgxSpaceText ------------------
  213. // ------------------
  214. constructor TgxSpaceText.Create(AOwner: TComponent);
  215. begin
  216. inherited Create(AOwner);
  217. FFont := TFont.Create;
  218. FFont.Family := 'Arial'; //in VCL FFont.Name
  219. FontChanged := True;
  220. CharacterRange := stcrDefault;
  221. FFont.OnChanged := OnFontChange;
  222. FAdjust := TgxTextAdjust.Create;
  223. FAdjust.OnChange := OnFontChange;
  224. FLines := TStringList.Create;
  225. FLines.OnChange := DoOnLinesChange;
  226. end;
  227. destructor TgxSpaceText.Destroy;
  228. begin
  229. FAdjust.OnChange := nil;
  230. FAdjust.Free;
  231. FFont.OnChanged := nil;
  232. FFont.Free;
  233. FLines.Free;
  234. FontManager.Release(FTextFontEntry, Self);
  235. inherited Destroy;
  236. end;
  237. procedure TgxSpaceText.TextMetrics(const str: WideString;
  238. out width, maxHeight, maxUnder: Single);
  239. var
  240. i, firstChar, lastChar, diff: Integer;
  241. buf: WideString;
  242. gmf: TGlyphMetricsFloat;
  243. begin
  244. width := 0;
  245. maxUnder := 0;
  246. maxHeight := 0;
  247. if Assigned(FTextFontEntry) then
  248. begin
  249. GetFirstAndLastChar(firstChar, lastChar);
  250. if str = '' then
  251. buf := GetText
  252. else
  253. buf := str;
  254. for i := 1 to Length(buf) do
  255. begin
  256. diff := Integer(buf[i]) - firstChar;
  257. if diff > High(FTextFontEntry^.glyphMetrics) then
  258. continue;
  259. gmf := FTextFontEntry^.glyphMetrics[diff];
  260. width := width + gmf.gmfCellIncX;
  261. if gmf.gmfptGlyphOrigin.y > maxHeight then
  262. maxHeight := gmf.gmfptGlyphOrigin.y;
  263. if gmf.gmfptGlyphOrigin.y - gmf.gmfBlackBoxY < maxUnder then
  264. maxUnder := gmf.gmfptGlyphOrigin.y - gmf.gmfBlackBoxY;
  265. end;
  266. end;
  267. end;
  268. function TgxSpaceText.TextWidth(const str: WideString = ''): Single;
  269. var
  270. mh, mu: Single;
  271. begin
  272. TextMetrics(str, Result, mh, mu);
  273. end;
  274. function TgxSpaceText.TextMaxHeight(const str: WideString = ''): Single;
  275. var
  276. w, mu: Single;
  277. begin
  278. TextMetrics(str, w, Result, mu);
  279. end;
  280. function TgxSpaceText.TextMaxUnder(const str: WideString = ''): Single;
  281. var
  282. w, mh: Single;
  283. begin
  284. TextMetrics(str, w, mh, Result);
  285. end;
  286. procedure TgxSpaceText.Assign(Source: TPersistent);
  287. begin
  288. inherited Assign(Source);
  289. if Source is TgxSpaceText then
  290. begin
  291. FAdjust.Assign(TgxSpaceText(Source).FAdjust);
  292. FFont.Assign(TgxSpaceText(Source).FFont);
  293. FAllowedDeviation := TgxSpaceText(Source).allowedDeviation;
  294. FAspectRatio := TgxSpaceText(Source).FAspectRatio;
  295. FCharacterRange := TgxSpaceText(Source).CharacterRange;
  296. FExtrusion := TgxSpaceText(Source).FExtrusion;
  297. FOblique := TgxSpaceText(Source).FOblique;
  298. FLines.Text := TgxSpaceText(Source).FLines.Text;
  299. FTextHeight := TgxSpaceText(Source).FTextHeight;
  300. StructureChanged;
  301. end;
  302. end;
  303. procedure TgxSpaceText.BuildList(var rci: TgxRenderContextInfo);
  304. var
  305. textL, maxUnder, maxHeight: Single;
  306. charScale: Single;
  307. i, j, k, c: Integer;
  308. glBase: GLuint;
  309. dirtyLine, cleanLine: WideString;
  310. begin
  311. if Length(GetText) > 0 then
  312. begin
  313. glPushMatrix;
  314. // FAspectRatio ignore
  315. if FAspectRatio <> 0 then
  316. glScalef(FAspectRatio, 1, 1);
  317. if FOblique <> 0 then
  318. glRotatef(FOblique, 0, 0, 1);
  319. glBase := FTextFontEntry^.FVirtualHandle.handle;
  320. case FCharacterRange of
  321. stcrAlphaNum:
  322. glListBase(GLuint(Integer(glBase) - 32));
  323. stcrNumbers:
  324. glListBase(GLuint(Integer(glBase) - Integer('0')));
  325. else
  326. glListBase(glBase);
  327. end;
  328. glPushAttrib(GL_POLYGON_BIT);
  329. for i := 0 to FLines.Count - 1 do
  330. begin
  331. glPushMatrix;
  332. TextMetrics(FLines.Strings[i], textL, maxHeight, maxUnder);
  333. if (FAdjust.Horz <> haLeft) or (FAdjust.Vert <> vaBaseLine) or
  334. (FTextHeight <> 0) then
  335. begin
  336. if FTextHeight <> 0 then
  337. begin
  338. charScale := FTextHeight / maxHeight;
  339. glScalef(charScale, charScale, 1);
  340. end;
  341. case FAdjust.Horz of
  342. haLeft:
  343. ; // nothing
  344. haCenter:
  345. glTranslatef(-textL * 0.5, 0, 0);
  346. haRight:
  347. glTranslatef(-textL, 0, 0);
  348. end;
  349. case FAdjust.Vert of
  350. vaBaseLine:
  351. ; // nothing;
  352. vaBottom:
  353. glTranslatef(0, abs(maxUnder), 0);
  354. vaCenter:
  355. glTranslatef(0, abs(maxUnder) * 0.5 - maxHeight * 0.5, 0);
  356. vaTop:
  357. glTranslatef(0, -maxHeight, 0);
  358. end;
  359. end;
  360. glTranslatef(0, -i * (maxHeight + FAspectRatio), 0);
  361. if FCharacterRange = stcrWide then
  362. begin
  363. dirtyLine := FLines.Strings[i];
  364. SetLength(cleanLine, Length(dirtyLine));
  365. k := 1;
  366. for j := 1 to Length(dirtyLine) do
  367. begin
  368. c := Integer(dirtyLine[j]);
  369. if (c >= FTextFontEntry^.firstChar) and
  370. (c <= FTextFontEntry^.lastChar) then
  371. begin
  372. cleanLine[k] := dirtyLine[j];
  373. Inc(k);
  374. end;
  375. end;
  376. if k > 1 then
  377. glCallLists(k - 1, GL_UNSIGNED_SHORT, PWideChar(cleanLine))
  378. end
  379. else
  380. glCallLists(Length(FLines.Strings[i]), GL_UNSIGNED_BYTE,
  381. PChar(String(FLines.Strings[i])));
  382. glPopMatrix;
  383. end;
  384. rci.gxStates.PopAttrib();
  385. glPopMatrix;
  386. end;
  387. end;
  388. procedure TgxSpaceText.DestroyHandle;
  389. begin
  390. FontChanged := True;
  391. inherited;
  392. end;
  393. procedure TgxSpaceText.GetFirstAndLastChar(var firstChar, lastChar: Integer);
  394. begin
  395. case FCharacterRange of
  396. stcrAlphaNum:
  397. begin
  398. firstChar := 32;
  399. lastChar := 127;
  400. end;
  401. stcrNumbers:
  402. begin
  403. firstChar := Integer('0');
  404. lastChar := Integer('9');
  405. end;
  406. stcrDefault:
  407. begin
  408. firstChar := 0;
  409. lastChar := 255;
  410. end;
  411. stcrWide:
  412. begin
  413. firstChar := 0;
  414. lastChar := $077F;
  415. end;
  416. end;
  417. end;
  418. procedure TgxSpaceText.DoRender(var ARci: TgxRenderContextInfo;
  419. ARenderSelf, ARenderChildren: Boolean);
  420. var
  421. firstChar, lastChar: Integer;
  422. begin
  423. if GetText <> '' then
  424. begin
  425. if Assigned(FTextFontEntry) then
  426. FTextFontEntry^.FVirtualHandle.AllocateHandle;
  427. if FontChanged or (Assigned(FTextFontEntry) and
  428. (FTextFontEntry^.FVirtualHandle.IsDataNeedUpdate)) then
  429. with FFont do
  430. begin
  431. FontManager.Release(FTextFontEntry, Self);
  432. GetFirstAndLastChar(firstChar, lastChar);
  433. FTextFontEntry := FontManager.GetFontBase(Name, Style, FExtrusion,
  434. FAllowedDeviation, firstChar, lastChar, Self);
  435. FontChanged := False;
  436. FTextFontEntry^.FVirtualHandle.NotifyDataUpdated;
  437. end;
  438. end;
  439. inherited;
  440. end;
  441. // SetExtrusion
  442. //
  443. procedure TgxSpaceText.SetExtrusion(AValue: Single);
  444. begin
  445. Assert(AValue >= 0, 'Extrusion must be >=0');
  446. if FExtrusion <> AValue then
  447. begin
  448. FExtrusion := AValue;
  449. OnFontChange(nil);
  450. end;
  451. end;
  452. procedure TgxSpaceText.SetAllowedDeviation(const val: Single);
  453. begin
  454. if FAllowedDeviation <> val then
  455. begin
  456. if val > 0 then
  457. FAllowedDeviation := val
  458. else
  459. FAllowedDeviation := 0;
  460. OnFontChange(nil);
  461. end;
  462. end;
  463. procedure TgxSpaceText.SetCharacterRange(const val: TgxSpaceTextCharRange);
  464. begin
  465. if FCharacterRange <> val then
  466. begin
  467. FCharacterRange := val;
  468. OnFontChange(nil);
  469. end;
  470. end;
  471. procedure TgxSpaceText.SetFont(AFont: TFont);
  472. begin
  473. FFont.Assign(AFont);
  474. OnFontChange(nil);
  475. end;
  476. procedure TgxSpaceText.OnFontChange(sender: TObject);
  477. begin
  478. FontChanged := True;
  479. StructureChanged;
  480. end;
  481. procedure TgxSpaceText.SetText(const AText: WideString);
  482. begin
  483. if GetText <> AText then
  484. begin
  485. FLines.Text := AText;
  486. // StructureChanged is Called in DoOnLinesChange.
  487. end;
  488. end;
  489. procedure TgxSpaceText.DoOnLinesChange(sender: TObject);
  490. begin
  491. StructureChanged;
  492. end;
  493. function TgxSpaceText.GetText: WideString;
  494. begin
  495. if FLines.Count = 1 then
  496. Result := FLines[0]
  497. else
  498. Result := FLines.Text;
  499. end;
  500. procedure TgxSpaceText.SetLines(const Value: TStringList);
  501. begin
  502. FLines.Assign(Value);
  503. end;
  504. procedure TgxSpaceText.SetAdjust(const Value: TgxTextAdjust);
  505. begin
  506. FAdjust.Assign(Value);
  507. StructureChanged;
  508. end;
  509. procedure TgxSpaceText.SetAspectRatio(const Value: Single);
  510. begin
  511. if FAspectRatio <> Value then
  512. begin
  513. FAspectRatio := Value;
  514. StructureChanged;
  515. end;
  516. end;
  517. procedure TgxSpaceText.SetOblique(const Value: Single);
  518. begin
  519. if FOblique <> Value then
  520. begin
  521. FOblique := Value;
  522. StructureChanged;
  523. end;
  524. end;
  525. procedure TgxSpaceText.SetTextHeight(const Value: Single);
  526. begin
  527. if Value <> FTextHeight then
  528. begin
  529. FTextHeight := Value;
  530. StructureChanged;
  531. end;
  532. end;
  533. procedure TgxSpaceText.NotifyFontChanged;
  534. begin
  535. FTextFontEntry := nil;
  536. FontChanged := True;
  537. end;
  538. procedure TgxSpaceText.NotifyChange(sender: TObject);
  539. begin
  540. if sender is TFontManager then
  541. NotifyFontChanged
  542. else
  543. inherited;
  544. end;
  545. procedure TgxSpaceText.DefaultHandler(var Message);
  546. begin
  547. with TMessage(Message) do
  548. begin
  549. if Msg = vFontManagerMsgID then
  550. NotifyFontChanged
  551. else
  552. inherited;
  553. end;
  554. end;
  555. function TgxSpaceText.BarycenterAbsolutePosition: TVector4f;
  556. var
  557. lWidth, lHeightMax, lHeightMin: Single;
  558. AdjustVector: TVector4f;
  559. begin
  560. TextMetrics(Text, lWidth, lHeightMax, lHeightMin);
  561. case FAdjust.FHorz of
  562. haLeft:
  563. AdjustVector.X := lWidth / 2;
  564. haCenter:
  565. AdjustVector.X := 0; // Nothing.
  566. haRight:
  567. AdjustVector.X := -lWidth / 2;
  568. else
  569. begin
  570. AdjustVector.X := 0;
  571. Assert(False, strErrorEx + strUnknownType); // Not implemented...
  572. end;
  573. end;
  574. case FAdjust.FVert of
  575. vaTop:
  576. AdjustVector.Y := -(abs(lHeightMin) * 0.5 + lHeightMax * 0.5);
  577. vaCenter:
  578. AdjustVector.Y := 0; // Nothing.
  579. vaBottom:
  580. AdjustVector.Y := (abs(lHeightMin) * 0.5 + lHeightMax * 0.5);
  581. vaBaseLine:
  582. AdjustVector.Y := -(abs(lHeightMin) * 0.5 - lHeightMax * 0.5);
  583. else
  584. begin
  585. AdjustVector.Y := 0;
  586. Assert(False, strErrorEx + strUnknownType); // Not implemented...
  587. end;
  588. end;
  589. AdjustVector.Z := -(FExtrusion / 2);
  590. AdjustVector.W := 1;
  591. Result := LocalToAbsolute(AdjustVector);
  592. end;
  593. function TgxSpaceText.AxisAlignedDimensionsUnscaled: TVector4f;
  594. var
  595. lWidth, lHeightMax, lHeightMin: Single;
  596. charScale: Single;
  597. begin
  598. TextMetrics(Text, lWidth, lHeightMax, lHeightMin);
  599. if FTextHeight = 0 then
  600. charScale := 1
  601. else
  602. charScale := FTextHeight / lHeightMax;
  603. Result.X := lWidth / 2 * charScale;
  604. Result.Y := (lHeightMax + abs(lHeightMin)) / 2 * charScale;
  605. Result.Z := FExtrusion / 2;
  606. Result.W := 0;
  607. end;
  608. // ------------------
  609. // ------------------ TFontManager ------------------
  610. // ------------------
  611. constructor TFontManager.Create;
  612. begin
  613. inherited;
  614. end;
  615. destructor TFontManager.Destroy;
  616. var
  617. i: Integer;
  618. begin
  619. for i := 0 to Count - 1 do
  620. begin
  621. TFontEntry(Items[i]^).FVirtualHandle.Free;
  622. NotifyClients(TFontEntry(Items[i]^).FClients);
  623. TFontEntry(Items[i]^).FClients.Free;
  624. TFontEntry(Items[i]^).Name := '';
  625. FreeMem(Items[i], SizeOf(TFontEntry));
  626. end;
  627. inherited Destroy;
  628. end;
  629. procedure TFontManager.VirtualHandleAlloc(sender: TgxVirtualHandle;
  630. var handle: Cardinal);
  631. begin
  632. handle := FCurrentBase;
  633. end;
  634. procedure TFontManager.VirtualHandleDestroy(sender: TgxVirtualHandle;
  635. var handle: Cardinal);
  636. begin
  637. if handle <> 0 then
  638. glDeleteLists(handle, sender.Tag);
  639. end;
  640. function TFontManager.FindFont(AName: string; FStyles: TFontStyles;
  641. FExtrusion: Single; FAllowedDeviation: Single; FFirstChar, FLastChar: Integer)
  642. : PFontEntry;
  643. var
  644. i: Integer;
  645. begin
  646. Result := nil;
  647. // try to find an entry with the required attributes
  648. for i := 0 to Count - 1 do
  649. with TFontEntry(Items[i]^) do
  650. if (CompareText(Name, AName) = 0) and (Styles = FStyles) and
  651. (Extrusion = FExtrusion) and (allowedDeviation = FAllowedDeviation) and
  652. (firstChar = FFirstChar) and (lastChar = FLastChar) then
  653. begin
  654. // entry found
  655. Result := Items[i];
  656. Break;
  657. end;
  658. end;
  659. function TFontManager.GetFontBase(AName: string; FStyles: TFontStyles;
  660. FExtrusion: Single; allowedDeviation: Single; firstChar, lastChar: Integer;
  661. client: TObject): PFontEntry;
  662. var
  663. NewEntry: PFontEntry;
  664. MemDC: HDC;
  665. AFont: TFont;
  666. nbLists: Integer;
  667. success: Boolean;
  668. begin
  669. NewEntry := FindFont(AName, FStyles, FExtrusion, allowedDeviation, firstChar,
  670. lastChar);
  671. if Assigned(NewEntry) then
  672. begin
  673. Inc(NewEntry^.RefCount);
  674. if NewEntry^.FClients.IndexOf(client) < 0 then
  675. NewEntry^.FClients.Add(client);
  676. Result := NewEntry;
  677. end
  678. else
  679. Result := nil;
  680. if (Result = nil) or (Assigned(Result) and
  681. (Result^.FVirtualHandle.handle = 0)) then
  682. begin
  683. // no entry found, or entry was purged
  684. nbLists := lastChar - firstChar + 1;
  685. if not Assigned(NewEntry) then
  686. begin
  687. // no entry found, so create one
  688. New(NewEntry);
  689. NewEntry^.Name := AName;
  690. NewEntry^.FVirtualHandle := TgxVirtualHandleTransf.Create;
  691. NewEntry^.FVirtualHandle.OnAllocate := VirtualHandleAlloc;
  692. NewEntry^.FVirtualHandle.OnDestroy := VirtualHandleDestroy;
  693. NewEntry^.FVirtualHandle.Tag := nbLists;
  694. NewEntry^.Styles := FStyles;
  695. NewEntry^.Extrusion := FExtrusion;
  696. NewEntry^.RefCount := 1;
  697. NewEntry^.firstChar := firstChar;
  698. NewEntry^.lastChar := lastChar;
  699. SetLength(NewEntry^.glyphMetrics, nbLists);
  700. NewEntry^.allowedDeviation := allowedDeviation;
  701. NewEntry^.FClients := TList.Create;
  702. NewEntry^.FClients.Add(client);
  703. Add(NewEntry);
  704. end;
  705. // create a font to be used while display list creation
  706. AFont := TFont.Create;
  707. MemDC := CreateCompatibleDC(0);
  708. try
  709. AFont.Family := AName;
  710. AFont.Style := FStyles;
  711. { TODO : E2003 Undeclared identifier: 'handle' }
  712. (*SelectObject(MemDC, AFont.handle);*)
  713. FCurrentBase := glGenLists(nbLists);
  714. if FCurrentBase = 0 then
  715. raise Exception.Create('FontManager: no more display lists available');
  716. NewEntry^.FVirtualHandle.AllocateHandle;
  717. if lastChar < 256 then
  718. begin
  719. success := wglUseFontOutlinesA(MemDC, firstChar, nbLists, FCurrentBase,
  720. allowedDeviation, FExtrusion, WGL_FONT_POLYGONS,
  721. @NewEntry^.glyphMetrics[0]);
  722. end
  723. else
  724. begin
  725. success := wglUseFontOutlinesW(MemDC, firstChar, nbLists, FCurrentBase,
  726. allowedDeviation, FExtrusion, WGL_FONT_POLYGONS,
  727. @NewEntry^.glyphMetrics[0]);
  728. end;
  729. if not success then
  730. raise Exception.Create('FontManager: font creation failed');
  731. finally
  732. AFont.Free;
  733. DeleteDC(MemDC);
  734. end;
  735. Result := NewEntry;
  736. end;
  737. end;
  738. procedure TFontManager.Release(entry: PFontEntry; client: TObject);
  739. var
  740. hMsg: TMessage;
  741. begin
  742. if Assigned(entry) then
  743. begin
  744. Dec(entry^.RefCount);
  745. if Assigned(client) then
  746. begin
  747. hMsg.Msg := vFontManagerMsgID;
  748. client.DefaultHandler(hMsg);
  749. end;
  750. entry^.FClients.Remove(client);
  751. if entry^.RefCount = 0 then
  752. begin
  753. entry^.FVirtualHandle.Free;
  754. NotifyClients(entry^.FClients);
  755. entry^.FClients.Free;
  756. Remove(entry);
  757. Dispose(entry)
  758. end;
  759. end;
  760. end;
  761. procedure TFontManager.NotifyClients(Clients: TList);
  762. var
  763. i: Integer;
  764. hMsg: TMessage;
  765. begin
  766. hMsg.Msg := vFontManagerMsgID;
  767. for i := 0 to Clients.Count - 1 do
  768. TObject(Clients[i]).DefaultHandler(hMsg);
  769. end;
  770. // -------------------------------------------------------------
  771. initialization
  772. // -------------------------------------------------------------
  773. vFontManagerMsgID := RegisterWindowMessage(cFontManagerMsg);
  774. RegisterClass(TgxSpaceText);
  775. finalization
  776. ReleaseFontManager;
  777. end.