GXS.ViewerOpenGL.pas 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //
  2. // The graphics GaLaXy Engine. The unit of GXScene
  3. //
  4. unit GXS.ViewerOpenGL;
  5. (* Viewer OpenGL for FMX *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Winapi.Windows,
  11. System.Types,
  12. System.Classes,
  13. System.UITypes,
  14. System.SysUtils,
  15. FMX.Forms,
  16. FMX.Platform.Win,
  17. FMX.Types,
  18. FMX.Types3D,
  19. FMX.Controls,
  20. FMX.Graphics,
  21. Stage.OpenGL4, // GL_ARB_framebuffer_object or GL_EXT_framebuffer_blit
  22. Stage.TextureFormat,
  23. GXS.Scene,
  24. GXS.Context,
  25. GXS.WinContext;
  26. type
  27. TgxSceneViewport = class(TControl)
  28. private
  29. FGLSBuffer: TgxSceneBuffer;
  30. FFMXBuffer: TBitmap;
  31. FFMXContext: TContext3D;
  32. FMultisample: FMX.Types3D.TMultisample;
  33. FParentHandle: HWND;
  34. FOwnDC: HDC;
  35. FDrawing: Boolean;
  36. FPostRender: TNotifyEvent;
  37. procedure SetBuffer(const Value: TgxSceneBuffer);
  38. function GetSceneCamera: TgxCamera;
  39. procedure SetSceneCamera(const Value: TgxCamera);
  40. procedure CopyBuffer(Sender: TObject);
  41. procedure SetBeforeRender(const Value: TNotifyEvent);
  42. function GetBeforeRender: TNotifyEvent;
  43. procedure SetAfterRender(const Value: TNotifyEvent);
  44. function GetAfterRender: TNotifyEvent;
  45. protected
  46. procedure Paint; override;
  47. public
  48. constructor Create(AOwner: TComponent); override;
  49. destructor Destroy; override;
  50. //procedure Realign; override; - E2179, removed override;
  51. procedure Realign;
  52. published
  53. (* Triggered before the scene's objects get rendered.
  54. You may use this event to execute your own OpenGL rendering. *)
  55. property BeforeRender: TNotifyEvent read GetBeforeRender write SetBeforeRender;
  56. (* Triggered just after all the scene's objects have been rendered.
  57. The OpenGL context is still active in this event, and you may use it
  58. to execute your own OpenGL rendering. *)
  59. property PostRender: TNotifyEvent read FPostRender write FPostRender;
  60. (* Called after rendering. You cannot issue OpenGL calls in this event, if you want
  61. to do your own OpenGL stuff, use the PostRender event. *)
  62. property AfterRender: TNotifyEvent read GetAfterRender write SetAfterRender;
  63. // Access to buffer properties.
  64. property Buffer: TgxSceneBuffer read FGLSBuffer write SetBuffer;
  65. // Camera from which the scene is rendered.
  66. property SceneCamera: TgxCamera read GetSceneCamera write SetSceneCamera;
  67. end;
  68. //--------------------------------------------------------
  69. implementation
  70. //--------------------------------------------------------
  71. // TgxSceneViewport
  72. constructor TgxSceneViewport.Create(AOwner: TComponent);
  73. var
  74. FMXH: TFmxHandle;
  75. begin
  76. inherited Create(AOwner);
  77. FGLSBuffer := TgxSceneBuffer.Create(Self);
  78. FGLSBuffer.ContextOptions := FGLSBuffer.ContextOptions +
  79. [roDestinationAlpha] - [roDoubleBuffer] - [roNoSwapBuffers] + [roDebugContext];
  80. FGLSBuffer.BackgroundAlpha := 1.0;
  81. FGLSBuffer.AccumBufferBits := 32;
  82. FGLSBuffer.PostRender := CopyBuffer;
  83. if Owner is TCommonCustomForm then
  84. begin
  85. FMXH := THandle(Owner); /// TCommonCustomForm(Owner).Handle;
  86. FParentHandle := FMXH; /// FmxHandleToHWND(FMXH);
  87. end;
  88. Width := 100;
  89. Height := 100;
  90. FFMXBuffer := TBitmap.Create(100, 100);
  91. FMultisample := TMultisample.None;
  92. FFMXContext := TContextManager.DefaultContextClass.Create;
  93. end;
  94. destructor TgxSceneViewport.Destroy;
  95. begin
  96. FreeAndNil(FGLSBuffer);
  97. if FOwnDC <> 0 then
  98. begin
  99. ReleaseDC(FParentHandle, FOwnDC);
  100. FOwnDC := 0;
  101. end;
  102. FreeAndNil(FFMXBuffer);
  103. FreeAndNil(FFMXContext);
  104. inherited;
  105. end;
  106. procedure TgxSceneViewport.Realign;
  107. begin
  108. inherited Realign;
  109. if FFMXContext <> nil then
  110. begin
  111. FGLSBuffer.DestroyRC; // Service Context is shared handles, will be no so much
  112. FFMXBuffer.SetSize(Trunc(Width), Trunc(Height));
  113. FFMXContext.SetSize(Trunc(Width), Trunc(Height));
  114. AlignObjects(Self, Margins, FFMXBuffer.Width, FFMXBuffer.Height, FLastWidth, FLastHeight, FDisableAlign);
  115. end;
  116. end;
  117. procedure TgxSceneViewport.CopyBuffer(Sender: TObject);
  118. var
  119. tempBuffer: Cardinal;
  120. begin
  121. // Flip GL framebuffer
  122. if GL_ARB_framebuffer_object or GL_EXT_framebuffer_blit then
  123. begin
  124. if Buffer.RenderingContext.AntiAliasing in [aaDefault, aaNone] then
  125. tempBuffer := GL_AUX0
  126. else
  127. tempBuffer := GL_LEFT;
  128. glReadBuffer(GL_FRONT);
  129. glDrawBuffer(tempBuffer);
  130. FGLSBuffer.RenderingContext.gxStates.ReadFrameBuffer := 0;
  131. FGLSBuffer.RenderingContext.gxStates.DrawFrameBuffer := 0;
  132. glBlitFramebuffer(
  133. 0, FGLSBuffer.Height-1, FGLSBuffer.Width-1, 0,
  134. 0, 0, FGLSBuffer.Width-1, FGLSBuffer.Height-1,
  135. GL_COLOR_BUFFER_BIT, GL_NEAREST);
  136. glReadBuffer(tempBuffer);
  137. glDrawBuffer(GL_FRONT);
  138. end
  139. else
  140. begin
  141. FFMXBuffer.FlipHorizontal;
  142. glReadBuffer(GL_FRONT);
  143. end;
  144. // Read framebuffer to operative memory
  145. // FFMXBuffer.Startline - E2003 Undeclared identifier: 'StartLine', changed to
  146. glReadPixels(0, 0, FGLSBuffer.Width, FGLSBuffer.Height,
  147. GL_BGRA, GL_UNSIGNED_BYTE, FFMXBuffer.ClassInfo);
  148. glFinish;
  149. inherited Canvas.DrawBitmap(
  150. FFMXBuffer, RectF(0, 0, FFMXBuffer.Width, FFMXBuffer.Height),
  151. RectF(0, 0, FFMXBuffer.Width, FFMXBuffer.Height), AbsoluteOpacity, True);
  152. if Assigned(FPostRender) then
  153. FPostRender(Self);
  154. end;
  155. procedure TgxSceneViewport.Paint;
  156. var
  157. R: TRectF;
  158. begin
  159. if (csDesigning in ComponentState) then
  160. begin
  161. R := LocalRect;
  162. InflateRect(R, -0.5, -0.5);
  163. Canvas.Stroke.Thickness := 1;
  164. Canvas.Stroke.Dash := TStrokeDash.Dash;
  165. Canvas.Stroke.Kind := TBrushKind.Solid;
  166. Canvas.Stroke.Color := $A0909090;
  167. Canvas.DrawRect(R, 0, 0, AllCorners, AbsoluteOpacity);
  168. Canvas.Stroke.Dash := TStrokeDash.Solid;
  169. end;
  170. if FDrawing then Exit;
  171. if (FGLSBuffer.Width <> FFMXBuffer.Width)
  172. or (FGLSBuffer.Height <> FFMXBuffer.Height) then
  173. Realign;
  174. if FGLSBuffer.RenderingContext = nil then
  175. begin
  176. if FParentHandle <> 0 then
  177. begin
  178. FGLSBuffer.Resize(0, 0, Trunc(Width), Trunc(Height));
  179. FOwnDC := GetDC(FParentHandle);
  180. FGLSBuffer.CreateRC(FOwnDC, True, 1);
  181. FFMXContext.BeginScene;
  182. FFMXContext.Clear([TClearTarget.Color], TAlphaColor($FF000000), 1.0, 0);
  183. FFMXContext.EndScene;
  184. FDrawing := True;
  185. try
  186. FGLSBuffer.Render;
  187. finally
  188. FDrawing := False;
  189. end;
  190. end;
  191. end
  192. else
  193. begin
  194. FDrawing := True;
  195. try
  196. if FFMXContext.BeginScene then
  197. begin
  198. FGLSBuffer.Render;
  199. FFMXContext.EndScene;
  200. end;
  201. finally
  202. FDrawing := False;
  203. end;
  204. end;
  205. end;
  206. procedure TgxSceneViewport.SetBeforeRender(const Value: TNotifyEvent);
  207. begin
  208. FGLSBuffer.BeforeRender := Value;
  209. end;
  210. function TgxSceneViewport.GetBeforeRender: TNotifyEvent;
  211. begin
  212. Result := FGLSBuffer.BeforeRender;
  213. end;
  214. procedure TgxSceneViewport.SetAfterRender(const Value: TNotifyEvent);
  215. begin
  216. FGLSBuffer.AfterRender := Value;
  217. end;
  218. function TgxSceneViewport.GetAfterRender: TNotifyEvent;
  219. begin
  220. Result := FGLSBuffer.AfterRender;
  221. end;
  222. procedure TgxSceneViewport.SetBuffer(const Value: TgxSceneBuffer);
  223. begin
  224. FGLSBuffer.Assign(Value);
  225. end;
  226. function TgxSceneViewport.GetSceneCamera: TgxCamera;
  227. begin
  228. Result := FGLSBuffer.Camera;
  229. end;
  230. procedure TgxSceneViewport.SetSceneCamera(const Value: TgxCamera);
  231. begin
  232. FGLSBuffer.Camera := Value;
  233. end;
  234. //----------------------------------------------
  235. initialization
  236. //----------------------------------------------
  237. RegisterFmxClasses([TgxSceneViewport]);
  238. end.