2
// This unit is part of the GLScene Engine https://github.com/glscene
5
A Platform specific full-screen viewer.
7
Note: Eng: Lazarus has problems with minimizing and normalizing windows.
8
See code DoAvtivate DoDeactivate. Tests were conducted on
9
Lazarus 0.9.29.24627. If these problems are fixed in future versions
10
of FPC / Lazarus, you can safely remove work-arounds.
11
Note: Linux still has problems intercepting mouse events and problems
12
with DoActivate DoDeactivate.
14
 ëàçàðóñå åñòü ïðîáëåìû ìèíèìèçàöèè - íîðìàëèçàöèè îêíà.
15
Ñìîòðè êîä DoAvtivate DoDeactivate.
16
Òåñòû ïðîâîäèëèñü íà ëàçàðóñå 0.9.29.24627.
17
 ñëó÷àå óñòðàíåíèÿ ïðîáëåì â ëàçàðóñå,
18
óäàëèòå êîä ëàçàðóñà îñòàâèâ òîò êîòîðûé äëÿ äåëôè.
19
Ìîäóëü åùå íå çàêîí÷åí!  ëèíóêñå åñòü ïðîáëåìû ïåðåõâàòà ìûøè
20
è ïðîáëåìû ñ DoActivate DoDeactivate.
23
22/08/10 - DaStr - Restored backward-compatibility after previous changes
24
11/06/10 - Yar - Fixed uses section after lazarus-0.9.29.26033 release
25
28/04/10 - Yar - Merged GLFullScreenViewer and GLWin32FullScreenViewer into one unit
26
(by Rustam Asmandiarov aka Predator)
27
08/04/10 - Yar - Added more UNIX compatibility (thanks Rustam Asmandiarov aka Predator)
28
07/01/10 - DaStr - Added UNIX compatibility (thanks Predator)
29
07/11/09 - DaStr - Added to main GLScene CVS repository (from GLScene-Lazarus)
30
24/07/03 - EG - Creation from GLWin32Viewer split
33
unit GLFullScreenViewer;
40
Forms, Controls, Menus,
41
Classes, Messages, GLViewer, GLScene, GLContext,LcLtype, LCLIntf
51
TGLScreenDepth = (sd8bits, sd16bits, sd24bits, sd32bits);
53
// TGLFullScreenViewer
55
{ : A FullScreen viewer.
56
This non visual viewer will, when activated, use the full screen as rendering
57
surface. It will also switch/restore videomode depending on the required
59
This is performed by creating an underlying TForm and using its surface
60
for rendering OpenGL, "decent" ICDs will automatically use PageFlipping
61
instead of BlockTransfer (slower buffer flipping mode used for windowed
63
Note: if you terminate the application either via a kill or in the IDE,
64
the original resolution isn't restored. }
65
TGLFullScreenViewer = class(TGLNonVisualViewer)
68
FFormIsOwned: Boolean;
71
FScreenDepth: TGLScreenDepth;
73
FSwitchedResolution: Boolean;
74
FManualRendering: Boolean;
75
FUpdateCount: Integer;
76
FOnMouseDown: TMouseEvent;
77
FOnMouseUp: TMouseEvent;
78
FOnMouseMove: TMouseMoveEvent;
79
FOnMouseWheel: TMouseWheelEvent;
80
FOnMouseWheelDown: TMouseWheelUpDownEvent;
81
FOnMouseWheelUp: TMouseWheelUpDownEvent;
82
FOnClick, FOnDblClick: TNotifyEvent;
83
FOnKeyDown: TKeyEvent;
85
FOnKeyPress: TKeyPressEvent;
86
FOnClose: TCloseEvent;
87
FOnCloseQuery: TCloseQueryEvent;
90
FRefreshRate: Integer;
92
FPopupMenu: TPopupMenu;
93
procedure SetScreenDepth(const val: TGLScreenDepth);
94
procedure SetActive(const val: Boolean);
95
procedure SetOnMouseDown(const val: TMouseEvent);
96
procedure SetOnMouseUp(const val: TMouseEvent);
97
procedure SetOnMouseMove(const val: TMouseMoveEvent);
98
procedure SetOnMouseWheel(const val: TMouseWheelEvent);
99
procedure SetOnMouseWheelDown(const val: TMouseWheelUpDownEvent);
100
procedure SetOnMouseWheelUp(const val: TMouseWheelUpDownEvent);
101
procedure SetOnClick(const val: TNotifyEvent);
102
procedure SetOnDblClick(const val: TNotifyEvent);
103
procedure SetOnCloseQuery(const val: TCloseQueryEvent);
104
procedure SetOnClose(const val: TCloseEvent);
105
procedure SetOnKeyUp(const val: TKeyEvent);
106
procedure SetOnKeyDown(const val: TKeyEvent);
107
procedure SetOnKeyPress(const val: TKeyPressEvent);
108
procedure SetStayOnTop(const val: Boolean);
109
procedure SetCursor(const val: TCursor);
110
procedure SetPopupMenu(const val: TPopupMenu);
111
procedure SetForm(aVal: TForm);
112
procedure SetManualRendering(const val: Boolean);
115
function GetHandle: HWND;
117
procedure DoBeforeRender(Sender: TObject);
118
procedure DoBufferChange(Sender: TObject); override;
119
procedure DoBufferStructuralChange(Sender: TObject); override;
123
procedure BindFormEvents;
124
procedure DoCloseQuery(Sender: TObject; var CanClose: Boolean);
125
procedure DoPaint(Sender: TObject);
126
procedure DoActivate(Sender: TObject);
127
procedure DoDeactivate(Sender: TObject);
128
procedure DoFormDestroy(Sender: TObject);
131
constructor Create(AOwner: TComponent); override;
132
destructor Destroy; override;
134
procedure Render(baseObject: TGLBaseSceneObject = nil); override;
136
{ : Adjusts property so that current resolution will be used.
137
Call this method if you want to make sure video mode isn't switched. }
138
procedure UseCurrentResolution;
140
procedure BeginUpdate;
143
{ : Activates/deactivates full screen mode. }
144
property Active: Boolean read FActive write SetActive;
146
procedure ReActivate;
147
{ : Read access to the underlying form handle.
148
Returns 0 (zero) if the viewer is not active or has not yet
149
instantiated its form. }
150
property Handle: HWND read GetHandle;
152
procedure Notification(AComponent: TComponent;
153
Operation: TOperation); override;
155
function LastFrameTime: Single;
156
function FramesPerSecond: Single;
157
function FramesPerSecondText(decimals: Integer = 1): String;
158
procedure ResetPerformanceMonitor;
160
property RenderDC: HWND read FOwnDC;
163
property Form: TForm read FForm write SetForm;
165
property ManualRendering: Boolean read FManualRendering
166
write SetManualRendering;
168
// It is not used in UNIX
169
{ : Requested ScreenDepth. }
170
property ScreenDepth: TGLScreenDepth read FScreenDepth write SetScreenDepth
173
{ : Specifies if the underlying form is "fsStayOnTop".
174
The benefit of StayOnTop is that it hides the windows bar and
175
other background windows. The "fsStayOnTop" is automatically
176
switched off/on when the underlying form loses/gains focus.
177
It is recommended not to use StayOnTop while running in the IDE
178
or during the debugging phase. }
179
property StayOnTop: Boolean read FStayOnTop write SetStayOnTop
182
{ : Specifies if the refresh should be synchronized with the VSync signal.
183
If the underlying OpenGL ICD does not support the WGL_EXT_swap_control
184
extension, this property is ignored. }
185
property VSync: TVSyncMode read FVSync write FVSync default vsmSync;
186
{ : Screen refresh rate.
187
Use zero for system default. This property allows you to work around
188
the winxp bug that limits uses a refresh rate of 60hz when changeing
189
resolution. it is however suggested to give the user the opportunity
190
to adjust it instead of having a fixed value (expecially beyond
191
75hz or for resolutions beyond 1024x768).
192
the value will be automatically clamped to the highest value
193
*reported* compatible with the monitor. }
194
property RefreshRate: Integer read FRefreshRate write FRefreshRate;
196
property Cursor: TCursor read FCursor write SetCursor default crDefault;
197
property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
199
property OnClose: TCloseEvent read FOnClose write SetOnClose;
200
property OnKeyUp: TKeyEvent read FOnKeyUp write SetOnKeyUp;
201
property OnKeyDown: TKeyEvent read FOnKeyDown write SetOnKeyDown;
202
property OnKeyPress: TKeyPressEvent read FOnKeyPress write SetOnKeyPress;
203
property OnCloseQuery: TCloseQueryEvent read FOnCloseQuery
204
write SetOnCloseQuery;
205
property OnClick: TNotifyEvent read FOnClick write SetOnClick;
206
property OnDblClick: TNotifyEvent read FOnDblClick write SetOnDblClick;
207
property OnMouseDown: TMouseEvent read FOnMouseDown write SetOnMouseDown;
208
property OnMouseUp: TMouseEvent read FOnMouseUp write SetOnMouseUp;
209
property OnMouseMove: TMouseMoveEvent read FOnMouseMove
210
write SetOnMouseMove;
211
property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel
212
write SetOnMouseWheel;
213
property OnMouseWheelDown: TMouseWheelUpDownEvent read FOnMouseWheelDown
214
write SetOnMouseWheelDown;
215
property OnMouseWheelUp: TMouseWheelUpDownEvent read FOnMouseWheelUp
216
write SetOnMouseWheelUp;
221
// ------------------------------------------------------------------
222
// ------------------------------------------------------------------
223
// ------------------------------------------------------------------
226
// ------------------------------------------------------------------
227
// ------------------------------------------------------------------
228
// ------------------------------------------------------------------
230
uses OpenGLTokens, OpenGLAdapter, SysUtils, GLCrossPlatform, GLScreen
240
{$IF DEFINED(LCLWIN32) or DEFINED(LCLWIN64)}
241
{$IFNDEF CONTEXT_INCLUDED}
243
{$DEFINE CONTEXT_INCLUDED}
246
{$IF DEFINED(LCLGTK) or DEFINED(LCLGTK2)}
247
{$IFNDEF CONTEXT_INCLUDED}
249
{$DEFINE CONTEXT_INCLUDED}
256
{$ERROR unimplemented QT context}
262
cScreenDepthToBPP: array [sd8bits .. sd32bits] of Integer = (8, 16, 24, 32);
266
RegisterComponents('GLScene', [TGLFullScreenViewer]);
270
// ------------------ TGLFullScreenViewer ------------------
275
constructor TGLFullScreenViewer.Create(AOwner: TComponent);
277
inherited Create(AOwner);
280
FScreenDepth := sd32bits;
282
FCursor := crDefault;
283
Buffer.ViewerBeforeRender := DoBeforeRender;
288
destructor TGLFullScreenViewer.Destroy;
296
procedure TGLFullScreenViewer.DoBeforeRender(Sender: TObject);
303
procedure TGLFullScreenViewer.DoBufferChange(Sender: TObject);
305
if Assigned(FForm) and (not Buffer.Rendering) then
311
// DoBufferStructuralChange
313
procedure TGLFullScreenViewer.DoBufferStructuralChange(Sender: TObject);
315
if Active and (FUpdateCount = 0) then
321
procedure TGLFullScreenViewer.Render(baseObject: TGLBaseSceneObject = nil);
323
Buffer.Render(baseObject);
328
procedure TGLFullScreenViewer.BeginUpdate;
335
procedure TGLFullScreenViewer.EndUpdate;
338
if FUpdateCount = 0 then
341
DoBufferStructuralChange(Self)
343
else if FUpdateCount < 0 then
346
Assert(False, 'Unbalanced Begin/EndUpdate');
350
procedure TGLFullScreenViewer.ReActivate;
356
procedure TGLFullScreenViewer.Notification(AComponent: TComponent;
357
Operation: TOperation);
359
if (Operation = opRemove) and (Buffer <> nil) then
361
if (AComponent = Buffer.Camera) then
362
Buffer.Camera := nil;
364
if (AComponent = FForm) then
370
inherited Notification(AComponent, Operation);
373
function TGLFullScreenViewer.LastFrameTime: Single;
375
Result := Buffer.LastFrameTime;
378
function TGLFullScreenViewer.FramesPerSecond: Single;
380
Result := Buffer.FramesPerSecond;
383
function TGLFullScreenViewer.FramesPerSecondText(decimals: Integer): String;
385
Result := Format('%.*f FPS', [decimals, Buffer.FramesPerSecond]);
388
procedure TGLFullScreenViewer.ResetPerformanceMonitor;
390
Buffer.ResetPerformanceMonitor;
393
// UseCurrentResolution
395
procedure TGLFullScreenViewer.UseCurrentResolution;
399
Width := Screen.Width;
400
Height := Screen.Height;
401
case GetCurrentColorDepth of
403
ScreenDepth := sd24bits;
405
ScreenDepth := sd16bits;
407
ScreenDepth := sd8bits;
409
// highest depth possible otherwise
410
ScreenDepth := sd32bits;
419
procedure TGLFullScreenViewer.SetActive(const val: Boolean);
421
if val <> FActive then
424
// Alt+Tab delayed until better times
425
// {$IFDEF MSWindows}
426
// Application.OnDeactivate:=DoDeActivate;
427
// Application.OnActivate:=DoActivate;
439
procedure TGLFullScreenViewer.Startup;
448
FFormIsOwned := True;
449
FForm := TForm.Create(nil);
453
FFormIsOwned := False;
457
If BorderStyle <> bsNone then
458
BorderStyle := bsNone;
459
Cursor := Self.Cursor;
460
PopupMenu := Self.PopupMenu;
463
ClientWidth := Self.Width;
464
ClientHeight := Self.Height;
466
res := GetIndexFromResolution(Width, Height,
467
cScreenDepthToBPP[ScreenDepth]);
469
raise Exception.Create('Unsupported video mode');
471
FormStyle := fsStayOnTop
473
FormStyle := fsNormal;
475
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and
478
// WindowState:=wsMaximized;
480
if (Screen.Width <> Width) or (Screen.Height <> Height) or
481
(GetCurrentColorDepth <> cScreenDepthToBPP[ScreenDepth]) then
483
SetFullscreenMode(res, FRefreshRate);
484
FSwitchedResolution := True;
487
// Hides Taskbar + Windows 7 Button
488
ShowWindow(FindWindow('Shell_TrayWnd', nil), SW_HIDE);
489
ShowWindow(FindWindow('BUTTON', nil), SW_HIDE);
494
Buffer.Resize(0, 0, Width, Height);
495
FOwnDC := GetDC(FForm.Handle);
496
Buffer.CreateRC(FOwnDC, False);
499
GrabMouseToForm(FForm);
507
procedure TGLFullScreenViewer.Shutdown;
511
Assert(FForm <> nil);
520
ReleaseMouseFromForm(FForm);
523
// Restore Taskbar + Windows 7 Button
524
ShowWindow(FindWindow('Shell_TrayWnd', nil), SW_SHOWNA);
525
ShowWindow(FindWindow('BUTTON', nil), SW_SHOWNA);
527
// attempt that, at the very least...
528
if FSwitchedResolution then
538
procedure TGLFullScreenViewer.BindFormEvents;
540
if Assigned(FForm) then
543
OnMouseDown := FOnMouseDown;
544
OnMouseUp := FOnMouseUp;
545
OnMouseMove := FOnMouseMove;
546
OnMouseWheel := FOnMouseWheel;
547
OnMouseWheelDown := FOnMouseWheelDown;
548
OnMouseWheelUp := FOnMouseWheelUp;
550
OnDblClick := FOnDblClick;
551
OnCloseQuery := DoCloseQuery;
554
OnKeyDown := FOnKeyDown;
555
OnKeyPress := FOnKeyPress;
557
OnDestroy := DoFormDestroy;
563
procedure TGLFullScreenViewer.DoCloseQuery(Sender: TObject;
564
var CanClose: Boolean);
566
if Assigned(FOnCloseQuery) then
567
FOnCloseQuery(Sender, CanClose);
569
// if CanClose then Shutdown;
574
procedure TGLFullScreenViewer.DoPaint(Sender: TObject);
576
If not ManualRendering then
581
procedure TGLFullScreenViewer.DoActivate(Sender: TObject);
583
If not Active and (Form <> nil) then
589
procedure TGLFullScreenViewer.DoDeactivate(Sender: TObject);
591
If Active and (Form <> nil) then
595
Application.Minimize;
599
procedure TGLFullScreenViewer.DoFormDestroy(Sender: TObject);
606
procedure TGLFullScreenViewer.SetScreenDepth(const val: TGLScreenDepth);
608
if FScreenDepth <> val then
611
DoBufferStructuralChange(Self);
617
procedure TGLFullScreenViewer.SetStayOnTop(const val: Boolean);
619
if val <> FStayOnTop then
622
DoBufferStructuralChange(Self);
628
procedure TGLFullScreenViewer.SetOnCloseQuery(const val: TCloseQueryEvent);
630
FOnCloseQuery := val; // this one uses a special binding
635
procedure TGLFullScreenViewer.SetOnClose(const val: TCloseEvent);
644
procedure TGLFullScreenViewer.SetOnKeyPress(const val: TKeyPressEvent);
647
Form.OnKeyPress := val;
653
procedure TGLFullScreenViewer.SetOnKeyUp(const val: TKeyEvent);
662
procedure TGLFullScreenViewer.SetOnKeyDown(const val: TKeyEvent);
665
Form.OnKeyDown := val;
671
procedure TGLFullScreenViewer.SetOnMouseWheel(const val: TMouseWheelEvent);
674
Form.OnMouseWheel := val;
675
FOnMouseWheel := val;
678
// SetOnMouseWheelDown
680
procedure TGLFullScreenViewer.SetOnMouseWheelDown
681
(const val: TMouseWheelUpDownEvent);
684
Form.OnMouseWheelDown := val;
685
FOnMouseWheelDown := val;
690
procedure TGLFullScreenViewer.SetOnMouseWheelUp
691
(const val: TMouseWheelUpDownEvent);
694
Form.OnMouseWheelUp := val;
695
FOnMouseWheelUp := val;
700
procedure TGLFullScreenViewer.SetOnClick(const val: TNotifyEvent);
709
procedure TGLFullScreenViewer.SetOnDblClick(const val: TNotifyEvent);
712
Form.OnDblClick := val;
718
procedure TGLFullScreenViewer.SetOnMouseMove(const val: TMouseMoveEvent);
721
Form.OnMouseMove := val;
727
procedure TGLFullScreenViewer.SetOnMouseDown(const val: TMouseEvent);
730
Form.OnMouseDown := val;
736
procedure TGLFullScreenViewer.SetOnMouseUp(const val: TMouseEvent);
739
Form.OnMouseUp := val;
745
procedure TGLFullScreenViewer.SetCursor(const val: TCursor);
747
if val <> FCursor then
757
procedure TGLFullScreenViewer.SetPopupMenu(const val: TPopupMenu);
759
if val <> FPopupMenu then
762
if Assigned(FForm) then
763
FForm.PopupMenu := val;
767
procedure TGLFullScreenViewer.SetForm(aVal: TForm);
772
procedure TGLFullScreenViewer.SetManualRendering(const val: Boolean);
774
if FManualRendering <> val then
775
FManualRendering := val;
780
function TGLFullScreenViewer.GetHandle: HWND;
783
Result := FForm.Handle
788
// ------------------------------------------------------------------
789
// ------------------------------------------------------------------
790
// ------------------------------------------------------------------
793
// ------------------------------------------------------------------
794
// ------------------------------------------------------------------
795
// ------------------------------------------------------------------
797
RegisterClasses([TGLFullScreenViewer]);
802
// Restore Taskbar + Windows 7 Button
803
ShowWindow(FindWindow('Shell_TrayWnd', nil), SW_SHOWNA);
804
ShowWindow(FindWindow('BUTTON', nil), SW_SHOWNA);