GLHUDObjects.pas 13 KB

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