GLS.SpaceText.pas 23 KB

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