GLS.HUDObjects.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.HUDObjects;
  5. (* GLScene objects that get rendered in 2D coordinates *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. Vcl.StdCtrls,
  12. GLS.OpenGLTokens,
  13. GLS.Scene,
  14. GLS.VectorTypes,
  15. GLS.Coordinates,
  16. GLS.PersistentClasses,
  17. GLS.VectorGeometry,
  18. GLS.Objects,
  19. GLS.BitmapFont,
  20. GLS.Color,
  21. GLS.RenderContextInfo,
  22. GLS.Material,
  23. GLS.Texture;
  24. type
  25. (*
  26. A rectangular area, NOT perspective projected.
  27. (x, y) coordinates map directly to the viewport (in pixels) and refer
  28. the center of the area.
  29. The coordinate system is that of an equivalent TCanvas, ie. top-left
  30. point is the origin (0, 0).
  31. The z component is ignored and Z-Buffer is disabled when rendering.
  32. Using TGLHUDSprite in 2D only scenes :
  33. The most convenient way to use a TGLHUDSprite as a simple 2D sprite with
  34. blending capabilities (transparency or additive), is to set the texture
  35. mode to tmModulate, in FrontProperties, to use the Emission color to
  36. control coloring/intensity, and finally use the Diffuse color's alpha
  37. to control transparency (while setting the other RGB components to 0).
  38. You can also control aplha-blending by defining a <1 value in the sprite's
  39. AlphaChannel field. This provides you with hardware accelerated,
  40. alpha-blended blitting.
  41. Note : since TGLHUDSprite works in absolute coordinates, TGLProxyObject
  42. can't be used to duplicate an hud sprite.
  43. *)
  44. TGLHUDSprite = class(TGLSprite)
  45. private
  46. FXTiles, FYTiles: Integer;
  47. function StoreWidth: Boolean;
  48. function StoreHeight: Boolean;
  49. protected
  50. procedure SetXTiles(const val: Integer);
  51. procedure SetYTiles(const val: Integer);
  52. public
  53. constructor Create(AOwner: TComponent); override;
  54. procedure DoRender(var rci: TGLRenderContextInfo;
  55. renderSelf, renderChildren: Boolean); override;
  56. published
  57. property XTiles: Integer read FXTiles write SetXTiles default 1;
  58. property YTiles: Integer read FYTiles write SetYTiles default 1;
  59. // Redeclare them with new default values.
  60. property Width stored StoreWidth;
  61. property Height stored StoreHeight;
  62. end;
  63. (*
  64. A 2D text displayed and positionned in 2D coordinates.
  65. The HUDText uses a character font defined and stored by a TGLBitmapFont
  66. component. The text can be scaled and rotated (2D), the layout and
  67. alignment can also be controled.
  68. *)
  69. TGLHUDText = class(TGLImmaterialSceneObject)
  70. private
  71. FBitmapFont: TGLCustomBitmapFont;
  72. FText: UnicodeString;
  73. FRotation: Single;
  74. FAlignment: TAlignment;
  75. FLayout: TTextLayout;
  76. FModulateColor: TGLColor;
  77. protected
  78. procedure SetBitmapFont(const val: TGLCustomBitmapFont);
  79. procedure SetText(const val: UnicodeString);
  80. procedure SetRotation(const val: Single);
  81. procedure SetAlignment(const val: TAlignment);
  82. procedure SetLayout(const val: TTextLayout);
  83. procedure SetModulateColor(const val: TGLColor);
  84. procedure Notification(AComponent: TComponent;
  85. Operation: TOperation); override;
  86. procedure RenderTextAtPosition(const X, Y, Z: Single;
  87. var rci: TGLRenderContextInfo);
  88. public
  89. constructor Create(AOwner: TComponent); override;
  90. destructor Destroy; override;
  91. procedure DoRender(var rci: TGLRenderContextInfo;
  92. renderSelf, renderChildren: Boolean); override;
  93. published
  94. (*
  95. Refers the bitmap font to use.
  96. The referred bitmap font component stores and allows access to
  97. individual character bitmaps.
  98. *)
  99. property BitmapFont: TGLCustomBitmapFont read FBitmapFont
  100. write SetBitmapFont;
  101. (*
  102. Text to render.
  103. Be aware that only the characters available in the bitmap font will
  104. be rendered. CR LF sequences are allowed.
  105. *)
  106. property Text: UnicodeString read FText write SetText;
  107. // Rotation angle in degrees (2d).
  108. property Rotation: Single read FRotation write SetRotation;
  109. (* Controls the text alignment (horizontal).
  110. Possible values : taLeftJustify, taRightJustify, taCenter *)
  111. property Alignment: TAlignment read FAlignment write SetAlignment
  112. default taLeftJustify;
  113. (* Controls the text layout (vertical).
  114. Possible values : tlTop, tlCenter, tlBottom *)
  115. property Layout: TTextLayout read FLayout write SetLayout default tlTop;
  116. // Color modulation, can be used for fade in/out too.
  117. property ModulateColor: TGLColor read FModulateColor write SetModulateColor;
  118. end;
  119. (* Position (X, Y and X) is in absolute coordinates. This component converts
  120. them to screen coordinates and renderes text there. *)
  121. TGLAbsoluteHUDText = class(TGLHUDText)
  122. public
  123. procedure DoRender(var rci: TGLRenderContextInfo;
  124. renderSelf, renderChildren: Boolean); override;
  125. end;
  126. (*
  127. Position (X and Y) is expected in a [0..1] range (from Screen size)
  128. This component converts this position to the actual screen position and
  129. renders the text there. This way a HUD text always appears to be in the
  130. the same place, regardless of the currect screen resolution.
  131. Note: this still does not solve the font scaling problem.
  132. *)
  133. TGLResolutionIndependantHUDText = class(TGLHUDText)
  134. public
  135. procedure DoRender(var rci: TGLRenderContextInfo;
  136. renderSelf, renderChildren: Boolean); override;
  137. constructor Create(AOwner: TComponent); override;
  138. end;
  139. // ------------------------------------------------------------------
  140. implementation
  141. // ------------------------------------------------------------------
  142. uses
  143. GLS.Context,
  144. GLS.State,
  145. GLS.XOpenGL;
  146. // ------------------
  147. // ------------------ TGLHUDSprite ------------------
  148. // ------------------
  149. constructor TGLHUDSprite.Create(AOwner: TComponent);
  150. begin
  151. inherited;
  152. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  153. Width := 16;
  154. Height := 16;
  155. FXTiles := 1;
  156. FYTiles := 1;
  157. end;
  158. procedure TGLHUDSprite.SetXTiles(const val: Integer);
  159. begin
  160. if val <> FXTiles then
  161. begin
  162. FXTiles := val;
  163. StructureChanged;
  164. end;
  165. end;
  166. procedure TGLHUDSprite.SetYTiles(const val: Integer);
  167. begin
  168. if val <> FYTiles then
  169. begin
  170. FYTiles := val;
  171. StructureChanged;
  172. end;
  173. end;
  174. procedure TGLHUDSprite.DoRender(var rci: TGLRenderContextInfo;
  175. renderSelf, renderChildren: Boolean);
  176. var
  177. vx, vy, vx1, vy1, f: Single;
  178. u0, v0, u1, v1: Integer;
  179. begin
  180. if rci.ignoreMaterials then
  181. Exit;
  182. Material.Apply(rci);
  183. repeat
  184. if AlphaChannel <> 1 then
  185. begin
  186. if stLighting in rci.GLStates.States then
  187. rci.GLStates.SetGLMaterialAlphaChannel(GL_FRONT, AlphaChannel)
  188. else
  189. with Material.GetActualPrimaryMaterial.FrontProperties.Diffuse do
  190. gl.Color4f(Red, Green, Blue, AlphaChannel);
  191. end;
  192. // Prepare matrices
  193. gl.MatrixMode(GL_MODELVIEW);
  194. gl.PushMatrix;
  195. gl.LoadMatrixf(@TGLSceneBuffer(rci.buffer).BaseProjectionMatrix);
  196. if rci.renderDPI = 96 then
  197. f := 1
  198. else
  199. f := rci.renderDPI / 96;
  200. gl.Scalef(2 / rci.viewPortSize.cx, 2 / rci.viewPortSize.cy, 1);
  201. gl.Translatef(f * Position.X - rci.viewPortSize.cx * 0.5,
  202. rci.viewPortSize.cy * 0.5 - f * Position.Y, Position.Z);
  203. if Rotation <> 0 then
  204. gl.Rotatef(Rotation, 0, 0, 1);
  205. gl.MatrixMode(GL_PROJECTION);
  206. gl.PushMatrix;
  207. gl.LoadIdentity;
  208. rci.GLStates.Disable(stDepthTest);
  209. rci.GLStates.DepthWriteMask := False;
  210. // precalc coordinates
  211. vx := -Width * 0.5 * f;
  212. vx1 := vx + Width * f;
  213. vy := +Height * 0.5 * f;
  214. vy1 := vy - Height * f;
  215. // Texture coordinates
  216. if MirrorU then
  217. begin
  218. u0 := FXTiles;
  219. u1 := 0;
  220. end
  221. else
  222. begin
  223. u0 := 0;
  224. u1 := FXTiles;
  225. end;
  226. if MirrorV then
  227. begin
  228. v0 := FYTiles;
  229. v1 := 0;
  230. end
  231. else
  232. begin
  233. v0 := 0;
  234. v1 := FYTiles;
  235. end;
  236. // issue quad
  237. gl.Begin_(GL_QUADS);
  238. gl.Normal3fv(@YVector);
  239. xgl.TexCoord2f(u0, v0);
  240. gl.Vertex2f(vx, vy1);
  241. xgl.TexCoord2f(u1, v0);
  242. gl.Vertex2f(vx1, vy1);
  243. xgl.TexCoord2f(u1, v1);
  244. gl.Vertex2f(vx1, vy);
  245. xgl.TexCoord2f(u0, v1);
  246. gl.Vertex2f(vx, vy);
  247. gl.End_;
  248. // restore state
  249. gl.PopMatrix;
  250. gl.MatrixMode(GL_MODELVIEW);
  251. gl.PopMatrix;
  252. until not Material.UnApply(rci);
  253. if Count > 0 then
  254. Self.renderChildren(0, Count - 1, rci);
  255. end;
  256. function TGLHUDSprite.StoreHeight: Boolean;
  257. begin
  258. Result := Abs(Height - 16) > 0.001;
  259. end;
  260. function TGLHUDSprite.StoreWidth: Boolean;
  261. begin
  262. Result := Abs(Height - 16) > 0.001;
  263. end;
  264. // ------------------
  265. // ------------------ TGLHUDText ------------------
  266. // ------------------
  267. constructor TGLHUDText.Create(AOwner: TComponent);
  268. begin
  269. inherited;
  270. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  271. FModulateColor := TGLColor.CreateInitialized(Self, clrWhite);
  272. end;
  273. destructor TGLHUDText.Destroy;
  274. begin
  275. FModulateColor.Free;
  276. BitmapFont := nil;
  277. inherited;
  278. end;
  279. procedure TGLHUDText.Notification(AComponent: TComponent;
  280. Operation: TOperation);
  281. begin
  282. if (Operation = opRemove) and (AComponent = FBitmapFont) then
  283. BitmapFont := nil;
  284. inherited;
  285. end;
  286. procedure TGLHUDText.SetBitmapFont(const val: TGLCustomBitmapFont);
  287. begin
  288. if val <> FBitmapFont then
  289. begin
  290. if Assigned(FBitmapFont) then
  291. FBitmapFont.UnRegisterUser(Self);
  292. FBitmapFont := val;
  293. if Assigned(FBitmapFont) then
  294. begin
  295. FBitmapFont.RegisterUser(Self);
  296. FBitmapFont.FreeNotification(Self);
  297. end;
  298. StructureChanged;
  299. end;
  300. end;
  301. procedure TGLHUDText.SetText(const val: UnicodeString);
  302. begin
  303. FText := val;
  304. StructureChanged;
  305. end;
  306. procedure TGLHUDText.SetRotation(const val: Single);
  307. begin
  308. FRotation := val;
  309. StructureChanged;
  310. end;
  311. procedure TGLHUDText.SetAlignment(const val: TAlignment);
  312. begin
  313. FAlignment := val;
  314. StructureChanged;
  315. end;
  316. procedure TGLHUDText.SetLayout(const val: TTextLayout);
  317. begin
  318. FLayout := val;
  319. StructureChanged;
  320. end;
  321. procedure TGLHUDText.SetModulateColor(const val: TGLColor);
  322. begin
  323. FModulateColor.Assign(val);
  324. end;
  325. procedure TGLHUDText.RenderTextAtPosition(const X, Y, Z: Single;
  326. var rci: TGLRenderContextInfo);
  327. var
  328. f: Single;
  329. begin
  330. if Assigned(FBitmapFont) and (Text <> '') then
  331. begin
  332. rci.GLStates.PolygonMode := pmFill;
  333. // Prepare matrices
  334. gl.MatrixMode(GL_MODELVIEW);
  335. gl.PushMatrix;
  336. gl.LoadMatrixf(@TGLSceneBuffer(rci.buffer).BaseProjectionMatrix);
  337. f := rci.renderDPI / 96;
  338. gl.Scalef(2 / rci.viewPortSize.cx, 2 / rci.viewPortSize.cy, 1);
  339. gl.Translatef(X * f - rci.viewPortSize.cx / 2, rci.viewPortSize.cy / 2 -
  340. Y * f, Z);
  341. if FRotation <> 0 then
  342. gl.Rotatef(FRotation, 0, 0, 1);
  343. gl.Scalef(Scale.DirectX * f, Scale.DirectY * f, 1);
  344. gl.MatrixMode(GL_PROJECTION);
  345. gl.PushMatrix;
  346. gl.LoadIdentity;
  347. rci.GLStates.Disable(stDepthTest);
  348. // render text
  349. FBitmapFont.RenderString(rci, Text, FAlignment, FLayout,
  350. FModulateColor.Color);
  351. // restore state
  352. rci.GLStates.Enable(stDepthTest);
  353. gl.PopMatrix;
  354. gl.MatrixMode(GL_MODELVIEW);
  355. gl.PopMatrix;
  356. end;
  357. end;
  358. procedure TGLHUDText.DoRender(var rci: TGLRenderContextInfo;
  359. renderSelf, renderChildren: Boolean);
  360. begin
  361. RenderTextAtPosition(Position.X, Position.Y, Position.Z, rci);
  362. if Count > 0 then
  363. Self.renderChildren(0, Count - 1, rci);
  364. end;
  365. // ------------------
  366. // ------------------ TGLResolutionIndependantHUDText ------------------
  367. // ------------------
  368. constructor TGLResolutionIndependantHUDText.Create(AOwner: TComponent);
  369. begin
  370. inherited;
  371. Position.X := 0.5;
  372. Position.Y := 0.5;
  373. end;
  374. procedure TGLResolutionIndependantHUDText.DoRender(var rci: TGLRenderContextInfo;
  375. renderSelf, renderChildren: Boolean);
  376. begin
  377. RenderTextAtPosition(Position.X * rci.viewPortSize.cx,
  378. Position.Y * rci.viewPortSize.cy, Position.Z, rci);
  379. if Count > 0 then
  380. Self.renderChildren(0, Count - 1, rci);
  381. end;
  382. // ------------------
  383. // ------------------ TGLAbsoluteHUDText ------------------
  384. // ------------------
  385. procedure TGLAbsoluteHUDText.DoRender(var rci: TGLRenderContextInfo;
  386. renderSelf, renderChildren: Boolean);
  387. var
  388. Temp: TAffineVector;
  389. begin
  390. Temp := TGLSceneBuffer(rci.buffer).WorldToScreen(Self.AbsoluteAffinePosition);
  391. Temp.Y := rci.viewPortSize.cy - Temp.Y;
  392. RenderTextAtPosition(Temp.X, Temp.Y, Temp.Z, rci);
  393. if Count > 0 then
  394. Self.renderChildren(0, Count - 1, rci);
  395. end;
  396. // ------------------------------------------------------------------
  397. initialization
  398. // ------------------------------------------------------------------
  399. RegisterClasses([TGLHUDText, TGLHUDSprite, TGLResolutionIndependantHUDText,
  400. TGLAbsoluteHUDText]);
  401. end.