GXS.FMX.Viewer.pas 7.3 KB

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