GLS.SDLContext.pas 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLS.SDLContext;
  5. (*
  6. SDL specific Context and Viewer.
  7. NOTA: SDL notifies use of context destruction *after* it happened, this prevents
  8. clean release of allocated stuff and requires a temporary switch to
  9. "ignore OpenGL errors" mode during destruction, thus potentially
  10. leaking memory (depending on hardware drivers willingness to perform
  11. automatic releases)
  12. *)
  13. interface
  14. uses
  15. Winapi.Windows,
  16. System.Classes,
  17. System.SysUtils,
  18. OpenGLTokens,
  19. OpenGLAdapter,
  20. XOpenGL,
  21. GLContext,
  22. GLScene,
  23. GLCrossPlatform,
  24. GLS.SDLWindow,
  25. Import.SDL2;
  26. type
  27. (* A viewer using SDL.
  28. Beware: only one at a time, no other viewers allowed!
  29. Will also close the application when the window is closed! *)
  30. TSDLViewer = class(TGLNonVisualViewer)
  31. private
  32. FCaption: string;
  33. FOnSDLEvent: TSDLEvent;
  34. FOnEventPollDone: TNotifyEvent;
  35. FOnResize: TNotifyEvent;
  36. protected
  37. procedure SetCaption(const val: string);
  38. procedure DoOnOpen(sender: TObject);
  39. procedure DoOnClose(sender: TObject);
  40. procedure DoOnResize(sender: TObject);
  41. procedure DoOnSDLEvent(sender: TObject; const event: TSDL_Event);
  42. procedure DoOnEventPollDone(sender: TObject);
  43. procedure DoBufferStructuralChange(Sender: TObject); override;
  44. procedure PrepareGLContext; override;
  45. public
  46. constructor Create(AOwner: TComponent); override;
  47. destructor Destroy; override;
  48. procedure Render(baseObject: TGLBaseSceneObject = nil); override;
  49. function Active: Boolean;
  50. published
  51. property Caption: string read FCaption write SetCaption;
  52. property OnResize: TNotifyEvent read FOnResize write FOnResize;
  53. (* Fired whenever an SDL Event is polled.
  54. SDL_QUITEV and SDL_VIDEORESIZE are not passed to this event handler,
  55. they are passed via OnClose and OnResize respectively. *)
  56. property OnSDLEvent: TSDLEvent read FOnSDLEvent write FOnSDLEvent;
  57. // Fired whenever an event polling completes with no events left to poll.
  58. property OnEventPollDone: TNotifyEvent read FOnEventPollDone write FOnEventPollDone;
  59. end;
  60. (* A context driver for OpenGL via SDL (libsdl.org).
  61. Due to limitations of SDL:
  62. you may have only one SDL window opened at any time (you cannot have memory viewers)
  63. closing the SDL window will terminate the application *)
  64. TSDLContext = class(TGLScreenControlingContext)
  65. private
  66. FSDLWin: TSDLWindow;
  67. FSimulatedValidity: Boolean; // Hack around SDL's post-notified destruction of context
  68. protected
  69. procedure DoCreateContext(outputDevice: HDC); override;
  70. procedure DoCreateMemoryContext(outputDevice: HWND; width, height: Integer; BufferCount: integer); override;
  71. function DoShareLists(aContext: TGLContext): Boolean; override;
  72. procedure DoDestroyContext; override;
  73. procedure DoActivate; override;
  74. procedure DoDeactivate; override;
  75. public
  76. constructor Create; override;
  77. destructor Destroy; override;
  78. function IsValid: Boolean; override;
  79. procedure SwapBuffers; override;
  80. function RenderOutputDevice: Pointer; override;
  81. property SDLWindow: TSDLWindow read FSDLWin;
  82. end;
  83. procedure Register;
  84. // ------------------------------------------------------------------
  85. implementation
  86. // ------------------------------------------------------------------
  87. // ------------------
  88. // ------------------ TSDLViewer ------------------
  89. // ------------------
  90. constructor TSDLViewer.Create(AOwner: TComponent);
  91. begin
  92. inherited Create(AOwner);
  93. Width := 640;
  94. Height := 480;
  95. end;
  96. destructor TSDLViewer.Destroy;
  97. begin
  98. inherited Destroy;
  99. end;
  100. procedure TSDLViewer.DoBufferStructuralChange(Sender: TObject);
  101. begin
  102. // ignore that, supporting it with SDL is not very praticable as of now...
  103. end;
  104. procedure TSDLViewer.PrepareGLContext;
  105. begin
  106. with Buffer.RenderingContext as TSDLContext do
  107. begin
  108. Width := Self.Width;
  109. Height := Self.Height;
  110. with FSDLWin do
  111. begin
  112. Caption := Self.Caption;
  113. OnOpen := DoOnOpen;
  114. OnClose := DoOnClose;
  115. OnResize := DoOnResize;
  116. OnSDLEvent := DoOnSDLEvent;
  117. OnEventPollDone := DoOnEventPollDone;
  118. end;
  119. end;
  120. end;
  121. procedure TSDLViewer.Render(baseObject: TGLBaseSceneObject = nil);
  122. begin
  123. LoadOpenGL;
  124. if Buffer.RenderingContext = nil then
  125. begin
  126. Buffer.CreateRC(0, False);
  127. end;
  128. Buffer.Render(baseObject);
  129. end;
  130. function TSDLViewer.Active: Boolean;
  131. begin
  132. Result := Assigned(Buffer.RenderingContext) and Buffer.RenderingContext.IsValid;
  133. end;
  134. procedure TSDLViewer.SetCaption(const val: string);
  135. begin
  136. if val <> FCaption then
  137. begin
  138. FCaption := val;
  139. if Buffer.RenderingContext <> nil then
  140. with Buffer.RenderingContext as TSDLContext do
  141. if Assigned(FSDLWin) then
  142. FSDLWin.Caption := FCaption;
  143. end;
  144. end;
  145. procedure TSDLViewer.DoOnOpen(sender: TObject);
  146. begin
  147. // nothing yet
  148. end;
  149. procedure TSDLViewer.DoOnClose(sender: TObject);
  150. begin
  151. // nothing yet
  152. end;
  153. procedure TSDLViewer.DoOnResize(sender: TObject);
  154. begin
  155. with Buffer.RenderingContext as TSDLContext do
  156. begin
  157. Self.Width := FSDLWin.Width;
  158. Self.Height := FSDLWin.Height;
  159. Buffer.Resize(0, 0, FSDLWin.Width, FSDLWin.Height);
  160. end;
  161. if Assigned(FOnResize) then
  162. FOnResize(Self);
  163. end;
  164. procedure TSDLViewer.DoOnSDLEvent(sender: TObject; const event: TSDL_Event);
  165. begin
  166. if Assigned(FOnSDLEvent) then
  167. FOnSDLEvent(sender, event);
  168. end;
  169. procedure TSDLViewer.DoOnEventPollDone(sender: TObject);
  170. begin
  171. if Assigned(FOnEventPollDone) then
  172. FOnEventPollDone(sender);
  173. end;
  174. // ------------------
  175. // ------------------ TSDLContext ------------------
  176. // ------------------
  177. constructor TSDLContext.Create;
  178. begin
  179. inherited Create;
  180. FSDLWin := TSDLWindow.Create(nil);
  181. end;
  182. destructor TSDLContext.Destroy;
  183. var
  184. oldIgnore: Boolean;
  185. begin
  186. oldIgnore := vIgnoreOpenGLErrors;
  187. FSimulatedValidity := True;
  188. vIgnoreOpenGLErrors := True;
  189. try
  190. inherited Destroy;
  191. finally
  192. vIgnoreOpenGLErrors := oldIgnore;
  193. FSimulatedValidity := False;
  194. end;
  195. FreeAndNil(FSDLWin);
  196. end;
  197. procedure TSDLContext.DoCreateContext(outputDevice: HDC);
  198. var
  199. sdlOpt: TSDLWindowOptions;
  200. begin
  201. // Just in case it didn't happen already.
  202. if not InitOpenGL then
  203. RaiseLastOSError;
  204. FSDLWin.Width := Width;
  205. FSDLWin.Height := Height;
  206. if ColorBits > 16 then
  207. FSDLWin.PixelDepth := vpd24bits
  208. else
  209. FSDLWin.PixelDepth := vpd16bits;
  210. sdlOpt := [voOpenGL, voHardwareAccel];
  211. if FullScreen then
  212. sdlOpt := sdlOpt + [voFullScreen]
  213. else
  214. sdlOpt := sdlOpt + [voResizable];
  215. if rcoDoubleBuffered in Options then
  216. sdlOpt := sdlOpt + [voDoubleBuffer];
  217. if StencilBits > 0 then
  218. sdlOpt := sdlOpt + [voStencilBuffer];
  219. FSDLWin.Open;
  220. if not FSDLWin.Active then
  221. raise Exception.Create('SDLWindow open failed.');
  222. FGL.Initialize;
  223. MakeGLCurrent;
  224. end;
  225. procedure TSDLContext.DoCreateMemoryContext(outputDevice: HWND; width, height: Integer; BufferCount: integer);
  226. begin
  227. raise Exception.Create(ClassName + ': Memory contexts not supported');
  228. end;
  229. function TSDLContext.DoShareLists(aContext: TGLContext): Boolean;
  230. begin
  231. // nothing (only one context at all times... no need to share)
  232. Result := False;
  233. end;
  234. procedure TSDLContext.DoDestroyContext;
  235. begin
  236. // Beware, SDL will also terminate the application
  237. FGL.Close;
  238. FSDLWin.Close;
  239. end;
  240. procedure TSDLContext.DoActivate;
  241. begin
  242. if not FGL.IsInitialized then
  243. FGL.Initialize;
  244. end;
  245. procedure TSDLContext.DoDeactivate;
  246. begin
  247. // nothing particular (only one context, always active)
  248. end;
  249. function TSDLContext.IsValid: Boolean;
  250. begin
  251. Result := (Assigned(FSDLWin) and (FSDLWin.Active)) or FSimulatedValidity;
  252. end;
  253. procedure TSDLContext.SwapBuffers;
  254. begin
  255. FSDLWin.SwapBuffers;
  256. end;
  257. function TSDLContext.RenderOutputDevice: Pointer;
  258. begin
  259. // unsupported
  260. Result := nil;
  261. end;
  262. procedure Register;
  263. begin
  264. RegisterComponents('GLScene', [TSDLViewer]);
  265. end;
  266. // ------------------------------------------------------------------
  267. initialization
  268. // ------------------------------------------------------------------
  269. RegisterClass(TSDLViewer);
  270. RegisterGLContextClass(TSDLContext);
  271. end.