123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- //
- // The multimedia graphics platform GLScene https://github.com/glscene
- //
- unit GLS.SceneForm;
- (* GLScene form loader *)
- interface
- {$I GLScene.inc}
- uses
- Winapi.Windows,
- Winapi.Messages,
- System.Classes,
- VCL.Controls,
- VCL.Forms,
- GLS.Scene,
- GLS.Context,
- GLS.Screen,
- GLS.SceneViewer;
- const
- lcl_major = 0;
- lcl_minor = 0;
- lcl_release = 0;
- type
- TGLSceneForm = class;
- (* Defines how GLSceneForm will handle fullscreen request
- fcWindowMaximize: Use current resolution (just maximize form and hide OS bars)
- fcNearestResolution: Change to nearest valid resolution from current window size
- fcManualResolution: Use FFullScreenVideoMode settings *)
- TGLFullScreenResolution = (
- fcUseCurrent,
- fcNearestResolution,
- fcManualResolution);
- // Screen mode settings
- TGLFullScreenVideoMode = class(TPersistent)
- private
- FOwner: TGLSceneForm;
- FEnabled: Boolean;
- FAltTabSupportEnable: Boolean;
- FWidth: Integer;
- FHeight: Integer;
- FColorDepth: Integer;
- FFrequency: Integer;
- FResolutionMode: TGLFullScreenResolution;
- procedure SetEnabled(aValue: Boolean);
- procedure SetAltTabSupportEnable(aValue: Boolean);
- public
- constructor Create(AOwner: TGLSceneForm);
- published
- property Enabled: Boolean read FEnabled write SetEnabled default False;
- property AltTabSupportEnable: Boolean read FAltTabSupportEnable
- write SetAltTabSupportEnable default False;
- property ResolutionMode: TGLFullScreenResolution read FResolutionMode
- write FResolutionMode default fcUseCurrent;
- property Width: Integer read FWidth write FWidth;
- property Height: Integer read FHeight write FHeight;
- property ColorDepth: Integer read FColorDepth write FColorDepth;
- property Frequency: Integer read FFrequency write FFrequency;
- end;
- TGLSceneForm = class(TForm)
- private
- FBuffer: TGLSceneBuffer;
- FVSync: TGLVSyncMode;
- FOwnDC: HDC;
- FFullScreenVideoMode: TGLFullScreenVideoMode;
- procedure SetBeforeRender(const val: TNotifyEvent);
- function GetBeforeRender: TNotifyEvent;
- procedure SetPostRender(const val: TNotifyEvent);
- function GetPostRender: TNotifyEvent;
- procedure SetAfterRender(const val: TNotifyEvent);
- function GetAfterRender: TNotifyEvent;
- procedure SetCamera(const val: TGLCamera);
- function GetCamera: TGLCamera;
- procedure SetBuffer(const val: TGLSceneBuffer);
- function GetFieldOfView: single;
- procedure SetFieldOfView(const Value: single);
- function GetIsRenderingContextAvailable: Boolean;
- procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
- procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
- procedure WMSize(var Message: TWMSize); message WM_SIZE;
- procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
- procedure LastFocus(var Mess: TMessage); message WM_ACTIVATE;
- procedure SetFullScreenVideoMode(AValue: TGLFullScreenVideoMode);
- procedure StartupFS;
- procedure ShutdownFS;
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation);
- override;
- procedure CreateWnd; override;
- procedure Loaded; override;
- procedure DoBeforeRender(Sender: TObject); virtual;
- procedure DoBufferChange(Sender: TObject); virtual;
- procedure DoBufferStructuralChange(Sender: TObject); virtual;
- procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DestroyWnd; override;
- property IsRenderingContextAvailable: Boolean read
- GetIsRenderingContextAvailable;
- property RenderDC: HDC read FOwnDC;
- published
- // Camera from which the scene is rendered.
- property Camera: TGLCamera read GetCamera write SetCamera;
- (* Specifies if the refresh should be synchronized with the VSync signal.
- If the underlying OpenGL ICD does not support the WGL_EXT_swap_control
- extension, this property is ignored. *)
- property VSync: TGLVSyncMode read FVSync write FVSync default vsmNoSync;
- (* Triggered before the scene's objects get rendered.
- You may use this event to execute your own OpenGL rendering. *)
- property BeforeRender: TNotifyEvent read GetBeforeRender write
- SetBeforeRender;
- (* Triggered just after all the scene's objects have been rendered.
- The OpenGL context is still active in this event, and you may use it
- to execute your own OpenGL rendering. *)
- property PostRender: TNotifyEvent read GetPostRender write SetPostRender;
- (* Called after rendering.
- You cannot issue OpenGL calls in this event, if you want to do your own
- OpenGL stuff, use the PostRender event. *)
- property AfterRender: TNotifyEvent read GetAfterRender write SetAfterRender;
- // Access to buffer properties.
- property Buffer: TGLSceneBuffer read FBuffer write SetBuffer;
- (* Returns or sets the field of view for the viewer, in degrees.
- This value depends on the camera and the width and height of the scene.
- The value isn't persisted, if the width/height or camera.focallength is
- changed, FieldOfView is changed also. *)
- property FieldOfView: single read GetFieldOfView write SetFieldOfView;
- property FullScreenVideoMode: TGLFullScreenVideoMode read
- FFullScreenVideoMode
- write SetFullScreenVideoMode;
- end;
- //-----------------------------------------------------------------
- implementation
- //-----------------------------------------------------------------
- constructor TGLSceneForm.Create(AOwner: TComponent);
- begin
- FBuffer := TGLSceneBuffer.Create(Self);
- FVSync := vsmNoSync;
- FBuffer.ViewerBeforeRender := DoBeforeRender;
- FBuffer.OnChange := DoBufferChange;
- FBuffer.OnStructuralChange := DoBufferStructuralChange;
- FFullScreenVideoMode := TGLFullScreenVideoMode.Create(Self);
- inherited Create(AOwner);
- end;
- destructor TGLSceneForm.Destroy;
- begin
- FBuffer.Free;
- FBuffer := nil;
- FFullScreenVideoMode.Destroy;
- inherited Destroy;
- end;
- procedure TGLSceneForm.Notification(AComponent: TComponent; Operation:
- TOperation);
- begin
- if (Operation = opRemove) and (FBuffer <> nil) then
- begin
- if (AComponent = FBuffer.Camera) then
- FBuffer.Camera := nil;
- end;
- inherited;
- end;
- procedure TGLSceneForm.CreateWnd;
- begin
- inherited CreateWnd;
- // initialize and activate the OpenGL rendering context
- // need to do this only once per window creation as we have a private DC
- FBuffer.Resize(0, 0, Self.Width, Self.Height);
- FOwnDC := GetDC(Handle);
- FBuffer.CreateRC(FOwnDC, false);
- end;
- procedure TGLSceneForm.DestroyWnd;
- begin
- if Assigned(FBuffer) then
- begin
- FBuffer.DestroyRC;
- if FOwnDC <> 0 then
- begin
- ReleaseDC(Handle, FOwnDC);
- FOwnDC := 0;
- end;
- end;
- inherited;
- end;
- procedure TGLSceneForm.Loaded;
- begin
- inherited Loaded;
- // initiate window creation
- HandleNeeded;
- if not (csDesigning in ComponentState) then
- begin
- if FFullScreenVideoMode.FEnabled then
- StartupFS;
- end;
- end;
- procedure TGLSceneForm.WMEraseBkgnd(var Message: TWMEraseBkgnd);
- begin
- if GetIsRenderingContextAvailable then
- Message.Result := 1
- else
- inherited;
- end;
- procedure TGLSceneForm.WMSize(var Message: TWMSize);
- begin
- inherited;
- if Assigned(FBuffer) then
- FBuffer.Resize(0, 0, Message.Width, Message.Height);
- end;
- procedure TGLSceneForm.WMPaint(var Message: TWMPaint);
- var
- PS: TPaintStruct;
- begin
- BeginPaint(Handle, PS);
- try
- if GetIsRenderingContextAvailable and (Width > 0) and (Height > 0) then
- FBuffer.Render;
- finally
- EndPaint(Handle, PS);
- Message.Result := 0;
- end;
- end;
- procedure TGLSceneForm.WMDestroy(var Message: TWMDestroy);
- begin
- if Assigned(FBuffer) then
- begin
- FBuffer.DestroyRC;
- if FOwnDC <> 0 then
- begin
- ReleaseDC(Handle, FOwnDC);
- FOwnDC := 0;
- end;
- end;
- inherited;
- end;
- procedure TGLSceneForm.LastFocus(var Mess: TMessage);
- begin
- if not (csDesigning in ComponentState)
- and FFullScreenVideoMode.FEnabled
- and FFullScreenVideoMode.FAltTabSupportEnable then
- begin
- if Mess.wParam = WA_INACTIVE then
- begin
- ShutdownFS;
- end
- else
- begin
- StartupFS;
- end;
- end;
- inherited;
- end;
- procedure TGLFullScreenVideoMode.SetEnabled(aValue: Boolean);
- begin
- if FEnabled <> aValue then
- begin
- FEnabled := aValue;
- if not ((csDesigning in FOwner.ComponentState)
- or (csLoading in FOwner.ComponentState)) then
- begin
- if FEnabled then
- FOwner.StartupFS
- else
- FOwner.ShutdownFS;
- end;
- end;
- end;
- constructor TGLFullScreenVideoMode.Create(AOwner: TGLSceneForm);
- begin
- inherited Create;
- FOwner := AOwner;
- FEnabled := False;
- FAltTabSupportEnable := False;
- ReadVideoModes;
- {$IFDEF MSWINDOWS}
- FWidth := vVideoModes[0].Width;
- FHeight := vVideoModes[0].Height;
- FColorDepth := vVideoModes[0].ColorDepth;
- FFrequency := vVideoModes[0].MaxFrequency;
- {$ENDIF}
- if FFrequency = 0 then
- FFrequency := 50;
- FResolutionMode := fcUseCurrent;
- end;
- procedure TGLFullScreenVideoMode.SetAltTabSupportEnable(aValue: Boolean);
- begin
- if FAltTabSupportEnable <> aValue then
- FAltTabSupportEnable := aValue;
- end;
- procedure TGLSceneForm.StartupFS;
- begin
- case FFullScreenVideoMode.FResolutionMode of
- fcNearestResolution:
- begin
- SetFullscreenMode(GetIndexFromResolution(ClientWidth, ClientHeight,
- {$IFDEF MSWINDOWS}
- vVideoModes[0].ColorDepth));
- {$ELSE}
- 32));
- {$ENDIF}
- end;
- fcManualResolution:
- begin
- SetFullscreenMode(GetIndexFromResolution(FFullScreenVideoMode.Width , FFullScreenVideoMode.Height, FFullScreenVideoMode.ColorDepth), FFullScreenVideoMode.Frequency);
- end;
- end;
- Left := 0;
- Top := 0;
- BorderStyle := bsNone;
- FormStyle := fsStayOnTop;
- BringToFront;
- WindowState := wsMaximized;
- Application.MainFormOnTaskBar := True;
- end;
- procedure TGLSceneForm.ShutdownFS;
- begin
- RestoreDefaultMode;
- SendToBack;
- WindowState := wsNormal;
- BorderStyle := bsSingle;
- FormStyle := fsNormal;
- Left := (Screen.Width div 2) - (Width div 2);
- Top := (Screen.Height div 2) - (Height div 2);
- end;
- procedure TGLSceneForm.DoBeforeRender(Sender: TObject);
- begin
- SetupVSync(VSync);
- end;
- procedure TGLSceneForm.DoBufferChange(Sender: TObject);
- begin
- if (not Buffer.Rendering) and (not Buffer.Freezed) then
- Invalidate;
- end;
- procedure TGLSceneForm.DoBufferStructuralChange(Sender: TObject);
- begin
- RecreateWnd;
- end;
- procedure TGLSceneForm.MouseMove(Shift: TShiftState; X, Y: Integer);
- begin
- inherited;
- if csDesignInteractive in ControlStyle then
- FBuffer.NotifyMouseMove(Shift, X, Y);
- end;
- procedure TGLSceneForm.SetBeforeRender(const val: TNotifyEvent);
- begin
- FBuffer.BeforeRender := val;
- end;
- function TGLSceneForm.GetBeforeRender: TNotifyEvent;
- begin
- Result := FBuffer.BeforeRender;
- end;
- procedure TGLSceneForm.SetPostRender(const val: TNotifyEvent);
- begin
- FBuffer.PostRender := val;
- end;
- function TGLSceneForm.GetPostRender: TNotifyEvent;
- begin
- Result := FBuffer.PostRender;
- end;
- procedure TGLSceneForm.SetAfterRender(const val: TNotifyEvent);
- begin
- FBuffer.AfterRender := val;
- end;
- function TGLSceneForm.GetAfterRender: TNotifyEvent;
- begin
- Result := FBuffer.AfterRender;
- end;
- procedure TGLSceneForm.SetCamera(const val: TGLCamera);
- begin
- FBuffer.Camera := val;
- end;
- function TGLSceneForm.GetCamera: TGLCamera;
- begin
- Result := FBuffer.Camera;
- end;
- procedure TGLSceneForm.SetBuffer(const val: TGLSceneBuffer);
- begin
- FBuffer.Assign(val);
- end;
- function TGLSceneForm.GetFieldOfView: single;
- begin
- if not Assigned(Camera) then
- Result := 0
- else if Width < Height then
- Result := Camera.GetFieldOfView(Width)
- else
- Result := Camera.GetFieldOfView(Height);
- end;
- procedure TGLSceneForm.SetFieldOfView(const Value: single);
- begin
- if Assigned(Camera) then
- begin
- if Width < Height then
- Camera.SetFieldOfView(Value, Width)
- else
- Camera.SetFieldOfView(Value, Height);
- end;
- end;
- procedure TGLSceneForm.SetFullScreenVideoMode(AValue: TGLFullScreenVideoMode);
- begin
- end;
- function TGLSceneForm.GetIsRenderingContextAvailable: Boolean;
- begin
- Result := FBuffer.RCInstantiated and FBuffer.RenderingContext.IsValid;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClass(TGLSceneForm);
- end.
|