GLSpaceText.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLSpaceText;
  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. OpenGLTokens,
  27. GLScene,
  28. GLTexture,
  29. GLContext,
  30. GLVectorGeometry,
  31. GLS.Strings,
  32. GLRenderContextInfo,
  33. GLState;
  34. type
  35. TGLSpaceTextCharRange = (stcrDefault, stcrAlphaNum, stcrNumbers, stcrWide);
  36. // Note: haAligned, haCentrically, haFitIn have not been implemented!
  37. TGLTextHorzAdjust = (haLeft, haCenter, haRight, haAligned, haCentrically, haFitIn);
  38. TGLTextVertAdjust = (vaTop, vaCenter, vaBottom, vaBaseLine);
  39. TGLTextAdjust = class(TPersistent)
  40. private
  41. FHorz: TGLTextHorzAdjust;
  42. FVert: TGLTextVertAdjust;
  43. FOnChange: TNotifyEvent;
  44. procedure SetHorz(const Value: TGLTextHorzAdjust);
  45. procedure SetVert(const Value: TGLTextVertAdjust);
  46. public
  47. constructor Create;
  48. procedure Assign(Source: TPersistent); override;
  49. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  50. published
  51. property Horz: TGLTextHorzAdjust read FHorz write SetHorz default haLeft;
  52. property Vert: TGLTextVertAdjust read FVert write SetVert
  53. default vaBaseLine;
  54. end;
  55. // holds an entry in the font manager list (used in TGLSpaceText)
  56. PFontEntry = ^TFontEntry;
  57. TFontEntry = record
  58. Name: string;
  59. FVirtualHandle: TGLVirtualHandleTransf;
  60. Styles: TFontStyles;
  61. Extrusion: Single;
  62. RefCount: Integer;
  63. allowedDeviation: Single;
  64. firstChar, lastChar: Integer;
  65. glyphMetrics: array of TGlyphMetricsFloat;
  66. FClients: TList;
  67. end;
  68. { Renders a text in 3D. }
  69. TGLSpaceText = class(TGLSceneObject)
  70. private
  71. FFont: TFont;
  72. FExtrusion: Single;
  73. FAllowedDeviation: Single;
  74. FCharacterRange: TGLSpaceTextCharRange;
  75. FAdjust: TGLTextAdjust;
  76. FAspectRatio: Single;
  77. FOblique: Single;
  78. FTextHeight: Single;
  79. FLines: TStringList;
  80. procedure SetCharacterRange(const val: TGLSpaceTextCharRange);
  81. procedure SetAllowedDeviation(const val: Single);
  82. procedure SetExtrusion(AValue: Single);
  83. procedure SetFont(AFont: TFont);
  84. function GetText: WideString;
  85. procedure SetLines(const Value: TStringList);
  86. procedure SetText(const AText: WideString);
  87. procedure SetAdjust(const Value: TGLTextAdjust);
  88. procedure SetAspectRatio(const Value: Single);
  89. procedure SetOblique(const Value: Single);
  90. procedure SetTextHeight(const Value: Single);
  91. protected
  92. FTextFontEntry: PFontEntry;
  93. FontChanged: Boolean;
  94. procedure DestroyHandle; override;
  95. procedure OnFontChange(sender: TObject);
  96. procedure GetFirstAndLastChar(var firstChar, lastChar: Integer);
  97. procedure DoOnLinesChange(sender: TObject);
  98. public
  99. constructor Create(AOwner: TComponent); override;
  100. destructor Destroy; override;
  101. procedure Assign(Source: TPersistent); override;
  102. procedure BuildList(var rci: TGLRenderContextInfo); override;
  103. procedure DoRender(var ARci: TGLRenderContextInfo;
  104. ARenderSelf, ARenderChildren: Boolean); override;
  105. function TextWidth(const str: WideString = ''): Single;
  106. function TextMaxHeight(const str: WideString = ''): Single;
  107. function TextMaxUnder(const str: WideString = ''): Single;
  108. (* Note: this fuction is valid only after text has been rendered
  109. the first time. Before that it returns zeros. *)
  110. procedure TextMetrics(const str: WideString; out width, maxHeight, maxUnder: Single);
  111. procedure NotifyFontChanged;
  112. procedure NotifyChange(sender: TObject); override;
  113. procedure DefaultHandler(var Message); override;
  114. function AxisAlignedDimensionsUnscaled: TVector; override;
  115. function BarycenterAbsolutePosition: TVector; override;
  116. published
  117. (* Adjusts the 3D font extrusion.
  118. If Extrusion=0, the characters will be flat (2D), values >0 will
  119. give them a third dimension. *)
  120. property Extrusion: Single read FExtrusion write SetExtrusion;
  121. property Font: TFont read FFont write SetFont;
  122. property Text: WideString read GetText write SetText stored False;
  123. property Lines: TStringList read FLines write SetLines;
  124. // Quality related, see Win32 help for wglUseFontOutlines
  125. property allowedDeviation: Single read FAllowedDeviation
  126. write SetAllowedDeviation;
  127. (* Character range to convert.
  128. Converting less characters saves time and memory... *)
  129. property CharacterRange: TGLSpaceTextCharRange read FCharacterRange
  130. write SetCharacterRange default stcrDefault;
  131. property AspectRatio: Single read FAspectRatio write SetAspectRatio;
  132. property TextHeight: Single read FTextHeight write SetTextHeight;
  133. property Oblique: Single read FOblique write SetOblique;
  134. property Adjust: TGLTextAdjust read FAdjust write SetAdjust;
  135. end;
  136. // Manages a list of fonts for which display lists were created.
  137. TFontManager = class(TList)
  138. private
  139. FCurrentBase: Integer;
  140. protected
  141. procedure NotifyClients(Clients: TList);
  142. procedure VirtualHandleAlloc(sender: TGLVirtualHandle;
  143. var handle: Cardinal);
  144. procedure VirtualHandleDestroy(sender: TGLVirtualHandle;
  145. var handle: Cardinal);
  146. public
  147. constructor Create;
  148. destructor Destroy; override;
  149. function FindFont(AName: string; FStyles: TFontStyles; FExtrusion: Single;
  150. FAllowedDeviation: Single; FFirstChar, FLastChar: Integer): PFontEntry;
  151. function GetFontBase(AName: string; FStyles: TFontStyles;
  152. FExtrusion: Single; allowedDeviation: Single;
  153. firstChar, lastChar: Integer; client: TObject): PFontEntry;
  154. procedure Release(entry: PFontEntry; client: TObject);
  155. end;
  156. function FontManager: TFontManager;
  157. procedure ReleaseFontManager;
  158. var
  159. vFontManagerMsgID: Cardinal;
  160. // ------------------------------------------------------------------
  161. implementation
  162. // ------------------------------------------------------------------
  163. const
  164. cFontManagerMsg = 'FontManagerMessage';
  165. var
  166. vFontManager: TFontManager;
  167. function FontManager: TFontManager;
  168. begin
  169. if not Assigned(vFontManager) then
  170. vFontManager := TFontManager.Create;
  171. Result := vFontManager;
  172. end;
  173. procedure ReleaseFontManager;
  174. begin
  175. if Assigned(vFontManager) then
  176. begin
  177. vFontManager.Free;
  178. vFontManager := nil;
  179. end;
  180. end;
  181. // ------------------
  182. // ------------------ TGLTextAdjust ------------------
  183. // ------------------
  184. constructor TGLTextAdjust.Create;
  185. begin
  186. inherited;
  187. FHorz := haLeft;
  188. FVert := vaBaseLine;
  189. end;
  190. procedure TGLTextAdjust.Assign(Source: TPersistent);
  191. begin
  192. if Source is TGLTextAdjust then
  193. begin
  194. FHorz := TGLTextAdjust(Source).Horz;
  195. FVert := TGLTextAdjust(Source).Vert;
  196. if Assigned(FOnChange) then
  197. FOnChange(Self);
  198. end
  199. else
  200. inherited Assign(Source);
  201. end;
  202. procedure TGLTextAdjust.SetHorz(const Value: TGLTextHorzAdjust);
  203. begin
  204. if FHorz <> Value then
  205. begin
  206. FHorz := Value;
  207. if Assigned(FOnChange) then
  208. FOnChange(Self);
  209. end;
  210. end;
  211. procedure TGLTextAdjust.SetVert(const Value: TGLTextVertAdjust);
  212. begin
  213. if Value <> FVert then
  214. begin
  215. FVert := Value;
  216. if Assigned(FOnChange) then
  217. FOnChange(Self);
  218. end;
  219. end;
  220. // ------------------
  221. // ------------------ TGLSpaceText ------------------
  222. // ------------------
  223. constructor TGLSpaceText.Create(AOwner: TComponent);
  224. begin
  225. inherited Create(AOwner);
  226. FFont := TFont.Create;
  227. FFont.Name := 'Arial';
  228. FontChanged := True;
  229. CharacterRange := stcrDefault;
  230. FFont.OnChange := OnFontChange;
  231. FAdjust := TGLTextAdjust.Create;
  232. FAdjust.OnChange := OnFontChange;
  233. FLines := TStringList.Create;
  234. FLines.OnChange := DoOnLinesChange;
  235. end;
  236. destructor TGLSpaceText.Destroy;
  237. begin
  238. FAdjust.OnChange := nil;
  239. FAdjust.Free;
  240. FFont.OnChange := nil;
  241. FFont.Free;
  242. FLines.Free;
  243. FontManager.Release(FTextFontEntry, Self);
  244. inherited Destroy;
  245. end;
  246. procedure TGLSpaceText.TextMetrics(const str: WideString;
  247. out width, maxHeight, maxUnder: Single);
  248. var
  249. i, firstChar, lastChar, diff: Integer;
  250. buf: WideString;
  251. gmf: TGlyphMetricsFloat;
  252. begin
  253. width := 0;
  254. maxUnder := 0;
  255. maxHeight := 0;
  256. if Assigned(FTextFontEntry) then
  257. begin
  258. GetFirstAndLastChar(firstChar, lastChar);
  259. if str = '' then
  260. buf := GetText
  261. else
  262. buf := str;
  263. for i := 1 to Length(buf) do
  264. begin
  265. diff := Integer(buf[i]) - firstChar;
  266. if diff > High(FTextFontEntry^.glyphMetrics) then
  267. continue;
  268. gmf := FTextFontEntry^.glyphMetrics[diff];
  269. width := width + gmf.gmfCellIncX;
  270. if gmf.gmfptGlyphOrigin.y > maxHeight then
  271. maxHeight := gmf.gmfptGlyphOrigin.y;
  272. if gmf.gmfptGlyphOrigin.y - gmf.gmfBlackBoxY < maxUnder then
  273. maxUnder := gmf.gmfptGlyphOrigin.y - gmf.gmfBlackBoxY;
  274. end;
  275. end;
  276. end;
  277. function TGLSpaceText.TextWidth(const str: WideString = ''): Single;
  278. var
  279. mh, mu: Single;
  280. begin
  281. TextMetrics(str, Result, mh, mu);
  282. end;
  283. function TGLSpaceText.TextMaxHeight(const str: WideString = ''): Single;
  284. var
  285. w, mu: Single;
  286. begin
  287. TextMetrics(str, w, Result, mu);
  288. end;
  289. function TGLSpaceText.TextMaxUnder(const str: WideString = ''): Single;
  290. var
  291. w, mh: Single;
  292. begin
  293. TextMetrics(str, w, mh, Result);
  294. end;
  295. procedure TGLSpaceText.Assign(Source: TPersistent);
  296. begin
  297. inherited Assign(Source);
  298. if Source is TGLSpaceText then
  299. begin
  300. FAdjust.Assign(TGLSpaceText(Source).FAdjust);
  301. FFont.Assign(TGLSpaceText(Source).FFont);
  302. FAllowedDeviation := TGLSpaceText(Source).allowedDeviation;
  303. FAspectRatio := TGLSpaceText(Source).FAspectRatio;
  304. FCharacterRange := TGLSpaceText(Source).CharacterRange;
  305. FExtrusion := TGLSpaceText(Source).FExtrusion;
  306. FOblique := TGLSpaceText(Source).FOblique;
  307. FLines.Text := TGLSpaceText(Source).FLines.Text;
  308. FTextHeight := TGLSpaceText(Source).FTextHeight;
  309. StructureChanged;
  310. end;
  311. end;
  312. procedure TGLSpaceText.BuildList(var rci: TGLRenderContextInfo);
  313. var
  314. textL, maxUnder, maxHeight: Single;
  315. charScale: Single;
  316. i, j, k, c: Integer;
  317. glBase: Cardinal;
  318. dirtyLine, cleanLine: WideString;
  319. begin
  320. if Length(GetText) > 0 then
  321. begin
  322. gl.PushMatrix;
  323. // FAspectRatio ignore
  324. if FAspectRatio <> 0 then
  325. gl.Scalef(FAspectRatio, 1, 1);
  326. if FOblique <> 0 then
  327. gl.Rotatef(FOblique, 0, 0, 1);
  328. glBase := FTextFontEntry^.FVirtualHandle.handle;
  329. case FCharacterRange of
  330. stcrAlphaNum:
  331. gl.ListBase(Cardinal(Integer(glBase) - 32));
  332. stcrNumbers:
  333. gl.ListBase(Cardinal(Integer(glBase) - Integer('0')));
  334. else
  335. gl.ListBase(glBase);
  336. end;
  337. rci.GLStates.PushAttrib([sttPolygon]);
  338. for i := 0 to FLines.Count - 1 do
  339. begin
  340. gl.PushMatrix;
  341. TextMetrics(FLines.Strings[i], textL, maxHeight, maxUnder);
  342. if (FAdjust.Horz <> haLeft) or (FAdjust.Vert <> vaBaseLine) or
  343. (FTextHeight <> 0) then
  344. begin
  345. if FTextHeight <> 0 then
  346. begin
  347. charScale := FTextHeight / maxHeight;
  348. gl.Scalef(charScale, charScale, 1);
  349. end;
  350. case FAdjust.Horz of
  351. haLeft: ; // nothing
  352. haCenter: gl.Translatef(-textL * 0.5, 0, 0);
  353. haRight: gl.Translatef(-textL, 0, 0);
  354. end;
  355. case FAdjust.Vert of
  356. vaBaseLine: ; // nothing;
  357. vaBottom: gl.Translatef(0, abs(maxUnder), 0);
  358. vaCenter: gl.Translatef(0, abs(maxUnder) * 0.5 - maxHeight * 0.5, 0);
  359. vaTop: gl.Translatef(0, -maxHeight, 0);
  360. end;
  361. end;
  362. gl.Translatef(0, -i * (maxHeight + FAspectRatio), 0);
  363. if FCharacterRange = stcrWide then
  364. begin
  365. dirtyLine := FLines.Strings[i];
  366. SetLength(cleanLine, Length(dirtyLine));
  367. k := 1;
  368. for j := 1 to Length(dirtyLine) do
  369. begin
  370. c := Integer(dirtyLine[j]);
  371. if (c >= FTextFontEntry^.firstChar) and
  372. (c <= FTextFontEntry^.lastChar) then
  373. begin
  374. cleanLine[k] := dirtyLine[j];
  375. Inc(k);
  376. end;
  377. end;
  378. if k > 1 then
  379. gl.CallLists(k - 1, GL_UNSIGNED_SHORT, PWideChar(cleanLine))
  380. end
  381. else
  382. gl.CallLists(Length(FLines.Strings[i]), GL_UNSIGNED_BYTE,
  383. PAnsiChar(AnsiString(FLines.Strings[i])));
  384. gl.PopMatrix;
  385. end;
  386. rci.GLStates.PopAttrib();
  387. gl.PopMatrix;
  388. end;
  389. end;
  390. procedure TGLSpaceText.DestroyHandle;
  391. begin
  392. FontChanged := True;
  393. inherited;
  394. end;
  395. procedure TGLSpaceText.GetFirstAndLastChar(var firstChar, lastChar: Integer);
  396. begin
  397. case FCharacterRange of
  398. stcrAlphaNum:
  399. begin
  400. firstChar := 32;
  401. lastChar := 127;
  402. end;
  403. stcrNumbers:
  404. begin
  405. firstChar := Integer('0');
  406. lastChar := Integer('9');
  407. end;
  408. stcrDefault:
  409. begin
  410. firstChar := 0;
  411. lastChar := 255;
  412. end;
  413. stcrWide:
  414. begin
  415. firstChar := 0;
  416. lastChar := $077F;
  417. end;
  418. end;
  419. end;
  420. procedure TGLSpaceText.DoRender(var ARci: TGLRenderContextInfo;
  421. ARenderSelf, ARenderChildren: Boolean);
  422. var
  423. firstChar, lastChar: Integer;
  424. begin
  425. if GetText <> '' then
  426. begin
  427. if Assigned(FTextFontEntry) then
  428. FTextFontEntry^.FVirtualHandle.AllocateHandle;
  429. if FontChanged or (Assigned(FTextFontEntry) and
  430. (FTextFontEntry^.FVirtualHandle.IsDataNeedUpdate)) then
  431. with FFont do
  432. begin
  433. FontManager.Release(FTextFontEntry, Self);
  434. GetFirstAndLastChar(firstChar, lastChar);
  435. FTextFontEntry := FontManager.GetFontBase(Name, Style, FExtrusion,
  436. FAllowedDeviation, firstChar, lastChar, Self);
  437. FontChanged := False;
  438. FTextFontEntry^.FVirtualHandle.NotifyDataUpdated;
  439. end;
  440. end;
  441. inherited;
  442. end;
  443. procedure TGLSpaceText.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 TGLSpaceText.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 TGLSpaceText.SetCharacterRange(const val: TGLSpaceTextCharRange);
  464. begin
  465. if FCharacterRange <> val then
  466. begin
  467. FCharacterRange := val;
  468. OnFontChange(nil);
  469. end;
  470. end;
  471. procedure TGLSpaceText.SetFont(AFont: TFont);
  472. begin
  473. FFont.Assign(AFont);
  474. OnFontChange(nil);
  475. end;
  476. procedure TGLSpaceText.OnFontChange(sender: TObject);
  477. begin
  478. FontChanged := True;
  479. StructureChanged;
  480. end;
  481. procedure TGLSpaceText.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 TGLSpaceText.DoOnLinesChange(sender: TObject);
  490. begin
  491. StructureChanged;
  492. end;
  493. function TGLSpaceText.GetText: WideString;
  494. begin
  495. if FLines.Count = 1 then
  496. Result := FLines[0]
  497. else
  498. Result := FLines.Text;
  499. end;
  500. procedure TGLSpaceText.SetLines(const Value: TStringList);
  501. begin
  502. FLines.Assign(Value);
  503. end;
  504. procedure TGLSpaceText.SetAdjust(const Value: TGLTextAdjust);
  505. begin
  506. FAdjust.Assign(Value);
  507. StructureChanged;
  508. end;
  509. procedure TGLSpaceText.SetAspectRatio(const Value: Single);
  510. begin
  511. if FAspectRatio <> Value then
  512. begin
  513. FAspectRatio := Value;
  514. StructureChanged;
  515. end;
  516. end;
  517. procedure TGLSpaceText.SetOblique(const Value: Single);
  518. begin
  519. if FOblique <> Value then
  520. begin
  521. FOblique := Value;
  522. StructureChanged;
  523. end;
  524. end;
  525. procedure TGLSpaceText.SetTextHeight(const Value: Single);
  526. begin
  527. if Value <> FTextHeight then
  528. begin
  529. FTextHeight := Value;
  530. StructureChanged;
  531. end;
  532. end;
  533. procedure TGLSpaceText.NotifyFontChanged;
  534. begin
  535. FTextFontEntry := nil;
  536. FontChanged := True;
  537. end;
  538. procedure TGLSpaceText.NotifyChange(sender: TObject);
  539. begin
  540. if sender is TFontManager then
  541. NotifyFontChanged
  542. else
  543. inherited;
  544. end;
  545. procedure TGLSpaceText.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 TGLSpaceText.BarycenterAbsolutePosition: TVector;
  556. var
  557. lWidth, lHeightMax, lHeightMin: Single;
  558. AdjustVector: TVector;
  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 TGLSpaceText.AxisAlignedDimensionsUnscaled: TVector;
  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: TGLVirtualHandle;
  630. var handle: Cardinal);
  631. begin
  632. handle := FCurrentBase;
  633. end;
  634. procedure TFontManager.VirtualHandleDestroy(sender: TGLVirtualHandle;
  635. var handle: Cardinal);
  636. begin
  637. if handle <> 0 then
  638. gl.DeleteLists(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 := TGLVirtualHandleTransf.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. // creates a font to be used while display list creation
  706. AFont := TFont.Create;
  707. MemDC := CreateCompatibleDC(0);
  708. try
  709. AFont.Name := AName;
  710. AFont.Style := FStyles;
  711. SelectObject(MemDC, AFont.handle);
  712. FCurrentBase := gl.GenLists(nbLists);
  713. if FCurrentBase = 0 then
  714. raise Exception.Create('FontManager: no more display lists available');
  715. NewEntry^.FVirtualHandle.AllocateHandle;
  716. if lastChar < 256 then
  717. begin
  718. success := wglUseFontOutlinesA(MemDC, firstChar, nbLists, FCurrentBase,
  719. allowedDeviation, FExtrusion, WGL_FONT_POLYGONS,
  720. @NewEntry^.glyphMetrics[0]);
  721. end
  722. else
  723. begin
  724. success := wglUseFontOutlinesW(MemDC, firstChar, nbLists, FCurrentBase,
  725. allowedDeviation, FExtrusion, WGL_FONT_POLYGONS,
  726. @NewEntry^.glyphMetrics[0]);
  727. end;
  728. if not success then
  729. raise Exception.Create('FontManager: font creation failed');
  730. finally
  731. AFont.Free;
  732. DeleteDC(MemDC);
  733. end;
  734. Result := NewEntry;
  735. end;
  736. end;
  737. procedure TFontManager.Release(entry: PFontEntry; client: TObject);
  738. var
  739. hMsg: TMessage;
  740. begin
  741. if Assigned(entry) then
  742. begin
  743. Dec(entry^.RefCount);
  744. if Assigned(client) then
  745. begin
  746. hMsg.Msg := vFontManagerMsgID;
  747. client.DefaultHandler(hMsg);
  748. end;
  749. entry^.FClients.Remove(client);
  750. if entry^.RefCount = 0 then
  751. begin
  752. entry^.FVirtualHandle.Free;
  753. NotifyClients(entry^.FClients);
  754. entry^.FClients.Free;
  755. Remove(entry);
  756. Dispose(entry)
  757. end;
  758. end;
  759. end;
  760. procedure TFontManager.NotifyClients(Clients: TList);
  761. var
  762. i: Integer;
  763. hMsg: TMessage;
  764. begin
  765. hMsg.Msg := vFontManagerMsgID;
  766. for i := 0 to Clients.Count - 1 do
  767. TObject(Clients[i]).DefaultHandler(hMsg);
  768. end;
  769. // -------------------------------------------------------------
  770. initialization
  771. // -------------------------------------------------------------
  772. vFontManagerMsgID := RegisterWindowMessage(cFontManagerMsg);
  773. RegisterClass(TGLSpaceText);
  774. finalization
  775. ReleaseFontManager;
  776. end.