123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit SDLx.Context;
- (*
- SDL specific Context and Viewer.
- NOTA: SDL notifies use of context destruction *after* it happened, this prevents
- clean release of allocated stuff and requires a temporary switch to
- "ignore OpenGL errors" mode during destruction, thus potentially
- leaking memory (depending on hardware drivers willingness to perform
- automatic releases)
- *)
- interface
- uses
- Winapi.Windows,
- System.Classes,
- System.SysUtils,
- SDL.Import,
- GXS.OpenGL,
- GXS.XOpenGL,
- GXS.Scene,
- GXS.Context,
- SDLx.Window;
- type
- (* A viewer using SDL.
- Beware: only one at a time, no other viewers allowed!
- Will also close the application when the window is closed! *)
- TgxSDLViewer = class(TgxNonVisualViewer)
- private
- FCaption: string;
- FOnSDLEvent: TgxSDLEvent;
- FOnEventPollDone: TNotifyEvent;
- FOnResize: TNotifyEvent;
- protected
- procedure SetCaption(const val: string);
- procedure DoOnOpen(sender: TObject);
- procedure DoOnClose(sender: TObject);
- procedure DoOnResize(sender: TObject);
- procedure DoOnSDLEvent(sender: TObject; const event: TSDL_Event);
- procedure DoOnEventPollDone(sender: TObject);
- procedure DoBufferStructuralChange(Sender: TObject); override;
- procedure PrepareVXContext; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Render(baseObject: TgxBaseSceneObject = nil); override;
- function Active: Boolean;
- published
- property Caption: string read FCaption write SetCaption;
- property OnResize: TNotifyEvent read FOnResize write FOnResize;
- { Fired whenever an SDL Event is polled.
- SDL_QUITEV and SDL_VIDEORESIZE are not passed to this event handler,
- they are passed via OnClose and OnResize respectively. }
- property OnSDLEvent: TgxSDLEvent read FOnSDLEvent write FOnSDLEvent;
- { Fired whenever an event polling completes with no events left to poll. }
- property OnEventPollDone: TNotifyEvent read FOnEventPollDone write FOnEventPollDone;
- end;
- { A context driver for OpenGL via SDL (libsdl.org).
- Due to limitations of SDL:
- you may have only one SDL window opened at any time (you cannot
- have memory viewers)
- closing the SDL window will terminate the application }
- TgxSDLContext = class(TgxScreenControlingContext)
- private
- FSDLWin: TgxSDLWindow;
- FSimulatedValidity: Boolean; // Hack around SDL's post-notified destruction of context
- protected
- procedure DoCreateContext(outputDevice : THandle); override;
- procedure DoCreateMemoryContext(OutputDevice:THandle; Width, Height: Integer; BufferCount: Integer = 1); override;
- function DoShareLists(aContext: TgxContext): Boolean; override;
- procedure DoDestroyContext; override;
- procedure DoActivate; override;
- procedure DoDeactivate; override;
- public
- constructor Create; override;
- destructor Destroy; override;
- function IsValid: Boolean; override;
- procedure SwapBuffers; override;
- function RenderOutputDevice: Pointer; override;
- property SDLWindow: TgxSDLWindow read FSDLWin;
- end;
- procedure Register;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- procedure Register;
- begin
- RegisterComponents('GXScene', [TgxSDLViewer]);
- end;
- // ------------------
- // ------------------ TgxSDLViewer ------------------
- // ------------------
- constructor TgxSDLViewer.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- Width := 640;
- Height := 480;
- end;
- destructor TgxSDLViewer.Destroy;
- begin
- inherited Destroy;
- end;
- procedure TgxSDLViewer.DoBufferStructuralChange(Sender: TObject);
- begin
- // ignore that, supporting it with SDL is not very praticable as of now...
- end;
- procedure TgxSDLViewer.PrepareVXContext;
- begin
- with Buffer.RenderingContext as TgxSDLContext do
- begin
- Width := Self.Width;
- Height := Self.Height;
- with FSDLWin do
- begin
- Caption := Self.Caption;
- OnOpen := DoOnOpen;
- OnClose := DoOnClose;
- OnResize := DoOnResize;
- OnSDLEvent := DoOnSDLEvent;
- OnEventPollDone := DoOnEventPollDone;
- end;
- end;
- end;
- procedure TgxSDLViewer.Render(baseObject: TgxBaseSceneObject = nil);
- begin
- InitOpenGL;
- if Buffer.RenderingContext = nil then
- begin
- Buffer.CreateRC(0, False);
- end;
- Buffer.Render(baseObject);
- end;
- function TgxSDLViewer.Active: Boolean;
- begin
- Result := Assigned(Buffer.RenderingContext) and Buffer.RenderingContext.IsValid;
- end;
- procedure TgxSDLViewer.SetCaption(const val: string);
- begin
- if val <> FCaption then
- begin
- FCaption := val;
- if Buffer.RenderingContext <> nil then
- with Buffer.RenderingContext as TgxSDLContext do
- if Assigned(FSDLWin) then
- FSDLWin.Caption := FCaption;
- end;
- end;
- procedure TgxSDLViewer.DoOnOpen(sender: TObject);
- begin
- // nothing yet
- end;
- procedure TgxSDLViewer.DoOnClose(sender: TObject);
- begin
- // nothing yet
- end;
- procedure TgxSDLViewer.DoOnResize(sender: TObject);
- begin
- with Buffer.RenderingContext as TgxSDLContext do
- begin
- Self.Width := FSDLWin.Width;
- Self.Height := FSDLWin.Height;
- Buffer.Resize(0, 0, FSDLWin.Width, FSDLWin.Height);
- end;
- if Assigned(FOnResize) then
- FOnResize(Self);
- end;
- procedure TgxSDLViewer.DoOnSDLEvent(sender: TObject; const event: TSDL_Event);
- begin
- if Assigned(FOnSDLEvent) then
- FOnSDLEvent(sender, event);
- end;
- procedure TgxSDLViewer.DoOnEventPollDone(sender: TObject);
- begin
- if Assigned(FOnEventPollDone) then
- FOnEventPollDone(sender);
- end;
- // ------------------
- // ------------------ TgxSDLContext ------------------
- // ------------------
- constructor TgxSDLContext.Create;
- begin
- inherited Create;
- FSDLWin := TgxSDLWindow.Create(nil);
- end;
- destructor TgxSDLContext.Destroy;
- var
- oldIgnore: Boolean;
- begin
- oldIgnore := vIgnoreOpenGXErrors;
- FSimulatedValidity := True;
- vIgnoreOpenGXErrors := True;
- try
- inherited Destroy;
- finally
- vIgnoreOpenGXErrors := oldIgnore;
- FSimulatedValidity := False;
- end;
- FreeAndNil(FSDLWin);
- end;
- procedure TgxSDLContext.DoCreateContext(outputDevice: THandle);
- var
- sdlOpt: TgxSDLWindowOptions;
- begin
- // Just in case it didn't happen already.
- if not InitOpenGL then
- RaiseLastOSError;
- FSDLWin.Width := Width;
- FSDLWin.Height := Height;
- if ColorBits > 16 then
- FSDLWin.PixelDepth := vpd24bits
- else
- FSDLWin.PixelDepth := vpd16bits;
- sdlOpt := [voOpenGL];
- if FullScreen then
- sdlOpt := sdlOpt + [voFullScreen]
- else
- sdlOpt := sdlOpt + [voResizable];
- if rcoDoubleBuffered in Options then
- sdlOpt := sdlOpt + [voDoubleBuffer];
- if StencilBits > 0 then
- sdlOpt := sdlOpt + [voStencilBuffer];
- FSDLWin.Open;
- if not FSDLWin.Active then
- raise Exception.Create('SDLWindow open failed.');
- xglMapTexCoordToNull;
- ReadExtensions;
- ReadImplementationProperties;
- xglMapTexCoordToMain;
- end;
- procedure TgxSDLContext.DoCreateMemoryContext(OutputDevice: THandle; Width, Height: // VCL ->HWND
- Integer; BufferCount: Integer = 1);
- begin
- raise Exception.Create(ClassName + ': Memory contexts not supported');
- end;
- function TgxSDLContext.DoShareLists(aContext: TgxContext): Boolean;
- begin
- // nothing (only one context at all times... no need to share)
- Result := False;
- end;
- procedure TgxSDLContext.DoDestroyContext;
- begin
- // Beware, SDL will also terminate the application
- FSDLWin.Close;
- end;
- procedure TgxSDLContext.DoActivate;
- begin
- // nothing particular (only one context, always active)
- end;
- procedure TgxSDLContext.DoDeactivate;
- begin
- // nothing particular (only one context, always active)
- end;
- function TgxSDLContext.IsValid: Boolean;
- begin
- Result := (Assigned(FSDLWin) and (FSDLWin.Active)) or FSimulatedValidity;
- end;
- procedure TgxSDLContext.SwapBuffers;
- begin
- FSDLWin.SwapBuffers;
- end;
- function TgxSDLContext.RenderOutputDevice: Pointer;
- begin
- // unsupported
- Result := nil;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClass(TgxSDLViewer);
- RegisterVXContextClass(TgxSDLContext);
- end.
|