2
// This unit is part of the GLScene Engine https://github.com/glscene
5
An extention of TGLNavigator, which allows to move objects with inertia
6
Note: it is not completely FPS-independant. Only Moving code is, but
7
MoveAroundTarget, Turn[Vertical/Horizontal] and AdjustDistanceTo[..] is not.
9
Don't know why, but when I make their code identical, these function stop
10
working completely. So you probably have to call the AutoScaleParameters
11
procedure once in a while for it to adjust to the current framerate.
12
If someone knows a better way to solve this issue, please contact me via
17
30/06/11 - DaStr - Converted many procedures to functions
18
Bugfixed Assign() in some places
19
Added "Cutoff" property instead of fixed EPS values
20
02/06/11 - DaStr - DeltaTime is now Double, like in Cadencer
21
Added CustomAnimatedItems
22
28/05/11 - DaStr - Added the AdjustDistanceTo[..]Ex procedures
23
25/02/07 - DaStr - Added the AdjustDistanceTo[..] procedures
24
23/02/07 - DaStr - Initial version (contributed to GLScene)
28
1) Scale "Old values" too, when callin the Scale parameter procedure to
29
avoid the temporary "freeze" of controls.
30
2) AddImpulse procedures.
34
Previous version history:
35
v1.0 10 December '2005 Creation
36
v1.0.2 11 December '2005 TurnMaxAngle added
37
v1.1 04 March '2006 Inertia became FPS-independant
38
TGLSmoothNavigatorParameters added
39
v1.1.6 18 February '2007 Merged with GLInertedUserInterface.pas
40
All parameters moved into separate classes
41
Added MoveAroudTargetWithInertia
42
v1.2 23 February '2007 Finally made it trully FPS-independant
43
Added default values to every property
44
Contributed to GLScene
47
unit GLSmoothNavigator;
57
GLNavigator, GLVectorGeometry, GLScene, GLCrossPlatform, GLCoordinates,
58
GLScreen, GLXCollection;
62
{ TGLNavigatorAdjustDistanceParameters includes a basic set of parameters
63
that control the smoothness of movement.
65
TGLNavigatorAbstractParameters = class(TPersistent)
71
function StoreCutoff: Boolean;
73
function StoreInertia: Boolean; virtual;
74
function StoreSpeed: Boolean; virtual;
76
function GetOwner: TPersistent; override;
78
constructor Create(AOwner: TPersistent); virtual;
79
procedure Assign(Source: TPersistent); override;
80
procedure ScaleParameters(const Value: Single); virtual;
82
property Inertia: Single read FInertia write FInertia stored StoreInertia;
83
property Speed: Single read FSpeed write FSpeed stored StoreSpeed;
84
property Cutoff: Single read FCutoff write FCutoff stored StoreCutoff;
87
TGLSmoothNavigator = class;
89
{ TGLNavigatorSmoothChangeItem includes a basic set of parameters
90
that control the smoothness of movement.
92
TGLNavigatorSmoothChangeItem = class(TGLXCollectionItem)
99
function StoreInertia: Boolean;
100
function StoreSpeed: Boolean;
101
function StoreSpeedLimit: Boolean;
102
function StoreCutoff: Boolean;
104
function GetNavigator: TGLSmoothNavigator;
106
{ Returns False if there was no change. }
107
function Proceed(ADeltaTime: Double): Boolean; virtual; abstract;
108
constructor Create(aOwner: TGLXCollection); override;
109
procedure Assign(Source: TPersistent); override;
110
procedure ScaleParameters(const Value: Single); virtual;
111
procedure ResetTargetValue(); virtual; abstract;
113
property Inertia: Single read FInertia write FInertia stored StoreInertia;
114
property Speed: Single read FSpeed write FSpeed stored StoreSpeed;
115
property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
116
property Cutoff: Double read FCutoff write FCutoff stored StoreCutoff;
117
property Enabled: Boolean read FEnabled write FEnabled default True;
120
TGLNavigatorSmoothChangeSingle = class;
121
TGLNavigatorSmoothChangeSingleGetEvent = function(const ASender: TGLNavigatorSmoothChangeSingle): Single of object;
122
TGLNavigatorSmoothChangeSingleSetEvent = procedure(const ASender: TGLNavigatorSmoothChangeSingle; const AValue: Single) of object;
124
{ Smoothly change any Single value, so it will become TargetValue in the end. }
125
TGLNavigatorSmoothChangeSingle = class(TGLNavigatorSmoothChangeItem)
127
FTargetValue: Single;
128
FOnGetCurrentValue: TGLNavigatorSmoothChangeSingleGetEvent;
129
FOnSetCurrentValue: TGLNavigatorSmoothChangeSingleSetEvent;
131
class function FriendlyName: string; override;
132
function Proceed(ADeltaTime: Double): Boolean; override;
133
procedure Assign(Source: TPersistent); override;
134
procedure ResetTargetValue(); override;
136
property TargetValue: Single read FTargetValue write FTargetValue;
137
property OnGetCurrentValue: TGLNavigatorSmoothChangeSingleGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
138
property OnSetCurrentValue: TGLNavigatorSmoothChangeSingleSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
141
TGLNavigatorSmoothChangeVector = class;
142
TGLNavigatorSmoothChangeVectorGetEvent = function(const ASender: TGLNavigatorSmoothChangeVector): TVector of object;
143
TGLNavigatorSmoothChangeVectorSetEvent = procedure(const ASender: TGLNavigatorSmoothChangeVector; const AValue: TVector) of object;
145
{ Smoothly change any Vector4f value, so it will become TargetValue in the end. }
146
TGLNavigatorSmoothChangeVector = class(TGLNavigatorSmoothChangeItem)
148
FTargetValue: TGLCoordinates;
149
FOnGetCurrentValue: TGLNavigatorSmoothChangeVectorGetEvent;
150
FOnSetCurrentValue: TGLNavigatorSmoothChangeVectorSetEvent;
151
procedure SetTargetValue(const Value: TGLCoordinates);
153
class function FriendlyName: string; override;
154
function Proceed(ADeltaTime: Double): Boolean; override;
155
procedure Assign(Source: TPersistent); override;
156
constructor Create(aOwner: TGLXCollection); override;
157
destructor Destroy; override;
158
procedure ResetTargetValue(); override;
160
property TargetValue: TGLCoordinates read FTargetValue write SetTargetValue;
161
property OnGetCurrentValue: TGLNavigatorSmoothChangeVectorGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
162
property OnSetCurrentValue: TGLNavigatorSmoothChangeVectorSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
165
TGLNavigatorSmoothChangeItemClass = class of TGLNavigatorSmoothChangeItem;
167
{ XCollection of TGLNavigatorSmoothChangeItem. }
168
TGLNavigatorSmoothChangeItems = class(TGLXCollection)
170
function GetItems(const Index : Integer): TGLNavigatorSmoothChangeItem;
171
procedure SetItems(const Index : Integer; const Value: TGLNavigatorSmoothChangeItem);
173
procedure DoProceed(ADeltaTime: Double);
175
function Add(AClass : TGLNavigatorSmoothChangeItemClass): TGLNavigatorSmoothChangeItem;
176
function CanAdd(AClass: TGLXCollectionItemClass): Boolean; override;
177
class function ItemsClass: TGLXCollectionItemClass; override;
178
property Items[const Index : Integer]: TGLNavigatorSmoothChangeItem read GetItems write
182
{ TGLNavigatorAdjustDistanceParameters is wrapper for all parameters that
183
affect how the AdjustDisanceTo[...] methods work
185
TGLNavigatorAdjustDistanceParameters = class(TGLNavigatorAbstractParameters)
187
FOldDistanceRatio: Single;
188
FImpulseSpeed: Single;
189
function StoreImpulseSpeed: Boolean;
191
constructor Create(AOwner: TPersistent); override;
192
procedure Assign(Source: TPersistent); override;
193
procedure ScaleParameters(const Value: Single); override;
195
procedure AddImpulse(const Impulse: Single); virtual;
197
property ImpulseSpeed: Single read FImpulseSpeed write FImpulseSpeed stored StoreImpulseSpeed;
200
{ TGLNavigatorAdjustDistanceParameters is wrapper for all parameters that
201
affect how the AdjustDisanceTo[...]Ex methods work
203
You need to set the TargetObject and desired distance to it,
204
then call AdjustDisanceTo[...]Ex() in your Cadencer.OnProgress code.
206
TGLNavigatorAdjustDistanceParametersEx = class(TGLNavigatorAbstractParameters)
209
FTargetDistance: Single;
210
function StoreSpeedLimit: Boolean;
211
function StoreTargetDistance: Boolean;
213
function StoreSpeed: Boolean; override;
214
function StoreInertia: Boolean; override;
216
constructor Create(AOwner: TPersistent); override;
217
procedure Assign(Source: TPersistent); override;
219
property TargetDistance: Single read FTargetDistance write FTargetDistance stored StoreTargetDistance;
220
property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
223
{ TGLNavigatorInertiaParameters is wrapper for all parameters that affect the
224
smoothness of movement
226
TGLNavigatorInertiaParameters = class(TPersistent)
230
OldTurnHorizontalAngle: Single;
231
OldTurnVerticalAngle: Single;
233
OldMoveForwardDistance: Single;
234
OldStrafeHorizontalDistance: Single;
235
OldStrafeVerticalDistance: Single;
237
FTurnInertia: Single;
239
FTurnMaxAngle: Single;
240
FMovementAcceleration: Single;
241
FMovementInertia: Single;
242
FMovementSpeed: Single;
244
function StoreTurnMaxAngle: Boolean;
245
function StoreMovementAcceleration: Boolean;
246
function StoreMovementInertia: Boolean;
247
function StoreMovementSpeed: Boolean;
248
function StoreTurnInertia: Boolean;
249
function StoreTurnSpeed: Boolean;
251
function GetOwner: TPersistent; override;
253
constructor Create(AOwner: TPersistent); virtual;
254
procedure Assign(Source: TPersistent); override;
255
procedure ScaleParameters(const Value: Single); virtual;
257
property MovementAcceleration: Single read FMovementAcceleration write FMovementAcceleration stored StoreMovementAcceleration;
258
property MovementInertia: Single read FMovementInertia write FMovementInertia stored StoreMovementInertia;
259
property MovementSpeed: Single read FMovementSpeed write FMovementSpeed stored StoreMovementSpeed;
261
property TurnMaxAngle: Single read FTurnMaxAngle write FTurnMaxAngle stored StoreTurnMaxAngle;
262
property TurnInertia: Single read FTurnInertia write FTurnInertia stored StoreTurnInertia;
263
property TurnSpeed: Single read FTurnSpeed write FTurnSpeed stored StoreTurnSpeed;
267
{ TGLNavigatorGeneralParameters is a wrapper for all general inertia parameters.
269
These properties mean that if ExpectedMaxFPS is 100, FAutoScaleMin is 0.1,
270
FAutoScaleMax is 0.75 then the "safe range" for it to change is [10..75].
271
If these bounds are violated, then ExpectedMaxFPS is automaticly increased
272
or decreased by AutoScaleMult.
274
TGLNavigatorGeneralParameters = class(TPersistent)
277
FAutoScaleMin: Single;
278
FAutoScaleMax: Single;
279
FAutoScaleMult: Single;
281
function StoreAutoScaleMax: Boolean;
282
function StoreAutoScaleMin: Boolean;
283
function StoreAutoScaleMult: Boolean;
285
function GetOwner: TPersistent; override;
287
constructor Create(AOwner: TPersistent); virtual;
288
procedure Assign(Source: TPersistent); override;
290
property AutoScaleMin: Single read FAutoScaleMin write FAutoScaleMin stored StoreAutoScaleMin;
291
property AutoScaleMax: Single read FAutoScaleMax write FAutoScaleMax stored StoreAutoScaleMax;
292
property AutoScaleMult: Single read FAutoScaleMult write FAutoScaleMult stored StoreAutoScaleMult;
296
{ TGLNavigatorMoveAroundParameters is a wrapper for all parameters that
297
effect how the TGLBaseSceneObject.MoveObjectAround() procedure works
299
TGLNavigatorMoveAroundParameters = class(TPersistent)
302
FTargetObject: TGLBaseSceneObject;
304
FOldPitchInertiaAngle : Single;
305
FOldTurnInertiaAngle : Single;
307
FPitchSpeed : Single;
313
function StoreInertia: Boolean;
314
function StoreMaxAngle: Boolean;
315
function StorePitchSpeed: Boolean;
316
function StoreTurnSpeed: Boolean;
317
procedure SetTargetObject(const Value: TGLBaseSceneObject);
318
function StoreCutoff: Boolean;
320
function GetOwner: TPersistent; override;
322
constructor Create(AOwner: TPersistent); virtual;
323
procedure Assign(Source: TPersistent); override;
324
procedure ScaleParameters(const Value: Single); virtual;
326
property Inertia: Single read FInertia write FInertia stored StoreInertia;
327
property MaxAngle: Single read FMaxAngle write FMaxAngle stored StoreMaxAngle;
328
property PitchSpeed: Single read FPitchSpeed write FPitchSpeed stored StorePitchSpeed;
329
property TurnSpeed: Single read FTurnSpeed write FTurnSpeed stored StoreTurnSpeed;
330
property TargetObject: TGLBaseSceneObject read FTargetObject write SetTargetObject;
331
property Cutoff: Double read FCutoff write FCutoff stored StoreCutoff;
335
// TGLSmoothNavigator
337
{ TGLSmoothNavigator is the component for moving a TGLBaseSceneObject, and all
338
classes based on it, this includes all the objects from the Scene Editor.
340
It uses complex smoothing algorithms, most of which are FPS-dependant.
341
Make sure your limit your FPS and set MaxExpectedDeltaTime to a value
342
that is aproximatly 5 times less than your usual deltatime.
344
TGLSmoothNavigator = class(TGLNavigator)
346
FMaxExpectedDeltaTime: Double;
347
FInertiaParams: TGLNavigatorInertiaParameters;
348
FGeneralParams: TGLNavigatorGeneralParameters;
349
FMoveAroundParams: TGLNavigatorMoveAroundParameters;
350
FAdjustDistanceParams: TGLNavigatorAdjustDistanceParameters;
351
FAdjustDistanceParamsEx: TGLNavigatorAdjustDistanceParametersEx;
352
FCustomAnimatedItems: TGLNavigatorSmoothChangeItems;
353
procedure SetInertiaParams(const Value: TGLNavigatorInertiaParameters);
354
function StoreMaxExpectedDeltaTime: Boolean;
355
procedure SetGeneralParams(const Value: TGLNavigatorGeneralParameters);
356
procedure SetMoveAroundParams(const Value: TGLNavigatorMoveAroundParameters);
357
procedure SetAdjustDistanceParams(const Value: TGLNavigatorAdjustDistanceParameters);
358
procedure SetAdjustDistanceParamsEx(
359
const Value: TGLNavigatorAdjustDistanceParametersEx);
360
procedure SetCustomAnimatedItems(
361
const Value: TGLNavigatorSmoothChangeItems);
363
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
365
// Constructors-destructors.
366
constructor Create(AOwner: TComponent); override;
367
destructor Destroy; override;
369
// From TGLNavigator. Probably, should not be public.
370
procedure SetObject(Value: TGLBaseSceneObject); override;
372
// Uses InertiaParams.
373
procedure TurnHorizontal(Angle: Single; ADeltaTime: Double); virtual;
374
procedure TurnVertical(Angle: Single; ADeltaTime: Double); virtual;
375
procedure FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
376
procedure MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
377
procedure StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
378
procedure StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
380
// Uses MoveAroundParams. Returns True, if object was actually moved.
381
function MoveAroundTarget(const PitchDelta, TurnDelta : Single; const ADeltaTime: Double): Boolean; virtual;
382
function MoveObjectAround(const AObject: TGLBaseSceneObject; PitchDelta, TurnDelta : Single; ADeltaTime: Double): Boolean; virtual;
384
// Uses AdjustDistanceParams.
385
function AdjustDistanceToPoint(const APoint: TVector; const DistanceRatio : Single; ADeltaTime: Double): Boolean; virtual;
386
function AdjustDistanceToTarget(const DistanceRatio : Single; const ADeltaTime: Double): Boolean; virtual;
388
// Uses AdjustDistanceParamsEx.
389
function AdjustDistanceToPointEx(const APoint: TVector; ADeltaTime: Double): Boolean; virtual;
390
function AdjustDistanceToTargetEx(const ADeltaTime: Double): Boolean; virtual;
392
// Uses CustomAnimatedItems.
393
procedure AnimateCustomItems(const ADeltaTime: Double); virtual;
395
// Uses GeneralParams.
396
{ In ScaleParameters, Value should be around 1. }
397
procedure ScaleParameters(const Value: Single); virtual;
398
procedure AutoScaleParameters(const FPS: Single); virtual;
399
procedure AutoScaleParametersUp(const FPS: Single); virtual;
401
property MaxExpectedDeltaTime: Double read FMaxExpectedDeltaTime write FMaxExpectedDeltaTime stored StoreMaxExpectedDeltaTime;
402
property InertiaParams: TGLNavigatorInertiaParameters read FInertiaParams write SetInertiaParams;
403
property GeneralParams: TGLNavigatorGeneralParameters read FGeneralParams write SetGeneralParams;
404
property MoveAroundParams: TGLNavigatorMoveAroundParameters read FMoveAroundParams write SetMoveAroundParams;
405
property AdjustDistanceParams: TGLNavigatorAdjustDistanceParameters read FAdjustDistanceParams write SetAdjustDistanceParams;
406
property AdjustDistanceParamsEx: TGLNavigatorAdjustDistanceParametersEx read FAdjustDistanceParamsEx write SetAdjustDistanceParamsEx;
407
property CustomAnimatedItems: TGLNavigatorSmoothChangeItems read FCustomAnimatedItems write SetCustomAnimatedItems;
411
// TGLSmoothUserInterface
413
{ TGLSmoothUserInterface is the component which reads the userinput and transform it into action.
415
Mouselook(ADeltaTime: double) : handles mouse look... Should be called
416
in the Cadencer event. (Though it works everywhere!)
418
The four properties to get you started are:
420
InvertMouse : Inverts the mouse Y axis.
421
AutoUpdateMouse : If enabled (by defaul), than handles all mouse updates.
422
GLNavigator : The Navigator which receives the user movement.
423
GLVertNavigator : The Navigator which if set receives the vertical user
424
movement. Used mostly for cameras....
427
TGLSmoothUserInterface = class(TComponent)
429
FAutoUpdateMouse: Boolean;
430
FMouseLookActive: Boolean;
431
FSmoothNavigator: TGLSmoothNavigator;
432
FSmoothVertNavigator: TGLSmoothNavigator;
433
FInvertMouse: Boolean;
434
FOriginalMousePos: TGLCoordinates2;
435
procedure SetSmoothNavigator(const Value: TGLSmoothNavigator); virtual;
436
procedure SetOriginalMousePos(const Value: TGLCoordinates2); virtual;
437
procedure SetSmoothVertNavigator(const Value: TGLSmoothNavigator); virtual;
438
procedure SetMouseLookActive(const Value: Boolean); virtual;
440
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
442
constructor Create(AOwner: TComponent); override;
443
destructor Destroy; override;
445
procedure TurnHorizontal(const Angle : Single; const ADeltaTime: Double); virtual;
446
procedure TurnVertical(const Angle : Single; const ADeltaTime: Double); virtual;
447
procedure MouseLookActiveToggle; virtual;
449
function MouseLook(const ADeltaTime: Double): Boolean; overload;
450
function MouseLook(const NewXY: TGLPoint; const ADeltaTime: Double): Boolean; overload;
451
function MouseLook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean; overload;
453
property AutoUpdateMouse: Boolean read FAutoUpdateMouse write FAutoUpdateMouse default True;
454
property MouseLookActive: Boolean read FMouseLookActive write SetMouseLookActive default False;
455
property SmoothVertNavigator: TGLSmoothNavigator read FSmoothVertNavigator write SetSmoothVertNavigator;
456
property SmoothNavigator: TGLSmoothNavigator read FSmoothNavigator write SetSmoothNavigator;
457
property InvertMouse: Boolean read FInvertMouse write FInvertMouse default False;
458
property OriginalMousePos: TGLCoordinates2 read FOriginalMousePos write SetOriginalMousePos;
468
{ TGLSmoothNavigator }
470
constructor TGLSmoothNavigator.Create(AOwner: TComponent);
473
FMaxExpectedDeltaTime := 0.001;
474
FInertiaParams := TGLNavigatorInertiaParameters.Create(Self);
475
FGeneralParams := TGLNavigatorGeneralParameters.Create(Self);
476
FMoveAroundParams := TGLNavigatorMoveAroundParameters.Create(Self);
477
FAdjustDistanceParams := TGLNavigatorAdjustDistanceParameters.Create(Self);
478
FAdjustDistanceParamsEx := TGLNavigatorAdjustDistanceParametersEx.Create(Self);
479
FCustomAnimatedItems := TGLNavigatorSmoothChangeItems.Create(Self);
482
destructor TGLSmoothNavigator.Destroy;
486
FMoveAroundParams.Free;
487
FAdjustDistanceParams.Free;
488
FAdjustDistanceParamsEx.Free;
489
FCustomAnimatedItems.Free;
493
procedure TGLSmoothNavigator.SetInertiaParams(
494
const Value: TGLNavigatorInertiaParameters);
496
FInertiaParams.Assign(Value);
499
procedure TGLSmoothNavigator.TurnHorizontal(Angle: Single; ADeltaTime: Double);
503
with FInertiaParams do
506
Angle := Angle * FTurnSpeed;
507
while ADeltaTime > FMaxExpectedDeltaTime do
509
Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnHorizontalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
510
OldTurnHorizontalAngle := Angle;
511
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
512
FinalAngle := FinalAngle + Angle;
516
if (Abs(FinalAngle) > EPS) then
517
inherited TurnHorizontal(FinalAngle);
520
procedure TGLSmoothNavigator.TurnVertical(Angle: Single; ADeltaTime: Double);
524
with FInertiaParams do
527
Angle := Angle * FTurnSpeed;
528
while ADeltaTime > FMaxExpectedDeltaTime do
530
Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnVerticalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
531
OldTurnVerticalAngle := Angle;
532
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
533
FinalAngle := FinalAngle + Angle;
537
if (Abs(FinalAngle) > EPS) then
538
inherited TurnVertical(FinalAngle);
542
procedure TGLSmoothNavigator.MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
544
FinalDistance: Single;
547
with FInertiaParams do
550
Distance := FMovementSpeed
552
Distance := -FMovementSpeed
557
Distance := Distance * FMovementAcceleration;
561
while ADeltaTime > FMaxExpectedDeltaTime do
563
OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
564
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
565
FinalDistance := FinalDistance + OldMoveForwardDistance;
569
if Abs(FinalDistance) > EPS then
570
inherited MoveForward(FinalDistance);
573
procedure TGLSmoothNavigator.FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
575
FinalDistance: Single;
578
with FInertiaParams do
581
Distance := FMovementSpeed
583
Distance := -FMovementSpeed
588
Distance := Distance * FMovementAcceleration;
592
while ADeltaTime > FMaxExpectedDeltaTime do
594
OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
595
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
596
FinalDistance := FinalDistance + OldMoveForwardDistance;
600
if Abs(FinalDistance) > EPS then
601
inherited FlyForward(FinalDistance);
604
procedure TGLSmoothNavigator.StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
606
FinalDistance: Single;
609
with FInertiaParams do
612
Distance := FMovementSpeed
614
Distance := -FMovementSpeed
619
Distance := Distance * FMovementAcceleration;
623
while ADeltaTime > FMaxExpectedDeltaTime do
625
OldStrafeHorizontalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeHorizontalDistance * FMovementInertia) / (FMovementInertia + 1);
626
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
627
FinalDistance := FinalDistance + OldStrafeHorizontalDistance;
631
if Abs(FinalDistance) > EPS then
632
inherited StrafeHorizontal(FinalDistance);
635
procedure TGLSmoothNavigator.StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
637
FinalDistance: Single;
640
with FInertiaParams do
643
Distance := FMovementSpeed
645
Distance := -FMovementSpeed
650
Distance := Distance * FMovementAcceleration;
654
while ADeltaTime > FMaxExpectedDeltaTime do
656
OldStrafeVerticalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeVerticalDistance * FMovementInertia) / (FMovementInertia + 1);
657
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
658
FinalDistance := FinalDistance + OldStrafeVerticalDistance;
662
if Abs(FinalDistance) > EPS then
663
inherited StrafeVertical(FinalDistance);
666
procedure TGLSmoothNavigator.AutoScaleParameters(const FPS: Single);
668
with FGeneralParams do
670
if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
671
ScaleParameters(FAutoScaleMult)
672
else if FPS < FAutoScaleMin / FMaxExpectedDeltatime then
673
ScaleParameters(1/FAutoScaleMult);
678
procedure TGLSmoothNavigator.AutoScaleParametersUp(const FPS: Single);
680
with FGeneralParams do
682
if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
683
ScaleParameters(FAutoScaleMult)
687
procedure TGLSmoothNavigator.ScaleParameters(const Value: Single);
690
FMaxExpectedDeltatime := FMaxExpectedDeltatime / Value;
691
FInertiaParams.ScaleParameters(Value);
692
FMoveAroundParams.ScaleParameters(Value);
693
FAdjustDistanceParams.ScaleParameters(Value);
696
function TGLSmoothNavigator.StoreMaxExpectedDeltaTime: Boolean;
698
Result := Abs(FMaxExpectedDeltaTime - 0.001) > EPS2;
701
procedure TGLSmoothNavigator.SetGeneralParams(
702
const Value: TGLNavigatorGeneralParameters);
704
FGeneralParams.Assign(Value);
707
procedure TGLSmoothNavigator.SetMoveAroundParams(
708
const Value: TGLNavigatorMoveAroundParameters);
710
FMoveAroundParams.Assign(Value);
713
procedure TGLSmoothNavigator.Notification(AComponent: TComponent;
714
Operation: TOperation);
717
if Operation = opRemove then
719
if AComponent = FMoveAroundParams.FTargetObject then
720
FMoveAroundParams.FTargetObject := nil;
724
procedure TGLSmoothNavigator.SetObject(Value: TGLBaseSceneObject);
729
// Try to detect a TargetObject.
731
if FMoveAroundParams.TargetObject = nil then
733
// May be it is a camera...
734
if Value is TGLCamera then
735
FMoveAroundParams.TargetObject := TGLCamera(Value).TargetObject
738
// May be it has camera children...
739
if Value.Count <> 0 then
740
for I := 0 to Value.Count - 1 do
741
if Value.Children[I] is TGLCamera then
743
FMoveAroundParams.TargetObject := TGLCamera(Value.Children[I]).TargetObject;
750
function TGLSmoothNavigator.MoveAroundTarget(const PitchDelta, TurnDelta: Single;
751
const ADeltaTime: Double): Boolean;
753
Result := MoveObjectAround(FMoveAroundParams.FTargetObject, PitchDelta, TurnDelta, ADeltaTime);
756
function TGLSmoothNavigator.MoveObjectAround(
757
const AObject: TGLBaseSceneObject; PitchDelta, TurnDelta: Single;
758
ADeltaTime: Double): Boolean;
768
with FMoveAroundParams do
770
PitchDelta := PitchDelta * FPitchSpeed;
771
TurnDelta := TurnDelta * FTurnSpeed;
773
while ADeltaTime > FMaxExpectedDeltatime do
775
PitchDelta := ClampValue((PitchDelta * FMaxExpectedDeltatime + FOldPitchInertiaAngle * FInertia) / (FInertia + 1), - FMaxAngle, FMaxAngle);
776
FOldPitchInertiaAngle := PitchDelta;
777
FinalPitch := FinalPitch + PitchDelta;
778
TurnDelta := ClampValue((TurnDelta * FMaxExpectedDeltatime + FOldTurnInertiaAngle * FInertia) / (FInertia + 1), - FMaxAngle, FMaxAngle);
779
FOldTurnInertiaAngle := TurnDelta;
780
FinalTurn := FinalTurn + TurnDelta;
782
ADeltaTime := ADeltaTime - FMaxExpectedDeltatime;
786
lUp := VirtualUp.AsVector
788
lUp := MovingObject.AbsoluteUp;
790
if (Abs(FinalPitch) > FCutOff) or (Abs(FinalTurn) > FCutOff) then
792
MovingObject.AbsolutePosition := GLVectorGeometry.MoveObjectAround(
793
MovingObject.AbsolutePosition, lUp, AObject.AbsolutePosition, FinalPitch, FinalTurn);
800
function TGLSmoothNavigator.AdjustDistanceToPoint(const APoint: TVector;
801
const DistanceRatio: Single; ADeltaTime: Double): Boolean;
803
// Based on TGLCamera.AdjustDistanceToTarget
804
procedure DoAdjustDistanceToPoint(const DistanceRatio: Single);
808
vect := VectorSubtract(MovingObject.AbsolutePosition, APoint);
809
ScaleVector(vect, (distanceRatio - 1));
810
AddVector(vect, MovingObject.AbsolutePosition);
811
if Assigned(MovingObject.Parent) then
812
vect := MovingObject.Parent.AbsoluteToLocal(vect);
813
MovingObject.Position.AsVector := vect;
818
FinalDistanceRatio: Single;
819
TempDistanceRatio: Single;
821
with FAdjustDistanceParams do
823
TempDistanceRatio := DistanceRatio * FSpeed;
824
FinalDistanceRatio := 0;
825
while ADeltaTime > FMaxExpectedDeltaTime do
827
TempDistanceRatio := (TempDistanceRatio * FMaxExpectedDeltaTime + FOldDistanceRatio * FInertia) / (FInertia + 1);
828
FOldDistanceRatio := TempDistanceRatio;
829
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
830
FinalDistanceRatio := FinalDistanceRatio + FOldDistanceRatio / FMaxExpectedDeltaTime;
833
if Abs(FinalDistanceRatio) > FCutoff then
835
if FinalDistanceRatio > 0 then
836
DoAdjustDistanceToPoint(1 / (1 + FinalDistanceRatio))
838
DoAdjustDistanceToPoint(1 * (1 - FinalDistanceRatio))
845
function TGLSmoothNavigator.AdjustDistanceToTarget(const DistanceRatio: Single;
846
const ADeltaTime: Double): Boolean;
848
Assert(FMoveAroundParams.FTargetObject <> nil);
849
Result := AdjustDistanceToPoint(FMoveAroundParams.FTargetObject.AbsolutePosition,
850
DistanceRatio, ADeltaTime);
853
procedure TGLSmoothNavigator.SetAdjustDistanceParams(
854
const Value: TGLNavigatorAdjustDistanceParameters);
856
FAdjustDistanceParams.Assign(Value);
859
function TGLSmoothNavigator.AdjustDistanceToPointEx(const APoint: TVector;
860
ADeltaTime: Double): Boolean;
863
lAbsolutePosition: TVector;
864
lCurrentDistance: Single;
865
lDistanceDifference, lTempCurrentDistance: Single;
867
procedure DoAdjustDistanceToPoint(const DistanceValue: Single);
871
vect := VectorSubtract(APoint, lAbsolutePosition);
872
NormalizeVector(vect);
873
ScaleVector(vect, DistanceValue);
874
MovingObject.AbsolutePosition := VectorAdd(lAbsolutePosition, vect);
879
lAbsolutePosition := MovingObject.AbsolutePosition;
880
lCurrentDistance := VectorDistance(lAbsolutePosition, APoint);
881
lDistanceDifference := lCurrentDistance - FAdjustDistanceParamsEx.FTargetDistance;
883
with FAdjustDistanceParamsEx do
885
lTempCurrentDistance := 0;
886
while ADeltaTime > FMaxExpectedDeltaTime do
888
lTempCurrentDistance := (FSpeed * FMaxExpectedDeltaTime * lDistanceDifference * FInertia) / (FInertia + 1);
889
// lTempCurrentDistance := (FSpeed * FMaxExpectedDeltaTime + lDistanceDifference * FInertia) / (FInertia + 1);- this also works, but a bit different.
890
ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
893
lTempCurrentDistance := ClampValue(lTempCurrentDistance, -FSpeedLimit * ADeltaTime, FSpeedLimit * ADeltaTime);
895
if Abs(lTempCurrentDistance) > FCutoff then
896
DoAdjustDistanceToPoint(lTempCurrentDistance)
902
function TGLSmoothNavigator.AdjustDistanceToTargetEx(
903
const ADeltaTime: Double): Boolean;
905
Assert(FMoveAroundParams.FTargetObject <> nil);
906
Result := AdjustDistanceToPointEx(FMoveAroundParams.FTargetObject.AbsolutePosition,
910
procedure TGLSmoothNavigator.SetAdjustDistanceParamsEx(
911
const Value: TGLNavigatorAdjustDistanceParametersEx);
913
FAdjustDistanceParamsEx.Assign(Value);
916
procedure TGLSmoothNavigator.AnimateCustomItems(const ADeltaTime: Double);
918
FCustomAnimatedItems.DoProceed(ADeltaTime);
921
procedure TGLSmoothNavigator.SetCustomAnimatedItems(
922
const Value: TGLNavigatorSmoothChangeItems);
924
FCustomAnimatedItems.Assign(Value);
927
{ TGLSmoothUserInterface }
929
function TGLSmoothUserInterface.MouseLook(
930
const ADeltaTime: Double): Boolean;
934
Assert(FAutoUpdateMouse, 'AutoUpdateMouse must be True to use this function');
935
if FMouseLookActive then
937
GLGetCursorPos(MousePos);
938
Result := Mouselook(MousePos.X, MousePos.Y, ADeltaTime);
939
GLSetCursorPos(Round(OriginalMousePos.X), Round(OriginalMousePos.Y));
945
function TGLSmoothUserInterface.Mouselook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean;
947
DeltaX, DeltaY: Single;
950
if FMouseLookActive then
952
Deltax := (NewX - FOriginalMousePos.X);
953
Deltay := (FOriginalMousePos.Y - NewY);
958
SmoothNavigator.TurnHorizontal(DeltaX, ADeltaTime);
959
SmoothNavigator.TurnVertical(DeltaY, ADeltaTime);
961
Result := (DeltaX <> 0) or (DeltaY <> 0);
966
function TGLSmoothUserInterface.MouseLook(const NewXY: TGLPoint; const ADeltaTime: Double): Boolean;
968
Result := Mouselook(NewXY.X, NewXY.Y, ADeltaTime);
971
constructor TGLSmoothUserInterface.Create(AOwner: TComponent);
974
FMouseLookActive := False;
975
FAutoUpdateMouse := True;
976
FOriginalMousePos := TGLCoordinates2.CreateInitialized(Self,
977
VectorMake(GLGetScreenWidth div 2,
978
GLGetScreenHeight div 2, 0, 0), csPoint2D);
981
procedure TGLSmoothUserInterface.Notification(AComponent: TComponent;
982
Operation: TOperation);
985
if (Operation = opRemove) then
987
if AComponent = FSmoothNavigator then
988
FSmoothNavigator := nil;
989
if AComponent = FSmoothVertNavigator then
990
FSmoothNavigator := nil;
994
procedure TGLSmoothUserInterface.SetSmoothNavigator(
995
const Value: TGLSmoothNavigator);
997
if FSmoothNavigator <> nil then
998
FSmoothNavigator.RemoveFreeNotification(Self);
1000
FSmoothNavigator := Value;
1002
if FSmoothNavigator <> nil then
1003
FSmoothNavigator.FreeNotification(Self);
1006
destructor TGLSmoothUserInterface.Destroy;
1008
FOriginalMousePos.Destroy;
1012
procedure TGLSmoothUserInterface.SetOriginalMousePos(
1013
const Value: TGLCoordinates2);
1015
FOriginalMousePos.Assign(Value);
1018
procedure TGLSmoothUserInterface.SetSmoothVertNavigator(
1019
const Value: TGLSmoothNavigator);
1021
if FSmoothVertNavigator <> nil then
1022
FSmoothVertNavigator.RemoveFreeNotification(Self);
1024
FSmoothVertNavigator := Value;
1026
if FSmoothVertNavigator <> nil then
1027
FSmoothVertNavigator.FreeNotification(Self);
1030
procedure TGLSmoothUserInterface.MouseLookActiveToggle;
1032
if FMouseLookActive then
1033
SetMouseLookActive(False)
1035
SetMouseLookActive(True)
1038
procedure TGLSmoothUserInterface.SetMouseLookActive(const Value: Boolean);
1042
if FMouseLookActive = Value then Exit;
1043
FMouseLookActive := Value;
1044
if FMouseLookActive then
1046
if FAutoUpdateMouse then
1048
GLGetCursorPos(MousePos);
1049
FOriginalMousePos.SetPoint2D(MousePos.X, MousePos.Y);
1050
GLShowCursor(False);
1055
if FAutoUpdateMouse then
1060
procedure TGLSmoothUserInterface.TurnHorizontal(const Angle: Single;
1061
const ADeltaTime: Double);
1063
FSmoothNavigator.TurnHorizontal(Angle, ADeltaTime);
1066
procedure TGLSmoothUserInterface.TurnVertical(const Angle: Single;
1067
const ADeltaTime: Double);
1069
if Assigned(FSmoothNavigator) then
1070
FSmoothNavigator.TurnVertical(Angle, ADeltaTime)
1072
FSmoothVertNavigator.TurnVertical(Angle, ADeltaTime);
1075
{ TGLNavigatorInertiaParameters }
1077
procedure TGLNavigatorInertiaParameters.Assign(Source: TPersistent);
1079
if Source is TGLNavigatorInertiaParameters then
1081
FMovementAcceleration := TGLNavigatorInertiaParameters(Source).FMovementAcceleration;
1082
FMovementInertia := TGLNavigatorInertiaParameters(Source).FMovementInertia;
1083
FMovementSpeed := TGLNavigatorInertiaParameters(Source).FMovementSpeed;
1084
FTurnMaxAngle := TGLNavigatorInertiaParameters(Source).FTurnMaxAngle;
1085
FTurnInertia := TGLNavigatorInertiaParameters(Source).FTurnInertia;
1086
FTurnSpeed := TGLNavigatorInertiaParameters(Source).FTurnSpeed;
1089
inherited; //to the pit of doom ;)
1092
constructor TGLNavigatorInertiaParameters.Create(AOwner: TPersistent);
1096
FTurnInertia := 150;
1098
FTurnMaxAngle := 0.5;
1100
FMovementAcceleration := 7;
1101
FMovementInertia := 200;
1102
FMovementSpeed := 200;
1105
function TGLNavigatorInertiaParameters.GetOwner: TPersistent;
1110
procedure TGLNavigatorInertiaParameters.ScaleParameters(
1111
const Value: Single);
1117
FMovementInertia := FMovementInertia * GLVectorGeometry.Power(2, 1 / Value);
1118
FTurnInertia := FTurnInertia * GLVectorGeometry.Power(2, 1 / Value);
1122
FMovementInertia := FMovementInertia / GLVectorGeometry.Power(2, Value);
1123
FTurnInertia := FTurnInertia / GLVectorGeometry.Power(2, Value);
1125
FTurnMaxAngle := FTurnMaxAngle / Value;
1126
FTurnSpeed := FTurnSpeed * Value;
1129
function TGLNavigatorInertiaParameters.StoreTurnMaxAngle: Boolean;
1131
Result := Abs(FTurnMaxAngle - 0.5) > EPS;
1134
function TGLNavigatorInertiaParameters.StoreMovementAcceleration: Boolean;
1136
Result := Abs(FMovementAcceleration - 7) > EPS;
1139
function TGLNavigatorInertiaParameters.StoreMovementInertia: Boolean;
1141
Result := Abs(FMovementInertia - 200) > EPS;
1144
function TGLNavigatorInertiaParameters.StoreMovementSpeed: Boolean;
1146
Result := Abs(FMovementSpeed - 200) > EPS;
1149
function TGLNavigatorInertiaParameters.StoreTurnInertia: Boolean;
1151
Result := Abs(FTurnInertia - 150) > EPS;
1154
function TGLNavigatorInertiaParameters.StoreTurnSpeed: Boolean;
1156
Result := Abs(FTurnSpeed - 50) > EPS;
1159
{ TGLNavigatorGeneralParameters }
1161
procedure TGLNavigatorGeneralParameters.Assign(Source: TPersistent);
1163
if Source is TGLNavigatorGeneralParameters then
1165
FAutoScaleMin := TGLNavigatorGeneralParameters(Source).FAutoScaleMin;
1166
FAutoScaleMax := TGLNavigatorGeneralParameters(Source).FAutoScaleMax;
1167
FAutoScaleMult := TGLNavigatorGeneralParameters(Source).FAutoScaleMult;
1173
constructor TGLNavigatorGeneralParameters.Create(AOwner: TPersistent);
1176
FAutoScaleMin := 0.1;
1177
FAutoScaleMax := 0.75;
1178
FAutoScaleMult := 2;
1181
function TGLNavigatorGeneralParameters.GetOwner: TPersistent;
1186
function TGLNavigatorGeneralParameters.StoreAutoScaleMax: Boolean;
1188
Result := Abs(FAutoScaleMax - 0.75) > EPS;
1191
function TGLNavigatorGeneralParameters.StoreAutoScaleMin: Boolean;
1193
Result := Abs(FAutoScaleMin - 0.1) > EPS;
1196
function TGLNavigatorGeneralParameters.StoreAutoScaleMult: Boolean;
1198
Result := Abs(FAutoScaleMult - 2) > EPS;
1201
{ TGLNavigatorMoveAroundParameters }
1203
procedure TGLNavigatorMoveAroundParameters.Assign(Source: TPersistent);
1205
if Source is TGLNavigatorMoveAroundParameters then
1207
FMaxAngle := TGLNavigatorMoveAroundParameters(Source).FMaxAngle;
1208
FInertia := TGLNavigatorMoveAroundParameters(Source).FInertia;
1209
FPitchSpeed := TGLNavigatorMoveAroundParameters(Source).FPitchSpeed;
1210
FTurnSpeed := TGLNavigatorMoveAroundParameters(Source).FTurnSpeed;
1211
FCutoff := TGLNavigatorMoveAroundParameters(Source).FCutoff;
1212
SetTargetObject(TGLNavigatorMoveAroundParameters(Source).FTargetObject);
1218
constructor TGLNavigatorMoveAroundParameters.Create(AOwner: TPersistent);
1228
function TGLNavigatorMoveAroundParameters.GetOwner: TPersistent;
1233
procedure TGLNavigatorMoveAroundParameters.ScaleParameters(
1234
const Value: Single);
1239
FInertia := FInertia / GLVectorGeometry.Power(2, Value)
1241
FInertia := FInertia * GLVectorGeometry.Power(2, 1 / Value);
1243
FMaxAngle := FMaxAngle / Value;
1244
FPitchSpeed := FPitchSpeed * Value;
1245
FTurnSpeed := FTurnSpeed * Value;
1248
procedure TGLNavigatorMoveAroundParameters.SetTargetObject(
1249
const Value: TGLBaseSceneObject);
1251
if FTargetObject <> nil then
1252
if FOwner is TGLSmoothNavigator then
1253
FTargetObject.RemoveFreeNotification(TGLSmoothNavigator(FOwner));
1255
FTargetObject := Value;
1257
if FTargetObject <> nil then
1258
if FOwner is TGLSmoothNavigator then
1259
FTargetObject.FreeNotification(TGLSmoothNavigator(FOwner));
1262
function TGLNavigatorMoveAroundParameters.StoreCutoff: Boolean;
1264
Result := Abs(FCutoff - EPS2) > EPS8;
1267
function TGLNavigatorMoveAroundParameters.StoreInertia: Boolean;
1269
Result := Abs(FInertia - 65) > EPS;
1272
function TGLNavigatorMoveAroundParameters.StoreMaxAngle: Boolean;
1274
Result := Abs(FMaxAngle - 1.5) > EPS;
1277
function TGLNavigatorMoveAroundParameters.StorePitchSpeed: Boolean;
1279
Result := Abs(FPitchSpeed - 500) > EPS;
1282
function TGLNavigatorMoveAroundParameters.StoreTurnSpeed: Boolean;
1284
Result := Abs(FTurnSpeed - 500) > EPS;
1287
{ TGLNavigatorAdjustDistanceParameters }
1289
procedure TGLNavigatorAdjustDistanceParameters.AddImpulse(
1290
const Impulse: Single);
1292
FOldDistanceRatio := FOldDistanceRatio + Impulse * FSpeed / FInertia * FImpulseSpeed;
1295
procedure TGLNavigatorAdjustDistanceParameters.Assign(Source: TPersistent);
1297
inherited Assign(Source);
1298
if Source is TGLNavigatorAdjustDistanceParameters then
1300
FImpulseSpeed := TGLNavigatorAdjustDistanceParameters(Source).FImpulseSpeed;
1304
constructor TGLNavigatorAdjustDistanceParameters.Create(
1305
AOwner: TPersistent);
1308
FImpulseSpeed := 0.02;
1312
procedure TGLNavigatorAdjustDistanceParameters.ScaleParameters(
1313
const Value: Single);
1316
FImpulseSpeed := FImpulseSpeed / Value;
1319
function TGLNavigatorAdjustDistanceParameters.StoreImpulseSpeed: Boolean;
1321
Result := Abs(FImpulseSpeed - 0.02) > EPS;
1324
{ TGLNavigatorAbstractParameters }
1327
procedure TGLNavigatorAbstractParameters.Assign(Source: TPersistent);
1329
if Source is TGLNavigatorAbstractParameters then
1331
FInertia := TGLNavigatorAbstractParameters(Source).FInertia;
1332
FSpeed := TGLNavigatorAbstractParameters(Source).FSpeed;
1333
FCutoff := TGLNavigatorAbstractParameters(Source).FCutoff;
1336
inherited; //to the pit of doom ;)
1339
constructor TGLNavigatorAbstractParameters.Create(
1340
AOwner: TPersistent);
1348
function TGLNavigatorAbstractParameters.GetOwner: TPersistent;
1353
procedure TGLNavigatorAbstractParameters.ScaleParameters(
1354
const Value: Single);
1359
FInertia := FInertia / GLVectorGeometry.Power(2, Value)
1361
FInertia := FInertia * GLVectorGeometry.Power(2, 1 / Value);
1364
function TGLNavigatorAbstractParameters.StoreCutoff: Boolean;
1366
Result := Abs(FCutoff - EPS) > EPS2;
1369
function TGLNavigatorAbstractParameters.StoreInertia: Boolean;
1371
Result := Abs(FInertia - 100) > EPS;
1374
function TGLNavigatorAbstractParameters.StoreSpeed: Boolean;
1376
Result := Abs(FSpeed - 0.005) > EPS2;
1379
{ TGLNavigatorAdjustDistanceParametersEx }
1381
procedure TGLNavigatorAdjustDistanceParametersEx.Assign(
1382
Source: TPersistent);
1384
if Source is TGLNavigatorAdjustDistanceParametersEx then
1386
FTargetDistance := TGLNavigatorAdjustDistanceParametersEx(Source).FTargetDistance;
1387
FSpeedLimit := TGLNavigatorAdjustDistanceParametersEx(Source).FSpeedLimit;
1393
constructor TGLNavigatorAdjustDistanceParametersEx.Create(
1394
AOwner: TPersistent);
1398
FTargetDistance := 100;
1400
FSpeedLimit := 20000;
1403
function TGLNavigatorAdjustDistanceParametersEx.StoreInertia: Boolean;
1405
Result := Abs(FInertia - 0.5) > EPS2;
1408
function TGLNavigatorAdjustDistanceParametersEx.StoreSpeed: Boolean;
1410
Result := Abs(FSpeed - 100) > EPS2;
1413
function TGLNavigatorAdjustDistanceParametersEx.StoreSpeedLimit: Boolean;
1415
Result := Abs(FSpeedLimit - 20000) > EPS2;
1418
function TGLNavigatorAdjustDistanceParametersEx.StoreTargetDistance: Boolean;
1420
Result := Abs(FTargetDistance - 100) > EPS2;
1423
{ TGLNavigatorSmoothChangeItem }
1425
procedure TGLNavigatorSmoothChangeItem.Assign(Source: TPersistent);
1427
inherited Assign(Source);
1429
if Source is TGLNavigatorSmoothChangeItem then
1431
FInertia := TGLNavigatorSmoothChangeItem(Source).FInertia;
1432
FSpeed := TGLNavigatorSmoothChangeItem(Source).FSpeed;
1433
FSpeedLimit := TGLNavigatorSmoothChangeItem(Source).FSpeedLimit;
1434
FCutoff := TGLNavigatorSmoothChangeItem(Source).FCutoff;
1435
FEnabled := TGLNavigatorSmoothChangeItem(Source).FEnabled;
1439
constructor TGLNavigatorSmoothChangeItem.Create(aOwner: TGLXCollection);
1444
FSpeedLimit := 20000;
1449
function TGLNavigatorSmoothChangeItem.GetNavigator: TGLSmoothNavigator;
1451
Result := TGLSmoothNavigator(TGLNavigatorSmoothChangeItems(GetOwner).Owner);
1454
procedure TGLNavigatorSmoothChangeItem.ScaleParameters(
1455
const Value: Single);
1460
FInertia := FInertia / GLVectorGeometry.Power(2, Value)
1462
FInertia := FInertia * GLVectorGeometry.Power(2, 1 / Value);
1465
function TGLNavigatorSmoothChangeItem.StoreCutoff: Boolean;
1467
Result := Abs(FCutoff - EPS) > EPS8;
1470
function TGLNavigatorSmoothChangeItem.StoreInertia: Boolean;
1472
Result := Abs(FInertia - 1) > EPS;
1475
function TGLNavigatorSmoothChangeItem.StoreSpeed: Boolean;
1477
Result := Abs(FSpeed - 5.5) > EPS2;
1480
function TGLNavigatorSmoothChangeItem.StoreSpeedLimit: Boolean;
1482
Result := Abs(FSpeedLimit - 20000) > EPS2;
1485
{ TGLNavigatorSmoothChangeItems }
1487
function TGLNavigatorSmoothChangeItems.Add(AClass : TGLNavigatorSmoothChangeItemClass): TGLNavigatorSmoothChangeItem;
1489
Result := AClass.Create(Self);
1492
function TGLNavigatorSmoothChangeItems.CanAdd(AClass: TGLXCollectionItemClass): Boolean;
1494
Result := AClass.InheritsFrom(TGLNavigatorSmoothChangeItem);
1497
procedure TGLNavigatorSmoothChangeItems.DoProceed(ADeltaTime: Double);
1501
for I := 0 to Count - 1 do
1502
GetItems(I).Proceed(ADeltaTime);
1505
function TGLNavigatorSmoothChangeItems.GetItems(const Index : Integer): TGLNavigatorSmoothChangeItem;
1507
Result := TGLNavigatorSmoothChangeItem(inherited GetItems(Index));
1510
class function TGLNavigatorSmoothChangeItems.ItemsClass: TGLXCollectionItemClass;
1512
Result := TGLNavigatorSmoothChangeItem;
1515
procedure TGLNavigatorSmoothChangeItems.SetItems(const Index : Integer; const Value:
1516
TGLNavigatorSmoothChangeItem);
1518
GetItems(Index).Assign(Value);
1521
{ TGLNavigatorSmoothChangeSingle }
1523
procedure TGLNavigatorSmoothChangeSingle.Assign(Source: TPersistent);
1525
inherited Assign(Source);
1527
if Source is TGLNavigatorSmoothChangeVector then
1529
FTargetValue := TGLNavigatorSmoothChangeSingle(Source).TargetValue;
1530
FOnGetCurrentValue := TGLNavigatorSmoothChangeSingle(Source).FOnGetCurrentValue;
1531
FOnSetCurrentValue := TGLNavigatorSmoothChangeSingle(Source).FOnSetCurrentValue;
1535
class function TGLNavigatorSmoothChangeSingle.FriendlyName: string;
1537
Result := 'Navigator SmoothChange Single';
1540
function TGLNavigatorSmoothChangeSingle.Proceed(ADeltaTime: Double): Boolean;
1542
lCurrentValue: Single;
1543
lCurrentDifference: Single;
1544
lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
1545
lMaxExpectedDeltaTime: Double;
1549
if not FEnabled then Exit;
1550
if not Assigned(FOnGetCurrentValue) then Exit;
1551
if not Assigned(FOnSetCurrentValue) then Exit;
1553
lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
1554
lCurrentValue := FOnGetCurrentValue(Self);
1555
lCurrentDifference := FTargetValue - lCurrentValue;
1557
lTotalDistanceToTravelThisTime := 0;
1559
while ADeltaTime > lMaxExpectedDeltaTime do
1561
lDistanceToTravelThisTime := MinFloat((lCurrentDifference * ADeltaTime * FSpeed * FInertia) / (FInertia + 1), FSpeedLimit);
1562
// lDistanceToTravelThisTime := (lCurrentDistance * ADeltaTime + FSpeed * FInertia) / (FInertia + 1);- this also works, but a bit different.
1564
lCurrentDifference := lCurrentDifference - lDistanceToTravelThisTime;
1565
lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
1566
ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
1569
if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
1571
FOnSetCurrentValue(Self, lCurrentValue + lTotalDistanceToTravelThisTime);
1576
procedure TGLNavigatorSmoothChangeSingle.ResetTargetValue;
1578
FTargetValue := FOnGetCurrentValue(Self);
1581
{ TGLNavigatorSmoothChangeVector }
1583
procedure TGLNavigatorSmoothChangeVector.Assign(Source: TPersistent);
1585
inherited Assign(Source);
1587
if Source is TGLNavigatorSmoothChangeVector then
1589
FTargetValue.Assign(TGLNavigatorSmoothChangeVector(Source).TargetValue);
1590
FOnGetCurrentValue := TGLNavigatorSmoothChangeVector(Source).FOnGetCurrentValue;
1591
FOnSetCurrentValue := TGLNavigatorSmoothChangeVector(Source).FOnSetCurrentValue;
1595
constructor TGLNavigatorSmoothChangeVector.Create(aOwner: TGLXCollection);
1598
FTargetValue := TGLCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
1601
destructor TGLNavigatorSmoothChangeVector.Destroy;
1607
class function TGLNavigatorSmoothChangeVector.FriendlyName: string;
1609
Result := 'Navigator SmoothChange Vector';
1612
function TGLNavigatorSmoothChangeVector.Proceed(ADeltaTime: Double): Boolean;
1614
lAbsolutePosition: TVector;
1615
lCurrentDistance: Single;
1616
lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
1617
lMaxExpectedDeltaTime: Double;
1619
procedure DoAdjustDistanceToPoint();
1623
vect := VectorScale(VectorNormalize(VectorSubtract(FTargetValue.DirectVector, lAbsolutePosition)), lTotalDistanceToTravelThisTime);
1624
AddVector(vect, lAbsolutePosition);
1626
// Did we go too far?
1627
if VectorDistance(vect, FTargetValue.DirectVector) > VectorDistance(lAbsolutePosition, FTargetValue.DirectVector) then
1628
vect := FTargetValue.DirectVector;
1630
FOnSetCurrentValue(Self, vect);
1636
if not FEnabled then Exit;
1637
if not Assigned(FOnGetCurrentValue) then Exit;
1638
if not Assigned(FOnSetCurrentValue) then Exit;
1640
lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
1641
lAbsolutePosition := FOnGetCurrentValue(Self);
1642
lCurrentDistance := VectorDistance(lAbsolutePosition, FTargetValue.DirectVector);
1644
lTotalDistanceToTravelThisTime := 0;
1647
while ADeltaTime > lMaxExpectedDeltaTime do
1649
lDistanceToTravelThisTime := MinFloat((lCurrentDistance * ADeltaTime * FSpeed * FInertia) / (FInertia + 1), FSpeedLimit);
1650
// lDistanceToTravelThisTime := (lCurrentDistance * ADeltaTime + FSpeed * FInertia) / (FInertia + 1);- this also works, but a bit different.
1652
lCurrentDistance := lCurrentDistance - lDistanceToTravelThisTime;
1653
lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
1654
ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
1657
if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
1658
DoAdjustDistanceToPoint();
1661
procedure TGLNavigatorSmoothChangeVector.ResetTargetValue;
1663
FTargetValue.DirectVector := FOnGetCurrentValue(Self);
1666
procedure TGLNavigatorSmoothChangeVector.SetTargetValue(
1667
const Value: TGLCoordinates);
1669
FTargetValue.Assign(Value);
1674
TGLSmoothNavigator, TGLSmoothUserInterface,
1675
TGLNavigatorInertiaParameters, TGLNavigatorGeneralParameters,
1676
TGLNavigatorMoveAroundParameters,
1677
TGLNavigatorAdjustDistanceParameters, TGLNavigatorAdjustDistanceParametersEx
1680
RegisterXCollectionItemClass(TGLNavigatorSmoothChangeSingle);
1681
RegisterXCollectionItemClass(TGLNavigatorSmoothChangeVector);