123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.FullScreenViewer;
- (* A cross-platform full-screen viewer *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.Messages,
- Winapi.Windows,
- System.Classes,
- System.SysUtils,
- FMX.Types,
- FMX.Forms,
- FMX.Controls,
- FMX.Menus,
- GXS.Scene,
- GXS.Context,
- GXS.SceneViewer,
- GXS.WinContext,
- GXS.ImageUtils,
- GXS.Screen;
- type
- TgxScreenDepth = (sd8bits, sd16bits, sd24bits, sd32bits);
- { A FullScreen viewer.
- This non visual viewer will, when activated, use the full screen as rendering
- surface. It will also switch/restore videomode depending on the required
- width/height.
- This is performed by creating an underlying TForm and using its surface
- for rendering OpenGL, "decent" ICDs will automatically use PageFlipping
- instead of BlockTransfer (slower buffer flipping mode used for windowed
- OpenGL).
- Note: if you terminate the application either via a kill or in the IDE,
- the original resolution isn't restored. }
- TgxFullScreenViewer = class(TgxNonVisualViewer)
- private
- FFormIsOwned: Boolean;
- FForm: TForm;
- FOwnDC: THandle; // in VCL HWND;
- FScreenDepth: TgxScreenDepth;
- FActive: Boolean;
- FSwitchedResolution: Boolean;
- FManualRendering: Boolean;
- FUpdateCount: Integer;
- FOnMouseDown: TMouseEvent;
- FOnMouseUp: TMouseEvent;
- FOnMouseMove: TMouseMoveEvent;
- FOnMouseWheel: TMouseWheelEvent; // in VCL TMouseWheelEvent;
- FOnMouseWheelDown: TMouseWheelEvent; // in VCL TMouseWheelUpDownEvent;
- FOnMouseWheelUp: TMouseWheelEvent; // in VCL TMouseWheelUpDownEvent;
- FOnClick, FOnDblClick: TNotifyEvent;
- FOnKeyDown: TKeyEvent;
- FOnKeyUp: TKeyEvent;
- FOnKeyPress: TKeyEvent; // In VCL TKeyPressEvent;
- FOnClose: TCloseEvent;
- FOnCloseQuery: TCloseQueryEvent;
- FStayOnTop: Boolean;
- FVSync: TgxSyncMode;
- FRefreshRate: Integer;
- { TODO : E2003 Undeclared identifier: 'TCursor' }
- (*FCursor: TCursor;*)
- FPopupMenu: TPopupMenu;
- procedure SetScreenDepth(const val: TgxScreenDepth);
- procedure SetActive(const val: Boolean);
- procedure SetOnMouseDown(const val: TMouseEvent);
- procedure SetOnMouseUp(const val: TMouseEvent);
- procedure SetOnMouseMove(const val: TMouseMoveEvent);
- procedure SetOnMouseWheel(const val: TMouseWheelEvent);
- procedure SetOnMouseWheelDown(const val: TMouseWheelEvent); //in VCL TMouseWheelUpDownEvent
- procedure SetOnMouseWheelUp(const val: TMouseWheelEvent); //in VCL TMouseWheelUpDownEvent
- procedure SetOnClick(const val: TNotifyEvent);
- procedure SetOnDblClick(const val: TNotifyEvent);
- procedure SetOnCloseQuery(const val: TCloseQueryEvent);
- procedure SetOnClose(const val: TCloseEvent);
- procedure SetOnKeyUp(const val: TKeyEvent);
- procedure SetOnKeyDown(const val: TKeyEvent);
- procedure SetOnKeyPress(const val: TKeyEvent); // in VCL TKeyPressEvent
- procedure SetStayOnTop(const val: Boolean);
- { TODO : E2003 Undeclared identifier: 'TCursor' }
- (*procedure SetCursor(const val: TCursor);*)
- procedure SetPopupMenu(const val: TPopupMenu);
- procedure SetForm(aVal: TForm);
- procedure SetManualRendering(const val: Boolean);
- protected
- function GetHandle: TWindowHandle;
- procedure DoBeforeRender(Sender: TObject);
- procedure DoBufferChange(Sender: TObject); override;
- procedure DoBufferStructuralChange(Sender: TObject); override;
- procedure Startup;
- procedure Shutdown;
- procedure BindFormEvents;
- procedure DoCloseQuery(Sender: TObject; var CanClose: Boolean);
- procedure DoPaint(Sender: TObject);
- procedure DoActivate(Sender: TObject);
- procedure DoDeactivate(Sender: TObject);
- procedure DoFormDestroy(Sender: TObject);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Render(baseObject: TgxBaseSceneObject = nil); override;
- { Adjusts property so that current resolution will be used.
- Call this method if you want to make sure video mode isn't switched. }
- procedure UseCurrentResolution;
- procedure BeginUpdate;
- procedure EndUpdate;
- { Activates/deactivates full screen mode. }
- property Active: Boolean read FActive write SetActive;
- procedure ReActivate;
- { Read access to the underlying form handle.
- Returns 0 (zero) if the viewer is not active or has not yet
- instantiated its form. }
- property Handle: TWindowHandle read GetHandle;
- procedure Notification(AComponent: TComponent;
- Operation: TOperation); override;
- function LastFrameTime: Single;
- function FramesPerSecond: Single;
- function FramesPerSecondText(decimals: Integer = 1): String;
- procedure ResetPerformanceMonitor;
- property RenderDC: THandle read FOwnDC; //HWND
- published
- property Form: TForm read FForm write SetForm;
- property ManualRendering: Boolean read FManualRendering
- write SetManualRendering;
- // It is not used in UNIX
- { Requested ScreenDepth. }
- property ScreenDepth: TgxScreenDepth read FScreenDepth write SetScreenDepth
- default sd32bits;
- { Specifies if the underlying form is "fsStayOnTop".
- The benefit of StayOnTop is that it hides the windows bar and
- other background windows. The "fsStayOnTop" is automatically
- switched off/on when the underlying form loses/gains focus.
- It is recommended not to use StayOnTop while running in the IDE
- or during the debugging phase. }
- property StayOnTop: Boolean read FStayOnTop write SetStayOnTop
- default False;
- { 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: TgxSyncMode read FVSync write FVSync default vsmSync;
- { Screen refresh rate.
- Use zero for system default. This property allows you to work around
- the winxp bug that limits uses a refresh rate of 60hz when changeing
- resolution. it is however suggested to give the user the opportunity
- to adjust it instead of having a fixed value (expecially beyond
- 75hz or for resolutions beyond 1024x768).
- the value will be automatically clamped to the highest value
- *reported* compatible with the monitor. }
- property RefreshRate: Integer read FRefreshRate write FRefreshRate;
- { TODO : E2003 Undeclared identifier: 'TCursor' }
- (*property Cursor: TCursor read FCursor write SetCursor default crDefault;*)
- property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
- property OnClose: TCloseEvent read FOnClose write SetOnClose;
- property OnKeyUp: TKeyEvent read FOnKeyUp write SetOnKeyUp;
- property OnKeyDown: TKeyEvent read FOnKeyDown write SetOnKeyDown;
- property OnKeyPress: TKeyEvent read FOnKeyPress write SetOnKeyPress;
- property OnCloseQuery: TCloseQueryEvent read FOnCloseQuery
- write SetOnCloseQuery;
- property OnClick: TNotifyEvent read FOnClick write SetOnClick;
- property OnDblClick: TNotifyEvent read FOnDblClick write SetOnDblClick;
- property OnMouseDown: TMouseEvent read FOnMouseDown write SetOnMouseDown;
- property OnMouseUp: TMouseEvent read FOnMouseUp write SetOnMouseUp;
- property OnMouseMove: TMouseMoveEvent read FOnMouseMove
- write SetOnMouseMove;
- property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel
- write SetOnMouseWheel;
- property OnMouseWheelDown: TMouseWheelEvent read FOnMouseWheelDown
- write SetOnMouseWheelDown;
- property OnMouseWheelUp: TMouseWheelEvent read FOnMouseWheelUp
- write SetOnMouseWheelUp;
- end;
- procedure Register;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- const
- cScreenDepthToBPP: array [sd8bits .. sd32bits] of Integer = (8, 16, 24, 32);
- procedure Register;
- begin
- RegisterComponents('GXScene', [TgxFullScreenViewer]);
- end;
- // ------------------
- // ------------------ TgxFullScreenViewer ------------------
- // ------------------
- constructor TgxFullScreenViewer.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- Width := 800;
- Height := 600;
- FScreenDepth := sd32bits;
- FVSync := vsmSync;
- { TODO : E2003 Undeclared identifier: 'TCursor' }
- (*FCursor := crDefault;*)
- Buffer.ViewerBeforeRender := DoBeforeRender;
- end;
- destructor TgxFullScreenViewer.Destroy;
- begin
- Active := False;
- inherited Destroy;
- end;
- procedure TgxFullScreenViewer.DoBeforeRender(Sender: TObject);
- begin
- SetupVSync(VSync);
- end;
- procedure TgxFullScreenViewer.DoBufferChange(Sender: TObject);
- begin
- if Assigned(FForm) and (not Buffer.Rendering) then
- begin
- Buffer.Render;
- end;
- end;
- procedure TgxFullScreenViewer.DoBufferStructuralChange(Sender: TObject);
- begin
- if Active and (FUpdateCount = 0) then
- ReActivate
- end;
- procedure TgxFullScreenViewer.Render(baseObject: TgxBaseSceneObject = nil);
- begin
- Buffer.Render(baseObject);
- end;
- procedure TgxFullScreenViewer.BeginUpdate;
- begin
- Inc(FUpdateCount);
- end;
- procedure TgxFullScreenViewer.EndUpdate;
- begin
- Dec(FUpdateCount);
- if FUpdateCount = 0 then
- begin
- if Active then
- DoBufferStructuralChange(Self)
- end
- else if FUpdateCount < 0 then
- begin
- FUpdateCount := 0;
- Assert(False, 'Unbalanced Begin/EndUpdate');
- end;
- end;
- procedure TgxFullScreenViewer.ReActivate;
- begin
- Shutdown;
- Startup;
- end;
- procedure TgxFullScreenViewer.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- if (Operation = opRemove) and (Buffer <> nil) then
- begin
- if (AComponent = Buffer.Camera) then
- Buffer.Camera := nil;
- Active := False;
- if (AComponent = FForm) then
- begin
- Active := False;
- Form := nil;
- end;
- end;
- inherited Notification(AComponent, Operation);
- end;
- function TgxFullScreenViewer.LastFrameTime: Single;
- begin
- Result := Buffer.LastFrameTime;
- end;
- function TgxFullScreenViewer.FramesPerSecond: Single;
- begin
- Result := Buffer.FramesPerSecond;
- end;
- function TgxFullScreenViewer.FramesPerSecondText(decimals: Integer): String;
- begin
- Result := Format('%.*f FPS', [decimals, Buffer.FramesPerSecond]);
- end;
- procedure TgxFullScreenViewer.ResetPerformanceMonitor;
- begin
- Buffer.ResetPerformanceMonitor;
- end;
- procedure TgxFullScreenViewer.UseCurrentResolution;
- begin
- BeginUpdate;
- try
- Width := Trunc(Screen.Width);
- Height := Trunc(Screen.Height);
- case GetCurrentColorDepth of
- 24: ScreenDepth := sd24bits;
- 16: ScreenDepth := sd16bits;
- 8: ScreenDepth := sd8bits;
- else
- // highest depth possible otherwise
- ScreenDepth := sd32bits;
- end;
- finally
- EndUpdate;
- end;
- end;
- procedure TgxFullScreenViewer.SetActive(const val: Boolean);
- begin
- if val <> FActive then
- begin
- // Alt+Tab delayed until better times
- // {$IFDEF MSWindows}
- // Application.OnDeactivate:=DoDeActivate;
- // Application.OnActivate:=DoActivate;
- // {$ENDIF}
- if val then
- Startup
- else
- Shutdown;
- end;
- end;
- procedure TgxFullScreenViewer.Startup;
- var
- res: TResolution;
- begin
- if FActive then
- Exit;
- if FForm = nil then
- begin
- FFormIsOwned := True;
- FForm := TForm.Create(nil);
- FForm.Show();
- end
- else
- FFormIsOwned := False;
- with FForm do
- begin
- If BorderStyle <> TFmxFormBorderStyle.None then
- BorderStyle := TFmxFormBorderStyle.None;
- { TODO : E2003 Undeclared identifier: 'Cursor' }
- (*Cursor := Self.Cursor;*)
- PopupMenu := Self.PopupMenu;
- Left := 0;
- Top := 0;
- ClientWidth := Self.Width;
- ClientHeight := Self.Height;
- BindFormEvents;
- res := GetIndexFromResolution(Width, Height,
- cScreenDepthToBPP[ScreenDepth]);
- if res = 0 then
- raise Exception.Create('Unsupported video mode');
- if StayOnTop then
- FormStyle := TFormStyle.StayOnTop
- else
- FormStyle := TFormStyle.Normal;
- { TODO : E2010 Incompatible types: 'HWND' and 'TWindowHandle' }
- (*
- SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and
- not WS_CAPTION);
- *)
- // WindowState:=wsMaximized;
- // Switch video mode
- if (Screen.Width <> Width) or (Screen.Height <> Height) or
- (GetCurrentColorDepth <> cScreenDepthToBPP[ScreenDepth]) then
- begin
- SetFullscreenMode(res, FRefreshRate);
- FSwitchedResolution := True;
- end;
- // Hides Taskbar + Windows 7 Button
- ShowWindow(FindWindow('Shell_TrayWnd', nil), SW_HIDE);
- ShowWindow(FindWindow('BUTTON', nil), SW_HIDE);
- // Show;
- end;
- Buffer.Resize(0, 0, Width, Height);
- { TODO : E2010 Incompatible types: 'HWND' and 'TWindowHandle' }
- (*FOwnDC := GetDC(FForm.Handle);*)
- Buffer.CreateRC(FOwnDC, False);
- // Linux Unicode
- {$IFDEF Linux}
- GrabMouseToForm(FForm);
- {$ENDIF}
- // todo
- FActive := True;
- end;
- procedure TgxFullScreenViewer.Shutdown;
- begin
- if not FActive then
- Exit;
- Assert(FForm <> nil);
- Buffer.DestroyRC;
- with FForm do
- begin
- { TODO : E2003 Undeclared identifier: 'crDefault' }
- (*Cursor := crDefault;*)
- PopupMenu := nil;
- end;
- // Restore Taskbar + Windows 7 Button
- ShowWindow(FindWindow('Shell_TrayWnd', nil), SW_SHOWNA);
- ShowWindow(FindWindow('BUTTON', nil), SW_SHOWNA);
- // attempt that, at the very least...
- if FSwitchedResolution then
- RestoreDefaultMode;
- FActive := False;
- if FFormIsOwned then
- FreeAndNil(FForm);
- end;
- procedure TgxFullScreenViewer.BindFormEvents;
- begin
- if Assigned(FForm) then
- with FForm do
- begin
- OnMouseDown := FOnMouseDown;
- OnMouseUp := FOnMouseUp;
- OnMouseMove := FOnMouseMove;
- OnMouseWheel := FOnMouseWheel;
- OnMouseWheelDown := FOnMouseWheelDown;
- OnMouseWheelUp := FOnMouseWheelUp;
- OnClick := FOnClick;
- OnDblClick := FOnDblClick;
- OnCloseQuery := DoCloseQuery;
- OnClose := FOnClose;
- OnKeyUp := FOnKeyUp;
- OnKeyDown := FOnKeyDown;
- OnKeyPress := FOnKeyPress;
- { TODO : E2009 Incompatible types: 'Parameter lists differ' }
- (*OnPaint := DoPaint;*)
- OnDestroy := DoFormDestroy;
- end;
- end;
- procedure TgxFullScreenViewer.DoCloseQuery(Sender: TObject;
- var CanClose: Boolean);
- begin
- if Assigned(FOnCloseQuery) then
- FOnCloseQuery(Sender, CanClose);
- CanClose := True;
- // if CanClose then Shutdown;
- end;
- procedure TgxFullScreenViewer.DoPaint(Sender: TObject);
- begin
- If not ManualRendering then
- if Form <> nil then
- Render;
- end;
- procedure TgxFullScreenViewer.DoActivate(Sender: TObject);
- begin
- (* If not Active and (Form <> nil) then begin
- Startup;
- end; *)
- end;
- procedure TgxFullScreenViewer.DoDeactivate(Sender: TObject);
- begin
- (* If Active and (Form <> nil) then begin
- Shutdown;
- Form.Height:=0;
- Form.Width:=0;
- end; *)
- end;
- procedure TgxFullScreenViewer.DoFormDestroy(Sender: TObject);
- begin
- Active := False;
- end;
- procedure TgxFullScreenViewer.SetScreenDepth(const val: TgxScreenDepth);
- begin
- if FScreenDepth <> val then
- begin
- FScreenDepth := val;
- DoBufferStructuralChange(Self);
- end;
- end;
- procedure TgxFullScreenViewer.SetStayOnTop(const val: Boolean);
- begin
- if val <> FStayOnTop then
- begin
- FStayOnTop := val;
- DoBufferStructuralChange(Self);
- end;
- end;
- procedure TgxFullScreenViewer.SetOnCloseQuery(const val: TCloseQueryEvent);
- begin
- FOnCloseQuery := val; // this one uses a special binding
- end;
- procedure TgxFullScreenViewer.SetOnClose(const val: TCloseEvent);
- begin
- If Form <> nil then
- Form.OnClose := val;
- FOnClose := val;
- end;
- procedure TgxFullScreenViewer.SetOnKeyPress(const val: TKeyEvent); //VCL - TKeyPressEvent
- begin
- If Form <> nil then
- Form.OnKeyDown := val;
- FOnKeyPress := val;
- end;
- procedure TgxFullScreenViewer.SetOnKeyUp(const val: TKeyEvent);
- begin
- If Form <> nil then
- Form.OnKeyUp := val;
- FOnKeyUp := val;
- end;
- procedure TgxFullScreenViewer.SetOnKeyDown(const val: TKeyEvent);
- begin
- If Form <> nil then
- Form.OnKeyDown := val;
- FOnKeyDown := val;
- end;
- procedure TgxFullScreenViewer.SetOnMouseWheel(const val: TMouseWheelEvent);
- begin
- If Form <> nil then
- Form.OnMouseWheel := val;
- FOnMouseWheel := val;
- end;
- procedure TgxFullScreenViewer.SetOnMouseWheelDown
- (const val: TMouseWheelEvent);
- begin
- If Form <> nil then
- Form.OnMouseWheel := val;
- FOnMouseWheelDown := val;
- end;
- procedure TgxFullScreenViewer.SetOnMouseWheelUp(const val: TMouseWheelEvent);
- begin
- If Form <> nil then
- Form.OnMouseWheel := val;
- FOnMouseWheelUp := val;
- end;
- procedure TgxFullScreenViewer.SetOnClick(const val: TNotifyEvent);
- begin
- If Form <> nil then
- { TODO : E2003 Undeclared identifier: 'OnClick' }
- (*Form.OnClick := val;*)
- FOnClick := val;
- end;
- procedure TgxFullScreenViewer.SetOnDblClick(const val: TNotifyEvent);
- begin
- If Form <> nil then
- { TODO : E2003 Undeclared identifier: 'OnDblClick' }
- (*Form.OnDblClick := val;*)
- FOnDblClick := val;
- end;
- procedure TgxFullScreenViewer.SetOnMouseMove(const val: TMouseMoveEvent);
- begin
- If Form <> nil then
- Form.OnMouseMove := val;
- FOnMouseMove := val;
- end;
- procedure TgxFullScreenViewer.SetOnMouseDown(const val: TMouseEvent);
- begin
- If Form <> nil then
- Form.OnMouseDown := val;
- FOnMouseDown := val;
- end;
- procedure TgxFullScreenViewer.SetOnMouseUp(const val: TMouseEvent);
- begin
- If Form <> nil then
- Form.OnMouseUp := val;
- FOnMouseUp := val;
- end;
- (*
- procedure TgxFullScreenViewer.SetCursor(const val: TCursor);
- begin
- if val <> FCursor then
- begin
- FCursor := val;
- if Form <> nil then
- FForm.Cursor := val;
- end;
- end;
- *)
- procedure TgxFullScreenViewer.SetPopupMenu(const val: TPopupMenu);
- begin
- if val <> FPopupMenu then
- begin
- FPopupMenu := val;
- if Assigned(FForm) then
- { TODO : E2003 Undeclared identifier: 'PopupMenu' }
- (*FForm.PopupMenu := val;*)
- end;
- end;
- procedure TgxFullScreenViewer.SetForm(aVal: TForm);
- begin
- FForm := aVal;
- end;
- procedure TgxFullScreenViewer.SetManualRendering(const val: Boolean);
- begin
- if FManualRendering <> val then
- FManualRendering := val;
- end;
- function TgxFullScreenViewer.GetHandle: TWindowHandle;
- begin
- if Form <> nil then
- Result := FForm.Handle
- else
- Result := nil;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClasses([TgxFullScreenViewer]);
- finalization
- // Restore Taskbar + Windows 7 Button
- ShowWindow(FindWindow('Shell_TrayWnd', nil), SW_SHOWNA);
- ShowWindow(FindWindow('BUTTON', nil), SW_SHOWNA);
- end.
|