SDLx.Context.pas 8.1 KB

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