2
// This unit is part of the GLScene Engine https://github.com/glscene
5
A simple component written by request from someone at the www.glscene.ru forums.
6
Allows to view the FPS and do the usual Zoom and MoveAroundTarget stuff
7
that all demos usually have in themselves. All that is just by dropping
8
this component on the form.
11
14/12/10 - DaStr - Fixed compiler hint
12
12/12/10 - Yar - Adapted to using with TGLSceneForm
13
01/07/10 - Yar - Fixed zooming for FPC (by Rustam Asmandiarov aka Predator)
14
17/06/10 - YP - Fixed Zoom in/out inconsistence (mousewheel up/down inverted)
15
11/06/10 - YP - Fixed wheeldata can be equal to 0 in FormMouseWheel (div by 0 exception)
16
21/01/10 - Yar - Bugfixed zooming in design time (BugtrackerID = 2936266)
17
25/12/09 - DaStr - Added OnMouseMove event (thanks YarUnderoaker)
18
18/10/09 - DaStr - Added snoShowFPS option (thanks YarUnderoaker)
19
Fixed a small bug with FPS string
20
29/09/07 - DaStr - Component now automaticly detects Form Caption
21
24/03/07 - DaStr - Replaced GLWin32Viewer with GLViewer
22
(thanks Burkhard Carstens) (Bugtracker ID = 1684432)
23
Got rid of Types dependancy
24
20/03/07 - DaStr - Improved SceneViewer detection
25
02/03/07 - DaStr - Added default values to all properties
26
Added TGLSimpleNavigationOptions
27
Added TGLSimpleNavigationKeyCombination
29
Added TGLSimpleNavigation.Assign
30
MouseWheel is now handled by default
31
06/02/07 - DaStr - Creation (donated to GLScene)
34
Previous version history:
35
v1.0 08 May '2006 Creation
36
v1.1 04 September '2006 FreeNotification fix
37
Automatic Form detection fix
38
v1.2 11 September '2006 Automatic SceneViewer detection
40
v1.3 06 February '2007 FPS is only updated in Run-Time now
44
unit GLSimpleNavigation;
51
Classes, SysUtils, TypInfo, Forms, Controls, ExtCtrls,
53
GLSceneForm, GLVectorGeometry, GLScene,
54
GLViewer, GLStrings, GLCrossPlatform;
58
TPoint = GLCrossPlatform.TGLPoint; // for Mouse Wheel
60
TGLSimpleNavigationOption = (
61
snoInvertMoveAroundX, snoInvertMoveAroundY, // MoveAroundTarget.
62
snoInvertZoom, snoInvertMouseWheel, // Zoom.
63
snoInvertRotateX, snoInvertRotateY, // RotateTarget.
64
snoMouseWheelHandled, // MouseWheel.
65
snoShowFPS // Show FPS
68
TGLSimpleNavigationOptions = set of TGLSimpleNavigationOption;
70
TGLSimpleNavigationAction = (snaNone, snaMoveAroundTarget, snaZoom, snaRotateTarget, snaCustom);
72
TGLSimpleNavigationKeyCombination = class;
73
TSimpleNavigationCustomActionEvent =
74
procedure(Sender: TGLSimpleNavigationKeyCombination; Shift: TShiftState; X, Y: Integer) of object;
76
TGLSimpleNavigationKeyCombination = class(TCollectionItem)
78
FExitOnMatch: Boolean;
79
FAction: TGLSimpleNavigationAction;
80
FOnCustomAction: TSimpleNavigationCustomActionEvent;
81
FShiftState: TShiftState;
83
function GetDisplayName: string; override;
84
procedure DoOnCustomAction(Shift: TShiftState; X, Y: Integer); virtual;
86
constructor Create(Collection: TCollection); override;
87
procedure Assign(Source: TPersistent); override;
89
property ShiftState: TShiftState read FShiftState write FShiftState default [];
90
property ExitOnMatch: Boolean read FExitOnMatch write FExitOnMatch default True;
91
property Action: TGLSimpleNavigationAction read FAction write FAction default snaNone;
92
property OnCustomAction: TSimpleNavigationCustomActionEvent read FOnCustomAction write FOnCustomAction;
95
TGLSimpleNavigationKeyCombinations = class(TOwnedCollection)
97
function GetItems(Index: Integer): TGLSimpleNavigationKeyCombination;
98
procedure SetItems(Index: Integer; const Value: TGLSimpleNavigationKeyCombination);
100
function Add: TGLSimpleNavigationKeyCombination; overload;
101
function Add(const AShiftState: TShiftState; const AAction: TGLSimpleNavigationAction; const AExitOnMatch: Boolean = True): TGLSimpleNavigationKeyCombination; overload;
102
property Items[Index: Integer]: TGLSimpleNavigationKeyCombination read GetItems write SetItems; default;
105
TGLSimpleNavigation = class(TComponent)
109
FGLSceneViewer: TGLSceneViewer;
111
FOldX, FOldY: Integer;
112
FFormCaption: string;
113
FMoveAroundTargetSpeed: Single;
115
FOptions: TGLSimpleNavigationOptions;
116
FKeyCombinations: TGLSimpleNavigationKeyCombinations;
117
FRotateTargetSpeed: Single;
118
FOnMouseMove: TMouseMoveEvent;
120
procedure ShowFPS(Sender: TObject);
121
procedure ViewerMouseMove(Sender: TObject;
122
Shift: TShiftState; X, Y: Integer);
123
procedure ViewerMouseWheel(Sender: TObject; Shift: TShiftState;
124
WheelDelta: Integer; MousePos: TGLPoint; var Handled: Boolean);
126
procedure SetGLSceneViewer(const Value: TGLSceneViewer);
127
procedure SetForm(const Value: TCustomForm);
128
function StoreFormCaption: Boolean;
129
function StoreMoveAroundTargetSpeed: Boolean;
130
function StoreZoomSpeed: Boolean;
131
procedure SetKeyCombinations(const Value: TGLSimpleNavigationKeyCombinations);
132
function StoreRotateTargetSpeed: Boolean;
133
procedure SetOptions(const Value: TGLSimpleNavigationOptions);
135
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
137
constructor Create(AOwner: TComponent); override;
138
destructor Destroy; override;
139
procedure Assign(Source: TPersistent); override;
141
property Form: TCustomForm read FForm write SetForm;
142
property GLSceneViewer: TGLSceneViewer read FGLSceneViewer write SetGLSceneViewer;
144
property ZoomSpeed: Single read FZoomSpeed write FZoomSpeed stored StoreZoomSpeed;
145
property MoveAroundTargetSpeed: Single read FMoveAroundTargetSpeed write FMoveAroundTargetSpeed stored StoreMoveAroundTargetSpeed;
146
property RotateTargetSpeed: Single read FRotateTargetSpeed write FRotateTargetSpeed stored StoreRotateTargetSpeed;
148
property FormCaption: string read FFormCaption write FFormCaption stored StoreFormCaption;
149
property Options: TGLSimpleNavigationOptions read FOptions write SetOptions default [snoMouseWheelHandled, snoShowFPS];
150
property KeyCombinations: TGLSimpleNavigationKeyCombinations read FKeyCombinations write SetKeyCombinations;
152
property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
161
{ TGLSimpleNavigation }
163
procedure TGLSimpleNavigation.Assign(Source: TPersistent);
165
if Source is TGLSimpleNavigation then
167
{ Don't do that, because that might overide the original component's event handlers
168
SetForm(TGLSimpleNavigation(Source).FForm);
169
SetGLSceneViewer(TGLSimpleNavigation(Source).FGLSceneViewer);
171
FZoomSpeed := TGLSimpleNavigation(Source).FZoomSpeed;
172
FMoveAroundTargetSpeed := TGLSimpleNavigation(Source).FMoveAroundTargetSpeed;
173
FRotateTargetSpeed := TGLSimpleNavigation(Source).FRotateTargetSpeed;
175
FFormCaption := TGLSimpleNavigation(Source).FFormCaption;
176
FOptions := TGLSimpleNavigation(Source).FOptions;
177
FKeyCombinations.Assign(TGLSimpleNavigation(Source).FKeyCombinations);
183
constructor TGLSimpleNavigation.Create(AOwner: TComponent);
188
FKeyCombinations := TGLSimpleNavigationKeyCombinations.Create(Self, TGLSimpleNavigationKeyCombination);
189
FKeyCombinations.Add([ssLeft, ssRight], snaZoom, True);
190
FKeyCombinations.Add([ssLeft], snaMoveAroundTarget, True);
191
FKeyCombinations.Add([ssRight], snaMoveAroundTarget, True);
193
FMoveAroundTargetSpeed := 1;
194
FRotateTargetSpeed := 1;
196
FOptions := [snoMouseWheelHandled, snoShowFPS];
197
FFormCaption := vFPSString;
199
FTimer := TTimer.Create(nil);
200
FTimer.OnTimer := ShowFPS;
204
if AOwner is TCustomForm then
205
SetForm(TCustomForm(AOwner));
210
if FForm.ComponentCount <> 0 then
211
for I := 0 to FForm.ComponentCount - 1 do
212
if FForm.Components[I] is TGLSceneViewer then
214
SetGLSceneViewer(TGLSceneViewer(FForm.Components[I]));
220
destructor TGLSimpleNavigation.Destroy;
223
FKeyCombinations.Free;
226
TForm(FForm).OnMouseWheel := nil;
228
if FGLSceneViewer <> nil then
229
FGLSceneViewer.OnMouseMove := nil;
234
procedure TGLSimpleNavigation.ViewerMouseWheel(Sender: TObject;
235
Shift: TShiftState; WheelDelta: Integer; MousePos: TGLPoint;
236
var Handled: Boolean);
241
if (csDesigning in ComponentState) or (WheelDelta = 0) then
244
if snoInvertMouseWheel in FOptions then
249
if FGLSceneViewer <> nil then
250
lCamera := FGLSceneViewer.Camera
251
else if FSceneForm then
252
lCamera := TGLSceneForm(FForm).Camera
256
if Assigned(lCamera) then
258
if lCamera.CameraStyle = csOrthogonal then
259
lCamera.FocalLength := FGLSceneViewer.Camera.FocalLength
260
/ Power(FZoomSpeed, Sign * WheelDelta div Abs(WheelDelta))
262
lCamera.AdjustDistanceToTarget(
263
Power(FZoomSpeed, Sign * WheelDelta div Abs(WheelDelta)));
266
Handled := snoMouseWheelHandled in FOptions;
269
procedure TGLSimpleNavigation.ViewerMouseMove(Sender: TObject;
270
Shift: TShiftState; X, Y: Integer);
279
if snoInvertZoom in FOptions then
283
lCamera.AdjustDistanceToTarget(
284
Power(FZoomSpeed, Sign * (Y - FOldY) / 20));
287
procedure DoMoveAroundTarget;
292
if snoInvertMoveAroundX in FOptions then
297
if snoInvertMoveAroundY in FOptions then
302
lCamera.MoveAroundTarget(SignX * FMoveAroundTargetSpeed * (FOldY - Y),
303
SignY * FMoveAroundTargetSpeed * (FOldX - X));
306
procedure DoRotateTarget;
311
if snoInvertRotateX in FOptions then
316
if snoInvertRotateY in FOptions then
321
lCamera.RotateTarget(SignY * FRotateTargetSpeed * (FOldY - Y),
322
SignX * FRotateTargetSpeed * (FOldX - X));
329
if csDesigning in ComponentState then
332
if FGLSceneViewer <> nil then
333
lCamera := FGLSceneViewer.Camera
334
else if FSceneForm then
335
lCamera := TGLSceneForm(FForm).Camera;
337
if Assigned(lCamera) then
339
if FKeyCombinations.Count <> 0 then
340
for I := 0 to FKeyCombinations.Count - 1 do
341
if FKeyCombinations[I].FShiftState <= Shift then
343
case FKeyCombinations[I].FAction of
345
snaMoveAroundTarget: DoMoveAroundTarget;
347
snaRotateTarget: DoRotateTarget;
348
snaCustom: FKeyCombinations[I].DoOnCustomAction(Shift, X, Y);
350
Assert(False, glsErrorEx + glsUnknownType);
353
if FKeyCombinations[I].FExitOnMatch then
361
if Assigned(FOnMouseMove) then
362
FOnMouseMove(Self, Shift, X, Y);
365
procedure TGLSimpleNavigation.Notification(AComponent: TComponent;
366
Operation: TOperation);
369
if (AComponent = FGLSceneViewer) and (Operation = opRemove) then
370
FGLSceneViewer := nil;
371
if (AComponent = FForm) and (Operation = opRemove) then
375
procedure TGLSimpleNavigation.SetKeyCombinations(
376
const Value: TGLSimpleNavigationKeyCombinations);
378
FKeyCombinations.Assign(Value);
381
procedure TGLSimpleNavigation.SetForm(const Value: TCustomForm);
385
FForm.RemoveFreeNotification(Self);
386
TForm(FForm).OnMouseWheel := nil;
388
if FSceneForm then TForm(FForm).OnMouseMove := nil;
396
if FFormCaption = vFPSString then
397
FFormCaption := FForm.Caption + ' - ' + vFPSString;
398
TForm(FForm).OnMouseWheel := ViewerMouseWheel;
399
FForm.FreeNotification(Self);
400
{$IFDEF GLS_MULTITHREAD}
401
if FForm is TGLSceneForm then
404
TForm(FForm).OnMouseMove := ViewerMouseMove;
410
procedure TGLSimpleNavigation.SetGLSceneViewer(
411
const Value: TGLSceneViewer);
413
if FGLSceneViewer <> nil then
415
FGLSceneViewer.RemoveFreeNotification(Self);
416
FGLSceneViewer.OnMouseMove := nil;
418
FGLSceneViewer.OnMouseWheel := nil;
422
FGLSceneViewer := Value;
424
if FGLSceneViewer <> nil then
426
FGLSceneViewer.OnMouseWheel := ViewerMouseWheel;
427
FGLSceneViewer.OnMouseMove := ViewerMouseMove;
428
FGLSceneViewer.FreeNotification(Self);
432
procedure TGLSimpleNavigation.ShowFPS(Sender: TObject);
437
if (FForm <> nil) and
438
not (csDesigning in ComponentState) and
439
(snoShowFPS in FOptions) then
441
Temp := FFormCaption;
442
Index := Pos(vFPSString, Temp);
443
if FForm is TGLSceneForm then
447
Delete(Temp, Index, Length(vFPSString));
448
Insert(Format('%.*f FPS', [1, TGLSceneForm(FForm).Buffer.FramesPerSecond]), Temp, Index);
450
TGLSceneForm(FForm).Buffer.ResetPerformanceMonitor;
452
else if Assigned(FGLSceneViewer) then
456
Delete(Temp, Index, Length(vFPSString));
457
Insert(Format('%.*f FPS', [1, FGLSceneViewer.Buffer.FramesPerSecond]), Temp, Index);
459
FGLSceneViewer.ResetPerformanceMonitor;
461
FForm.Caption := Temp;
465
function TGLSimpleNavigation.StoreFormCaption: Boolean;
467
Result := (FFormCaption <> vFPSString);
470
function TGLSimpleNavigation.StoreMoveAroundTargetSpeed: Boolean;
472
Result := Abs(FMoveAroundTargetSpeed - 1) > EPS;
475
function TGLSimpleNavigation.StoreZoomSpeed: Boolean;
477
Result := Abs(FZoomSpeed - 1.5) > EPS;
480
function TGLSimpleNavigation.StoreRotateTargetSpeed: Boolean;
482
Result := Abs(FRotateTargetSpeed - 1) > EPS;
485
procedure TGLSimpleNavigation.SetOptions(
486
const Value: TGLSimpleNavigationOptions);
488
if FOptions <> Value then
495
{ TGLSimpleNavigationKeyCombination }
497
procedure TGLSimpleNavigationKeyCombination.Assign(Source: TPersistent);
499
if Source is TGLSimpleNavigationKeyCombination then
501
FExitOnMatch := TGLSimpleNavigationKeyCombination(Source).FExitOnMatch;
502
FAction := TGLSimpleNavigationKeyCombination(Source).FAction;
503
FOnCustomAction := TGLSimpleNavigationKeyCombination(Source).FOnCustomAction;
504
FShiftState := TGLSimpleNavigationKeyCombination(Source).FShiftState;
510
constructor TGLSimpleNavigationKeyCombination.Create(Collection: TCollection);
514
FExitOnMatch := True;
517
procedure TGLSimpleNavigationKeyCombination.DoOnCustomAction(
518
Shift: TShiftState; X, Y: Integer);
520
if Assigned(FOnCustomAction) then
521
FOnCustomAction(Self, Shift, X, Y);
524
function TGLSimpleNavigationKeyCombination.GetDisplayName: string;
526
Result := GetSetProp(Self, 'ShiftState', True) + ' - ' +
527
GetEnumName(TypeInfo(TGLSimpleNavigationAction), Integer(FAction));
530
{ TGLSimpleNavigationKeyCombinations }
532
function TGLSimpleNavigationKeyCombinations.Add: TGLSimpleNavigationKeyCombination;
534
Result := TGLSimpleNavigationKeyCombination(inherited Add);
537
function TGLSimpleNavigationKeyCombinations.Add(
538
const AShiftState: TShiftState; const AAction: TGLSimpleNavigationAction;
539
const AExitOnMatch: Boolean): TGLSimpleNavigationKeyCombination;
544
FShiftState := AShiftState;
546
FExitOnMatch := AExitOnMatch;
550
function TGLSimpleNavigationKeyCombinations.GetItems(
551
Index: Integer): TGLSimpleNavigationKeyCombination;
553
Result := TGLSimpleNavigationKeyCombination(inherited GetItem(Index));
556
procedure TGLSimpleNavigationKeyCombinations.SetItems(Index: Integer;
557
const Value: TGLSimpleNavigationKeyCombination);
559
inherited SetItem(Index, Value);