1
unit LUX.GPU.OpenGL.Viewer;
11
FMX.Types, FMX.Graphics,
12
FMX.Controls, FMX.Forms,
13
FMX.Dialogs, FMX.StdCtrls,
20
LUX.GPU.OpenGL.Window,
21
LUX.GPU.OpenGL.Atom.Buffer.UniBuf,
22
LUX.GPU.OpenGL.Scener,
23
LUX.GPU.OpenGL.Camera;
26
TGLViewer = class(TFrame)
28
procedure GoMouseClick(Sender_: TObject; Button_: TMouseButton;
29
Shift_: TShiftState; X_, Y_: Single);
30
procedure GoMouseDown(Sender_: TObject; Button_: TMouseButton;
31
Shift_: TShiftState; X_, Y_: Single); inline;
32
procedure GoMouseMove(Sender_: TObject; Shift_: TShiftState;
33
X_, Y_: Single); inline;
34
procedure GoMouseUp(Sender_: TObject; Button_: TMouseButton;
35
Shift_: TShiftState; X_, Y_: Single); inline;
36
procedure GoMouseWheel(Sender_: TObject; Shift_: TShiftState;
37
WheelDelta_: Integer; var Handled_: Boolean); inline;
38
procedure OnCreateAnyWND(const Sender_: TObject; const Message_: TMessage);
39
procedure OnDestroAnyWND(const Sender_: TObject; const Message_: TMessage);
41
_RootForm: FMX.Forms.TCommonCustomForm;
43
_Viewer: TGLUniBuf<TSingleM4>;
45
_BackColor: TAlphaColorF;
47
class function GetScreenScale: Single;
48
function GetRootForm: TForm;
49
function GetPxSize: System.Types.TSize;
50
procedure DoAbsoluteChanged; override;
51
procedure ParentChanged; override;
52
procedure Paint; override;
53
procedure Resize; override;
54
procedure AncestorVisibleChanged(const Visible_: Boolean); override;
55
procedure AncestorParentChanged; override;
56
procedure CreateWindow;
57
procedure DestroWindow;
60
constructor Create(AOwner_: TComponent); override;
61
destructor Destroy; override;
62
property PxSize: System.Types.TSize read GetPxSize;
63
property Camera: TGLCamera read _Camera write _Camera;
64
property BackColor: TAlphaColorF read _BackColor write _BackColor;
65
property OnPaint: TProc read _OnPaint write _OnPaint;
67
procedure BeginRender;
69
function MakeScreenShot: FMX.Graphics.TBitmap;
70
function ShootRay(const X_, Y_: Single): TSingleRay3D;
71
function PickObject(const X_, Y_: Single): TGLObject;
74
implementation //------------------------------------------------------------
80
Winapi.OpenGL, Winapi.OpenGLext;
82
procedure TGLViewer.GoMouseClick(Sender_: TObject; Button_: TMouseButton;
83
Shift_: TShiftState; X_, Y_: Single);
85
MouseClick(Button_, Shift_, X_, Y_);
88
procedure TGLViewer.GoMouseDown(Sender_: TObject; Button_: TMouseButton;
89
Shift_: TShiftState; X_, Y_: Single);
93
MouseDown(Button_, Shift_, X_, Y_);
96
procedure TGLViewer.GoMouseMove(Sender_: TObject; Shift_: TShiftState;
99
MouseMove(Shift_, X_, Y_);
102
procedure TGLViewer.GoMouseUp(Sender_: TObject; Button_: TMouseButton;
103
Shift_: TShiftState; X_, Y_: Single);
105
MouseUp(Button_, Shift_, X_, Y_);
107
_Form.ReleaseCapture;
110
procedure TGLViewer.GoMouseWheel(Sender_: TObject; Shift_: TShiftState;
111
WheelDelta_: Integer; var Handled_: Boolean);
113
MouseWheel(Shift_, WheelDelta_, Handled_);
116
procedure TGLViewer.OnCreateAnyWND(const Sender_: TObject;
117
const Message_: TMessage);
119
if Sender_ = _RootForm then
121
Assert(not Assigned(_Form),
122
'Failed! _Form is not nil. @ TGLViewer.OnCreateAnyWND');
126
_Form.Parent := Self;
132
procedure TGLViewer.OnDestroAnyWND(const Sender_: TObject;
133
const Message_: TMessage);
135
if Sender_ = _RootForm then
141
class function TGLViewer.GetScreenScale: Single;
143
S: IFMXScreenService;
145
if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService,
147
Result := S.GetScreenScale
152
// ------------------------------------------------------------------------------
154
function TGLViewer.GetRootForm: TForm;
156
if Assigned(Root) and (Root.GetObject is TForm) then
158
Result := Root.GetObject as TForm;
164
// ------------------------------------------------------------------------------
166
function TGLViewer.GetPxSize: System.Types.TSize;
170
Width := Round(_Form.Width * GetScreenScale);
171
Height := Round(_Form.Height * GetScreenScale);
175
procedure TGLViewer.DoAbsoluteChanged;
181
procedure TGLViewer.ParentChanged;
184
_RootForm := GetRootForm;
185
_Form.Parent := Self;
188
procedure TGLViewer.Paint;
192
glViewport(0, 0, Width, Height);
193
if Assigned(_Camera) then
199
procedure TGLViewer.Resize;
203
if Assigned(Parent) then
207
procedure TGLViewer.AncestorVisibleChanged(const Visible_: Boolean);
210
_Form.Visible := ParentedVisible;
213
procedure TGLViewer.AncestorParentChanged;
216
_RootForm := GetRootForm;
217
_Form.Parent := Self;
220
// ------------------------------------------------------------------------------
222
procedure TGLViewer.CreateWindow;
224
_Form := TGLViewerForm.CreateNew(Self);
228
OnMouseClick := GoMouseClick;
229
OnMouseDown := GoMouseDown;
230
OnMouseMove := GoMouseMove;
231
OnMouseUp := GoMouseUp;
232
OnMouseWheel := GoMouseWheel;
236
procedure TGLViewer.DestroWindow;
241
// ------------------------------------------------------------------------------
243
procedure TGLViewer.FitWindow;
247
R := TRectF.Create(LocalToAbsolute(TPointF.Zero) * GetScreenScale,
250
_Form.Bounds := R.Round;
252
if Height < Width then
253
_Viewer[0] := TSingleM4.Scale(Height / Width, 1, 1)
254
else if Width < Height then
255
_Viewer[0] := TSingleM4.Scale(1, Width / Height, 1)
257
_Viewer[0] := TSingleM4.Identity;
260
constructor TGLViewer.Create(AOwner_: TComponent);
268
_OnPaint := procedure
272
if not(csDesigning in ComponentState) then
274
TMessageManager.DefaultManager.SubscribeToMessage(TAfterCreateFormHandle,
276
TMessageManager.DefaultManager.SubscribeToMessage(TBeforeDestroyFormHandle,
279
_Viewer := TGLUniBuf<TSingleM4>.Create(GL_DYNAMIC_DRAW);
280
_BackColor := TAlphaColorF.Create(0, 0, 0, 1);
283
destructor TGLViewer.Destroy;
287
if not(csDesigning in ComponentState) then
289
TMessageManager.DefaultManager.Unsubscribe(TBeforeDestroyFormHandle,
291
TMessageManager.DefaultManager.Unsubscribe(TAfterCreateFormHandle,
298
procedure TGLViewer.Repaint;
303
// ------------------------------------------------------------------------------
305
procedure TGLViewer.BeginRender;
310
glClearColor(R, G, B, A);
312
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
314
_Viewer.Use(0 { BinP } );
317
procedure TGLViewer.EndRender;
319
_Viewer.Unuse(0 { BinP } );
328
// ------------------------------------------------------------------------------
330
function TGLViewer.MakeScreenShot: FMX.Graphics.TBitmap;
332
Cs: TArray<TAlphaColor>;
337
Result := FMX.Graphics.TBitmap.Create;
343
SetLength(Cs, Height * Width);
349
glReadBuffer(GL_FRONT);
350
glReadPixels(0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_BYTE, C);
354
Map(TMapAccess.Write, Bs);
356
S := SizeOf(TAlphaColor) * Width;
358
for Y := Height - 1 downto 0 do
360
B := Bs.GetScanline(Y);
362
System.Move(C^, B^, S);
371
// ------------------------------------------------------------------------------
373
function TGLViewer.ShootRay(const X_, Y_: Single): TSingleRay3D;
376
S, P0, P1: TSingle4D;
378
M := _Camera.AbsoPose * _Camera.Proj.Inverse * _Viewer[0].Inverse;
382
S.X := X_ / Width * 2 - 1;
383
S.Y := 1 - Y_ / Height * 2;
395
Vec := Pos.UnitorTo(P1.ToCart);
399
function TGLViewer.PickObject(const X_, Y_: Single): TGLObject;
401
Result := _Camera.Scener.HitRay(ShootRay(X_, Y_));