LZScene

Форк
0
/
GLSmoothNavigator.pas 
1682 строки · 55.7 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
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.
8

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
13
   glscene newsgroups.
14

15

16
    History :  
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)
25

26

27
    TODO:
28
      1) Scale "Old values" too, when callin the Scale parameter procedure to
29
         avoid the temporary "freeze" of controls.
30
      2) AddImpulse procedures.
31

32

33

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
45
}
46

47
unit GLSmoothNavigator;
48

49
interface
50

51
{$I GLScene.inc}
52

53
uses
54
  // VCL
55
  Classes,
56

57
  GLNavigator, GLVectorGeometry, GLScene, GLCrossPlatform, GLCoordinates,
58
  GLScreen, GLXCollection;
59

60
type
61

62
  { TGLNavigatorAdjustDistanceParameters includes a basic set of parameters
63
     that control the smoothness of movement.
64
  }
65
  TGLNavigatorAbstractParameters = class(TPersistent)
66
  private
67
    FOwner: TPersistent;
68
    FInertia: Single;
69
    FSpeed: Single;
70
    FCutoff: Single;
71
    function StoreCutoff: Boolean;
72
  protected
73
    function StoreInertia: Boolean; virtual;
74
    function StoreSpeed: Boolean; virtual;
75
      
76
    function GetOwner: TPersistent; override;
77
  public
78
    constructor Create(AOwner: TPersistent); virtual;
79
    procedure Assign(Source: TPersistent); override;
80
    procedure ScaleParameters(const Value: Single); virtual;
81
  published
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; 
85
  end;
86

87
  TGLSmoothNavigator = class;
88

89
  { TGLNavigatorSmoothChangeItem includes a basic set of parameters
90
     that control the smoothness of movement.
91
  }
92
  TGLNavigatorSmoothChangeItem = class(TGLXCollectionItem)
93
  private
94
    FInertia: Single;
95
    FSpeed: Single;
96
    FEnabled: Boolean;
97
    FSpeedLimit: Single;
98
    FCutoff: Double;
99
    function StoreInertia: Boolean;
100
    function StoreSpeed: Boolean;
101
    function StoreSpeedLimit: Boolean;
102
    function StoreCutoff: Boolean;
103
  protected
104
    function GetNavigator: TGLSmoothNavigator;
105
  public
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;
112
  published
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;
118
  end;
119

120
  TGLNavigatorSmoothChangeSingle = class;
121
  TGLNavigatorSmoothChangeSingleGetEvent = function(const ASender: TGLNavigatorSmoothChangeSingle): Single of object;
122
  TGLNavigatorSmoothChangeSingleSetEvent = procedure(const ASender: TGLNavigatorSmoothChangeSingle; const AValue: Single) of object;
123

124
  { Smoothly change any Single value, so it will become TargetValue in the end. }
125
  TGLNavigatorSmoothChangeSingle = class(TGLNavigatorSmoothChangeItem)
126
  private
127
    FTargetValue: Single;
128
    FOnGetCurrentValue: TGLNavigatorSmoothChangeSingleGetEvent;
129
    FOnSetCurrentValue: TGLNavigatorSmoothChangeSingleSetEvent;
130
  public
131
    class function FriendlyName: string; override;
132
    function Proceed(ADeltaTime: Double): Boolean; override;
133
    procedure Assign(Source: TPersistent); override;
134
    procedure ResetTargetValue(); override;    
135
  published
136
    property TargetValue: Single read FTargetValue write FTargetValue;
137
    property OnGetCurrentValue: TGLNavigatorSmoothChangeSingleGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
138
    property OnSetCurrentValue: TGLNavigatorSmoothChangeSingleSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
139
  end;
140

141
  TGLNavigatorSmoothChangeVector = class;
142
  TGLNavigatorSmoothChangeVectorGetEvent = function(const ASender: TGLNavigatorSmoothChangeVector): TVector of object;
143
  TGLNavigatorSmoothChangeVectorSetEvent = procedure(const ASender: TGLNavigatorSmoothChangeVector; const AValue: TVector) of object;
144

145
  { Smoothly change any Vector4f value, so it will become TargetValue in the end. }
146
  TGLNavigatorSmoothChangeVector = class(TGLNavigatorSmoothChangeItem)
147
  private
148
    FTargetValue: TGLCoordinates;
149
    FOnGetCurrentValue: TGLNavigatorSmoothChangeVectorGetEvent;
150
    FOnSetCurrentValue: TGLNavigatorSmoothChangeVectorSetEvent;
151
    procedure SetTargetValue(const Value: TGLCoordinates);
152
  public
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;
159
  published
160
    property TargetValue: TGLCoordinates read FTargetValue write SetTargetValue;
161
    property OnGetCurrentValue: TGLNavigatorSmoothChangeVectorGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
162
    property OnSetCurrentValue: TGLNavigatorSmoothChangeVectorSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
163
  end;
164

165
  TGLNavigatorSmoothChangeItemClass = class of TGLNavigatorSmoothChangeItem;
166

167
  { XCollection of TGLNavigatorSmoothChangeItem. }
168
  TGLNavigatorSmoothChangeItems = class(TGLXCollection)
169
  private
170
    function GetItems(const Index : Integer): TGLNavigatorSmoothChangeItem;
171
    procedure SetItems(const Index : Integer; const Value: TGLNavigatorSmoothChangeItem);
172
  protected
173
    procedure DoProceed(ADeltaTime: Double);
174
  public
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
179
            SetItems; default;
180
  end;
181

182
  { TGLNavigatorAdjustDistanceParameters is wrapper for all parameters that
183
       affect how the AdjustDisanceTo[...] methods work
184
  }
185
  TGLNavigatorAdjustDistanceParameters = class(TGLNavigatorAbstractParameters)
186
  private
187
    FOldDistanceRatio: Single;
188
    FImpulseSpeed: Single;
189
    function StoreImpulseSpeed: Boolean;
190
  public
191
    constructor Create(AOwner: TPersistent); override;
192
    procedure Assign(Source: TPersistent); override;
193
    procedure ScaleParameters(const Value: Single); override;
194

195
    procedure AddImpulse(const Impulse: Single); virtual;
196
  published
197
    property ImpulseSpeed: Single read FImpulseSpeed write FImpulseSpeed stored StoreImpulseSpeed;
198
  end;
199

200
  { TGLNavigatorAdjustDistanceParameters is wrapper for all parameters that
201
       affect how the AdjustDisanceTo[...]Ex methods work
202

203
     You need to set the TargetObject and desired distance to it,
204
     then call AdjustDisanceTo[...]Ex() in your Cadencer.OnProgress code.
205
  }
206
  TGLNavigatorAdjustDistanceParametersEx = class(TGLNavigatorAbstractParameters)
207
  private
208
    FSpeedLimit: Single;
209
    FTargetDistance: Single;
210
    function StoreSpeedLimit: Boolean;
211
    function StoreTargetDistance: Boolean;
212
  protected
213
    function StoreSpeed: Boolean; override;
214
    function StoreInertia: Boolean; override;    
215
  public
216
    constructor Create(AOwner: TPersistent); override;
217
    procedure Assign(Source: TPersistent); override;
218
  published
219
    property TargetDistance: Single read FTargetDistance write FTargetDistance stored StoreTargetDistance;
220
    property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
221
  end;
222

223
  { TGLNavigatorInertiaParameters is wrapper for all parameters that affect the
224
       smoothness of movement
225
  }
226
  TGLNavigatorInertiaParameters = class(TPersistent)
227
  private
228
    FOwner: TPersistent;
229

230
    OldTurnHorizontalAngle: Single;
231
    OldTurnVerticalAngle: Single;
232

233
    OldMoveForwardDistance: Single;
234
    OldStrafeHorizontalDistance: Single;
235
    OldStrafeVerticalDistance: Single;
236

237
    FTurnInertia: Single;
238
    FTurnSpeed: Single;
239
    FTurnMaxAngle: Single;
240
    FMovementAcceleration: Single;
241
    FMovementInertia: Single;
242
    FMovementSpeed: Single;
243

244
    function StoreTurnMaxAngle: Boolean;
245
    function StoreMovementAcceleration: Boolean;
246
    function StoreMovementInertia: Boolean;
247
    function StoreMovementSpeed: Boolean;
248
    function StoreTurnInertia: Boolean;
249
    function StoreTurnSpeed: Boolean;
250
  protected
251
    function GetOwner: TPersistent; override;
252
  public
253
    constructor Create(AOwner: TPersistent); virtual;
254
    procedure Assign(Source: TPersistent); override;
255
    procedure ScaleParameters(const Value: Single); virtual;
256
  published
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;
260

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;
264
  end;
265

266

267
  { TGLNavigatorGeneralParameters is a wrapper for all general inertia parameters.
268

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.
273
  }
274
  TGLNavigatorGeneralParameters = class(TPersistent)
275
  private
276
    FOwner: TPersistent;
277
    FAutoScaleMin: Single;
278
    FAutoScaleMax: Single;
279
    FAutoScaleMult: Single;
280

281
    function StoreAutoScaleMax: Boolean;
282
    function StoreAutoScaleMin: Boolean;
283
    function StoreAutoScaleMult: Boolean;
284
  protected
285
    function GetOwner: TPersistent; override;
286
  public
287
    constructor Create(AOwner: TPersistent); virtual;
288
    procedure Assign(Source: TPersistent); override;
289
  published
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;
293
  end;
294

295

296
  { TGLNavigatorMoveAroundParameters is a wrapper for all parameters that
297
      effect how the TGLBaseSceneObject.MoveObjectAround() procedure works
298
  }
299
  TGLNavigatorMoveAroundParameters = class(TPersistent)
300
  private
301
    FOwner: TPersistent;
302
    FTargetObject: TGLBaseSceneObject;
303

304
    FOldPitchInertiaAngle : Single;
305
    FOldTurnInertiaAngle  : Single;
306

307
    FPitchSpeed : Single;
308
    FTurnSpeed  : Single;
309
    FInertia          : Single;
310
    FMaxAngle         : Single;
311
    FCutoff: Double;
312

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;
319
  protected
320
    function GetOwner: TPersistent; override;
321
  public
322
    constructor Create(AOwner: TPersistent); virtual;
323
    procedure Assign(Source: TPersistent); override;
324
    procedure ScaleParameters(const Value: Single); virtual;
325
  published
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;    
332
  end;
333

334

335
  // TGLSmoothNavigator
336
  //
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.
339

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.
343
  }
344
  TGLSmoothNavigator = class(TGLNavigator)
345
  private
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);
362
  protected
363
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
364
  public
365
    // Constructors-destructors.
366
    constructor Create(AOwner: TComponent); override;
367
    destructor Destroy; override;
368

369
    // From TGLNavigator. Probably, should not be public.
370
    procedure SetObject(Value: TGLBaseSceneObject); override;
371

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;
379

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;
383

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;
387

388
    // Uses AdjustDistanceParamsEx.
389
    function AdjustDistanceToPointEx(const  APoint: TVector; ADeltaTime: Double): Boolean; virtual;
390
    function AdjustDistanceToTargetEx(const ADeltaTime: Double): Boolean; virtual;
391

392
    // Uses CustomAnimatedItems.
393
    procedure AnimateCustomItems(const ADeltaTime: Double); virtual;
394

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;
400
  published
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;
408
  end;
409

410

411
  // TGLSmoothUserInterface
412
  //
413
  { TGLSmoothUserInterface is the component which reads the userinput and transform it into action.
414
       
415
	    Mouselook(ADeltaTime: double) : handles mouse look... Should be called
416
                           in the Cadencer event. (Though it works everywhere!)
417
       
418
	   The four properties to get you started are:
419
       
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....
425
       
426
   }
427
  TGLSmoothUserInterface = class(TComponent)
428
  private
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;
439
  protected
440
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
441
  public
442
    constructor Create(AOwner: TComponent); override;
443
    destructor Destroy; override;
444

445
    procedure TurnHorizontal(const Angle : Single; const ADeltaTime: Double); virtual;
446
    procedure TurnVertical(const Angle : Single; const ADeltaTime: Double); virtual;
447
    procedure MouseLookActiveToggle; virtual;
448

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;
452
  published
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;
459
  end;
460

461
implementation
462

463
const
464
  EPS =  0.001;
465
  EPS2 = 0.0001;
466
  EPS8 = 0.00000001;
467

468
{ TGLSmoothNavigator }
469

470
constructor TGLSmoothNavigator.Create(AOwner: TComponent);
471
begin
472
  inherited;
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);
480
end;
481

482
destructor TGLSmoothNavigator.Destroy;
483
begin
484
  FInertiaParams.Free;
485
  FGeneralParams.Free;
486
  FMoveAroundParams.Free;
487
  FAdjustDistanceParams.Free;
488
  FAdjustDistanceParamsEx.Free;
489
  FCustomAnimatedItems.Free;
490
  inherited;
491
end;
492

493
procedure TGLSmoothNavigator.SetInertiaParams(
494
  const Value: TGLNavigatorInertiaParameters);
495
begin
496
  FInertiaParams.Assign(Value);
497
end;
498

499
procedure TGLSmoothNavigator.TurnHorizontal(Angle: Single; ADeltaTime: Double);
500
var
501
  FinalAngle: Single;
502
begin
503
  with FInertiaParams do
504
  begin
505
    FinalAngle := 0;
506
    Angle := Angle * FTurnSpeed;
507
    while ADeltaTime > FMaxExpectedDeltaTime do
508
    begin
509
      Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnHorizontalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
510
      OldTurnHorizontalAngle := Angle;
511
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
512
      FinalAngle := FinalAngle + Angle;
513
    end;
514
  end;
515

516
  if (Abs(FinalAngle) > EPS) then
517
    inherited TurnHorizontal(FinalAngle);
518
end;
519

520
procedure TGLSmoothNavigator.TurnVertical(Angle: Single; ADeltaTime: Double);
521
var
522
  FinalAngle: Single;
523
begin
524
  with FInertiaParams do
525
  begin
526
    FinalAngle := 0;
527
    Angle := Angle * FTurnSpeed;
528
    while ADeltaTime > FMaxExpectedDeltaTime do
529
    begin
530
      Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnVerticalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
531
      OldTurnVerticalAngle := Angle;
532
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
533
      FinalAngle := FinalAngle + Angle;
534
    end;
535
  end;
536

537
  if (Abs(FinalAngle) > EPS) then
538
    inherited TurnVertical(FinalAngle);
539
end;
540

541

542
procedure TGLSmoothNavigator.MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
543
var
544
  FinalDistance: Single;
545
  Distance:      Single;
546
begin
547
  with FInertiaParams do
548
  begin
549
    if Plus then
550
      Distance := FMovementSpeed
551
    else if Minus then
552
      Distance := -FMovementSpeed
553
    else
554
      Distance := 0;
555

556
    if Accelerate then
557
      Distance := Distance * FMovementAcceleration;
558

559
    FinalDistance := 0;
560

561
    while ADeltaTime > FMaxExpectedDeltaTime do
562
    begin
563
      OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
564
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
565
      FinalDistance := FinalDistance + OldMoveForwardDistance;
566
    end;
567
  end;
568

569
  if Abs(FinalDistance) > EPS then
570
    inherited MoveForward(FinalDistance);
571
end;
572

573
procedure TGLSmoothNavigator.FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
574
var
575
  FinalDistance: Single;
576
  Distance:      Single;
577
begin
578
  with FInertiaParams do
579
  begin
580
    if Plus then
581
      Distance := FMovementSpeed
582
    else if Minus then
583
      Distance := -FMovementSpeed
584
    else
585
      Distance := 0;
586

587
    if Accelerate then
588
      Distance := Distance * FMovementAcceleration;
589

590
    FinalDistance := 0;
591

592
    while ADeltaTime > FMaxExpectedDeltaTime do
593
    begin
594
      OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
595
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
596
      FinalDistance := FinalDistance + OldMoveForwardDistance;
597
    end;
598
  end;
599

600
  if Abs(FinalDistance) > EPS then
601
    inherited FlyForward(FinalDistance);
602
end;
603

604
procedure TGLSmoothNavigator.StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
605
var
606
  FinalDistance: Single;
607
  Distance:      Single;
608
begin
609
  with FInertiaParams do
610
  begin
611
    if Plus then
612
      Distance := FMovementSpeed
613
    else if Minus then
614
      Distance := -FMovementSpeed
615
    else
616
      Distance := 0;
617

618
    if Accelerate then
619
      Distance := Distance * FMovementAcceleration;
620

621
    FinalDistance := 0;
622

623
    while ADeltaTime > FMaxExpectedDeltaTime do
624
    begin
625
      OldStrafeHorizontalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeHorizontalDistance * FMovementInertia) / (FMovementInertia + 1);
626
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
627
      FinalDistance := FinalDistance + OldStrafeHorizontalDistance;
628
    end;
629
  end;
630

631
  if Abs(FinalDistance) > EPS then
632
    inherited StrafeHorizontal(FinalDistance);
633
end;
634

635
procedure TGLSmoothNavigator.StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
636
var
637
  FinalDistance: Single;
638
  Distance:      Single;
639
begin
640
  with FInertiaParams do
641
  begin
642
    if Plus then
643
      Distance := FMovementSpeed
644
    else if Minus then
645
      Distance := -FMovementSpeed
646
    else
647
      Distance := 0;
648

649
    if Accelerate then
650
      Distance := Distance * FMovementAcceleration;
651

652
    FinalDistance := 0;
653

654
    while ADeltaTime > FMaxExpectedDeltaTime do
655
    begin
656
      OldStrafeVerticalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeVerticalDistance * FMovementInertia) / (FMovementInertia + 1);
657
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
658
      FinalDistance := FinalDistance + OldStrafeVerticalDistance;
659
    end;
660
  end;
661

662
  if Abs(FinalDistance) > EPS then
663
    inherited StrafeVertical(FinalDistance);
664
end;
665

666
procedure TGLSmoothNavigator.AutoScaleParameters(const FPS: Single);
667
begin
668
  with FGeneralParams do
669
  begin
670
    if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
671
      ScaleParameters(FAutoScaleMult)
672
    else if FPS < FAutoScaleMin / FMaxExpectedDeltatime then
673
      ScaleParameters(1/FAutoScaleMult);
674
  end;
675
end;
676

677

678
procedure TGLSmoothNavigator.AutoScaleParametersUp(const FPS: Single);
679
begin
680
  with FGeneralParams do
681
  begin
682
    if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
683
      ScaleParameters(FAutoScaleMult)
684
  end;
685
end;
686

687
procedure TGLSmoothNavigator.ScaleParameters(const Value: Single);
688
begin
689
  Assert(Value > 0);
690
  FMaxExpectedDeltatime := FMaxExpectedDeltatime / Value;
691
  FInertiaParams.ScaleParameters(Value);
692
  FMoveAroundParams.ScaleParameters(Value);
693
  FAdjustDistanceParams.ScaleParameters(Value);
694
end;
695

696
function TGLSmoothNavigator.StoreMaxExpectedDeltaTime: Boolean;
697
begin
698
  Result := Abs(FMaxExpectedDeltaTime - 0.001) > EPS2;
699
end;
700

701
procedure TGLSmoothNavigator.SetGeneralParams(
702
  const Value: TGLNavigatorGeneralParameters);
703
begin
704
  FGeneralParams.Assign(Value);
705
end;
706

707
procedure TGLSmoothNavigator.SetMoveAroundParams(
708
  const Value: TGLNavigatorMoveAroundParameters);
709
begin
710
  FMoveAroundParams.Assign(Value);
711
end;
712

713
procedure TGLSmoothNavigator.Notification(AComponent: TComponent;
714
  Operation: TOperation);
715
begin
716
  inherited;
717
  if Operation = opRemove then
718
  begin
719
    if AComponent = FMoveAroundParams.FTargetObject then
720
      FMoveAroundParams.FTargetObject := nil;
721
  end;
722
end;
723

724
procedure TGLSmoothNavigator.SetObject(Value: TGLBaseSceneObject);
725
var
726
  I: Integer;
727
begin
728
  inherited;
729
  // Try to detect a TargetObject.
730
  if Value <> nil then
731
    if FMoveAroundParams.TargetObject = nil then
732
    begin
733
      // May be it is a camera...
734
      if Value is TGLCamera then
735
        FMoveAroundParams.TargetObject := TGLCamera(Value).TargetObject
736
      else
737
      begin
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
742
            begin
743
              FMoveAroundParams.TargetObject := TGLCamera(Value.Children[I]).TargetObject;
744
              Exit;
745
            end;
746
      end;
747
    end;
748
end;
749

750
function TGLSmoothNavigator.MoveAroundTarget(const PitchDelta, TurnDelta: Single;
751
  const ADeltaTime: Double): Boolean;
752
begin
753
  Result := MoveObjectAround(FMoveAroundParams.FTargetObject, PitchDelta, TurnDelta, ADeltaTime);
754
end;
755

756
function TGLSmoothNavigator.MoveObjectAround(
757
  const AObject: TGLBaseSceneObject; PitchDelta, TurnDelta: Single;
758
  ADeltaTime: Double): Boolean;
759
var
760
  FinalPitch: Single;
761
  FinalTurn:  Single;
762

763
  lUp: TVector;
764
begin
765
  Result := False;
766
  FinalPitch := 0;
767
  FinalTurn := 0;
768
  with FMoveAroundParams do
769
  begin
770
    PitchDelta := PitchDelta * FPitchSpeed;
771
    TurnDelta := TurnDelta * FTurnSpeed;
772

773
    while ADeltaTime > FMaxExpectedDeltatime do
774
    begin
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;
781

782
      ADeltaTime := ADeltaTime - FMaxExpectedDeltatime;
783
    end;
784

785
    if UseVirtualUp then
786
      lUp := VirtualUp.AsVector
787
    else
788
      lUp := MovingObject.AbsoluteUp;
789

790
    if (Abs(FinalPitch) > FCutOff) or (Abs(FinalTurn) > FCutOff) then
791
    begin
792
      MovingObject.AbsolutePosition := GLVectorGeometry.MoveObjectAround(
793
        MovingObject.AbsolutePosition, lUp, AObject.AbsolutePosition, FinalPitch, FinalTurn);
794
      Result := True;
795
    end;
796
  end;
797
end;
798

799

800
function TGLSmoothNavigator.AdjustDistanceToPoint(const APoint: TVector;
801
  const DistanceRatio: Single; ADeltaTime: Double): Boolean;
802

803
  // Based on TGLCamera.AdjustDistanceToTarget
804
  procedure DoAdjustDistanceToPoint(const DistanceRatio: Single);
805
  var
806
    vect: TVector;
807
  begin
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;
814
    Result := True;
815
  end;
816

817
var
818
  FinalDistanceRatio: Single;
819
  TempDistanceRatio:  Single;
820
begin
821
  with FAdjustDistanceParams do
822
  begin
823
    TempDistanceRatio := DistanceRatio * FSpeed;
824
    FinalDistanceRatio := 0;
825
    while ADeltaTime > FMaxExpectedDeltaTime do
826
    begin
827
      TempDistanceRatio := (TempDistanceRatio * FMaxExpectedDeltaTime + FOldDistanceRatio * FInertia) / (FInertia + 1);
828
      FOldDistanceRatio := TempDistanceRatio;
829
      ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
830
      FinalDistanceRatio := FinalDistanceRatio + FOldDistanceRatio / FMaxExpectedDeltaTime;
831
    end;
832

833
    if Abs(FinalDistanceRatio) > FCutoff then
834
    begin
835
      if FinalDistanceRatio > 0 then
836
        DoAdjustDistanceToPoint(1 / (1 + FinalDistanceRatio))
837
      else
838
        DoAdjustDistanceToPoint(1 * (1 - FinalDistanceRatio))
839
    end
840
    else
841
      Result := False;
842
  end;
843
end;
844

845
function TGLSmoothNavigator.AdjustDistanceToTarget(const DistanceRatio: Single;
846
  const ADeltaTime: Double): Boolean;
847
begin
848
  Assert(FMoveAroundParams.FTargetObject <> nil);
849
  Result := AdjustDistanceToPoint(FMoveAroundParams.FTargetObject.AbsolutePosition,
850
                        DistanceRatio, ADeltaTime);
851
end;
852

853
procedure TGLSmoothNavigator.SetAdjustDistanceParams(
854
  const Value: TGLNavigatorAdjustDistanceParameters);
855
begin
856
  FAdjustDistanceParams.Assign(Value);
857
end;
858

859
function TGLSmoothNavigator.AdjustDistanceToPointEx(const APoint: TVector;
860
  ADeltaTime: Double): Boolean;
861

862
var
863
  lAbsolutePosition: TVector;
864
  lCurrentDistance: Single;
865
  lDistanceDifference, lTempCurrentDistance: Single;
866

867
  procedure DoAdjustDistanceToPoint(const DistanceValue: Single);
868
  var
869
    vect: TVector;
870
  begin
871
    vect := VectorSubtract(APoint, lAbsolutePosition);
872
    NormalizeVector(vect);
873
    ScaleVector(vect, DistanceValue);
874
    MovingObject.AbsolutePosition := VectorAdd(lAbsolutePosition, vect);
875
    Result := True;
876
  end;
877

878
begin
879
  lAbsolutePosition := MovingObject.AbsolutePosition;
880
  lCurrentDistance := VectorDistance(lAbsolutePosition, APoint);
881
  lDistanceDifference := lCurrentDistance - FAdjustDistanceParamsEx.FTargetDistance;
882

883
  with FAdjustDistanceParamsEx do
884
  begin
885
    lTempCurrentDistance := 0;
886
    while ADeltaTime > FMaxExpectedDeltaTime do
887
    begin
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;
891
    end;
892
    
893
    lTempCurrentDistance :=  ClampValue(lTempCurrentDistance, -FSpeedLimit * ADeltaTime, FSpeedLimit * ADeltaTime);
894

895
    if Abs(lTempCurrentDistance) > FCutoff then
896
      DoAdjustDistanceToPoint(lTempCurrentDistance)
897
    else
898
      Result := False;
899
  end;
900
end;
901

902
function TGLSmoothNavigator.AdjustDistanceToTargetEx(
903
  const ADeltaTime: Double): Boolean;
904
begin
905
  Assert(FMoveAroundParams.FTargetObject <> nil);
906
  Result := AdjustDistanceToPointEx(FMoveAroundParams.FTargetObject.AbsolutePosition,
907
                          ADeltaTime);
908
end;
909

910
procedure TGLSmoothNavigator.SetAdjustDistanceParamsEx(
911
  const Value: TGLNavigatorAdjustDistanceParametersEx);
912
begin
913
  FAdjustDistanceParamsEx.Assign(Value);
914
end;
915

916
procedure TGLSmoothNavigator.AnimateCustomItems(const ADeltaTime: Double);
917
begin
918
  FCustomAnimatedItems.DoProceed(ADeltaTime);
919
end;
920

921
procedure TGLSmoothNavigator.SetCustomAnimatedItems(
922
  const Value: TGLNavigatorSmoothChangeItems);
923
begin
924
  FCustomAnimatedItems.Assign(Value);
925
end;
926

927
{ TGLSmoothUserInterface }
928

929
function TGLSmoothUserInterface.MouseLook(
930
  const ADeltaTime: Double): Boolean;
931
var
932
  MousePos: TGLPoint;
933
begin
934
  Assert(FAutoUpdateMouse, 'AutoUpdateMouse must be True to use this function');
935
  if FMouseLookActive then
936
  begin
937
    GLGetCursorPos(MousePos);
938
    Result := Mouselook(MousePos.X, MousePos.Y, ADeltaTime);
939
    GLSetCursorPos(Round(OriginalMousePos.X), Round(OriginalMousePos.Y));
940
  end
941
  else
942
    Result := False;
943
end;
944

945
function TGLSmoothUserInterface.Mouselook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean;
946
var
947
  DeltaX, DeltaY: Single;
948
begin
949
  Result := False;
950
  if FMouseLookActive then
951
  begin
952
    Deltax := (NewX - FOriginalMousePos.X);
953
    Deltay := (FOriginalMousePos.Y - NewY);
954

955
    if InvertMouse then
956
      DeltaY := -DeltaY;
957

958
    SmoothNavigator.TurnHorizontal(DeltaX, ADeltaTime);
959
    SmoothNavigator.TurnVertical(DeltaY, ADeltaTime);
960

961
    Result := (DeltaX <> 0) or (DeltaY <> 0);
962
  end;
963
end;
964

965

966
function TGLSmoothUserInterface.MouseLook(const NewXY: TGLPoint; const ADeltaTime: Double): Boolean;
967
begin
968
  Result := Mouselook(NewXY.X, NewXY.Y, ADeltaTime);
969
end;
970

971
constructor TGLSmoothUserInterface.Create(AOwner: TComponent);
972
begin
973
  inherited;
974
  FMouseLookActive := False;
975
  FAutoUpdateMouse := True;
976
  FOriginalMousePos := TGLCoordinates2.CreateInitialized(Self,
977
                             VectorMake(GLGetScreenWidth div 2,
978
                             GLGetScreenHeight div 2, 0, 0), csPoint2D);
979
end;
980

981
procedure TGLSmoothUserInterface.Notification(AComponent: TComponent;
982
  Operation: TOperation);
983
begin
984
  inherited;
985
  if (Operation = opRemove) then
986
  begin
987
    if AComponent = FSmoothNavigator then
988
      FSmoothNavigator := nil;
989
    if AComponent = FSmoothVertNavigator then
990
      FSmoothNavigator := nil;
991
  end;
992
end;
993

994
procedure TGLSmoothUserInterface.SetSmoothNavigator(
995
  const Value: TGLSmoothNavigator);
996
begin
997
  if FSmoothNavigator <> nil then
998
    FSmoothNavigator.RemoveFreeNotification(Self);
999

1000
  FSmoothNavigator := Value;
1001

1002
  if FSmoothNavigator <> nil then
1003
    FSmoothNavigator.FreeNotification(Self);
1004
end;
1005

1006
destructor TGLSmoothUserInterface.Destroy;
1007
begin
1008
  FOriginalMousePos.Destroy;
1009
  inherited;
1010
end;
1011

1012
procedure TGLSmoothUserInterface.SetOriginalMousePos(
1013
  const Value: TGLCoordinates2);
1014
begin
1015
  FOriginalMousePos.Assign(Value);
1016
end;
1017

1018
procedure TGLSmoothUserInterface.SetSmoothVertNavigator(
1019
  const Value: TGLSmoothNavigator);
1020
begin
1021
  if FSmoothVertNavigator <> nil then
1022
    FSmoothVertNavigator.RemoveFreeNotification(Self);
1023

1024
  FSmoothVertNavigator := Value;
1025

1026
  if FSmoothVertNavigator <> nil then
1027
    FSmoothVertNavigator.FreeNotification(Self);
1028
end;
1029

1030
procedure TGLSmoothUserInterface.MouseLookActiveToggle;
1031
begin
1032
  if FMouseLookActive then
1033
    SetMouseLookActive(False)
1034
  else
1035
    SetMouseLookActive(True)
1036
end;
1037

1038
procedure TGLSmoothUserInterface.SetMouseLookActive(const Value: Boolean);
1039
var
1040
  MousePos: TGLPoint;
1041
begin
1042
  if FMouseLookActive = Value then Exit;
1043
  FMouseLookActive := Value;
1044
  if FMouseLookActive then
1045
  begin
1046
    if FAutoUpdateMouse then
1047
    begin
1048
      GLGetCursorPos(MousePos);
1049
      FOriginalMousePos.SetPoint2D(MousePos.X, MousePos.Y);
1050
      GLShowCursor(False);
1051
    end;
1052
  end
1053
  else
1054
  begin
1055
    if FAutoUpdateMouse then
1056
      GLShowCursor(True);
1057
  end;
1058
end;
1059

1060
procedure TGLSmoothUserInterface.TurnHorizontal(const Angle: Single;
1061
  const ADeltaTime: Double);
1062
begin
1063
  FSmoothNavigator.TurnHorizontal(Angle, ADeltaTime);
1064
end;
1065

1066
procedure TGLSmoothUserInterface.TurnVertical(const Angle: Single;
1067
  const ADeltaTime: Double);
1068
begin
1069
  if Assigned(FSmoothNavigator) then
1070
    FSmoothNavigator.TurnVertical(Angle, ADeltaTime)
1071
  else
1072
    FSmoothVertNavigator.TurnVertical(Angle, ADeltaTime);
1073
end;
1074

1075
{ TGLNavigatorInertiaParameters }
1076

1077
procedure TGLNavigatorInertiaParameters.Assign(Source: TPersistent);
1078
begin
1079
  if Source is TGLNavigatorInertiaParameters then
1080
  begin
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;
1087
  end
1088
  else
1089
    inherited; //to the pit of doom ;)
1090
end;
1091

1092
constructor TGLNavigatorInertiaParameters.Create(AOwner: TPersistent);
1093
begin
1094
  FOwner := AOwner;
1095

1096
  FTurnInertia := 150;
1097
  FTurnSpeed := 50;
1098
  FTurnMaxAngle := 0.5;
1099

1100
  FMovementAcceleration := 7;
1101
  FMovementInertia := 200;
1102
  FMovementSpeed := 200;
1103
end;
1104

1105
function TGLNavigatorInertiaParameters.GetOwner: TPersistent;
1106
begin
1107
  Result := FOwner;
1108
end;
1109

1110
procedure TGLNavigatorInertiaParameters.ScaleParameters(
1111
  const Value: Single);
1112
begin
1113
  Assert(Value > 0);
1114

1115
  if Value > 1 then
1116
  begin
1117
    FMovementInertia := FMovementInertia * GLVectorGeometry.Power(2, 1 / Value);
1118
    FTurnInertia := FTurnInertia * GLVectorGeometry.Power(2, 1 / Value);
1119
  end
1120
  else
1121
  begin
1122
    FMovementInertia := FMovementInertia / GLVectorGeometry.Power(2, Value);
1123
    FTurnInertia := FTurnInertia / GLVectorGeometry.Power(2, Value);
1124
  end;
1125
  FTurnMaxAngle := FTurnMaxAngle / Value;
1126
  FTurnSpeed := FTurnSpeed * Value;
1127
end;
1128

1129
function TGLNavigatorInertiaParameters.StoreTurnMaxAngle: Boolean;
1130
begin
1131
  Result := Abs(FTurnMaxAngle - 0.5) > EPS;
1132
end;
1133

1134
function TGLNavigatorInertiaParameters.StoreMovementAcceleration: Boolean;
1135
begin
1136
  Result := Abs(FMovementAcceleration - 7) > EPS;
1137
end;
1138

1139
function TGLNavigatorInertiaParameters.StoreMovementInertia: Boolean;
1140
begin
1141
  Result := Abs(FMovementInertia - 200) > EPS;
1142
end;
1143

1144
function TGLNavigatorInertiaParameters.StoreMovementSpeed: Boolean;
1145
begin
1146
  Result := Abs(FMovementSpeed - 200) > EPS;
1147
end;
1148

1149
function TGLNavigatorInertiaParameters.StoreTurnInertia: Boolean;
1150
begin
1151
  Result := Abs(FTurnInertia - 150) > EPS;
1152
end;
1153

1154
function TGLNavigatorInertiaParameters.StoreTurnSpeed: Boolean;
1155
begin
1156
  Result := Abs(FTurnSpeed - 50) > EPS;
1157
end;
1158

1159
{ TGLNavigatorGeneralParameters }
1160

1161
procedure TGLNavigatorGeneralParameters.Assign(Source: TPersistent);
1162
begin
1163
  if Source is TGLNavigatorGeneralParameters then
1164
  begin
1165
    FAutoScaleMin := TGLNavigatorGeneralParameters(Source).FAutoScaleMin;
1166
    FAutoScaleMax := TGLNavigatorGeneralParameters(Source).FAutoScaleMax;
1167
    FAutoScaleMult := TGLNavigatorGeneralParameters(Source).FAutoScaleMult;
1168
  end
1169
  else
1170
    inherited; //die!
1171
end;
1172

1173
constructor TGLNavigatorGeneralParameters.Create(AOwner: TPersistent);
1174
begin
1175
  FOwner := AOwner;
1176
  FAutoScaleMin := 0.1;
1177
  FAutoScaleMax := 0.75;
1178
  FAutoScaleMult := 2;
1179
end;
1180

1181
function TGLNavigatorGeneralParameters.GetOwner: TPersistent;
1182
begin
1183
  Result := FOwner;
1184
end;
1185

1186
function TGLNavigatorGeneralParameters.StoreAutoScaleMax: Boolean;
1187
begin
1188
  Result := Abs(FAutoScaleMax - 0.75) > EPS;
1189
end;
1190

1191
function TGLNavigatorGeneralParameters.StoreAutoScaleMin: Boolean;
1192
begin
1193
  Result := Abs(FAutoScaleMin - 0.1) > EPS;
1194
end;
1195

1196
function TGLNavigatorGeneralParameters.StoreAutoScaleMult: Boolean;
1197
begin
1198
  Result := Abs(FAutoScaleMult - 2) > EPS;
1199
end;
1200

1201
{ TGLNavigatorMoveAroundParameters }
1202

1203
procedure TGLNavigatorMoveAroundParameters.Assign(Source: TPersistent);
1204
begin
1205
  if Source is TGLNavigatorMoveAroundParameters then
1206
  begin
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);
1213
  end
1214
  else
1215
    inherited; //die
1216
end;
1217

1218
constructor TGLNavigatorMoveAroundParameters.Create(AOwner: TPersistent);
1219
begin
1220
  FOwner := AOwner;
1221
  FPitchSpeed := 500;
1222
  FTurnSpeed  := 500;
1223
  FInertia    := 65;
1224
  FMaxAngle   := 1.5;
1225
  FCutoff     := EPS2;
1226
end;
1227

1228
function TGLNavigatorMoveAroundParameters.GetOwner: TPersistent;
1229
begin
1230
  Result := FOwner;
1231
end;
1232

1233
procedure TGLNavigatorMoveAroundParameters.ScaleParameters(
1234
  const Value: Single);
1235
begin
1236
  Assert(Value > 0);
1237

1238
  if Value < 1 then
1239
    FInertia := FInertia / GLVectorGeometry.Power(2, Value)
1240
  else
1241
    FInertia := FInertia * GLVectorGeometry.Power(2, 1 / Value);
1242

1243
  FMaxAngle := FMaxAngle / Value;
1244
  FPitchSpeed := FPitchSpeed * Value;
1245
  FTurnSpeed := FTurnSpeed * Value;
1246
end;
1247

1248
procedure TGLNavigatorMoveAroundParameters.SetTargetObject(
1249
  const Value: TGLBaseSceneObject);
1250
begin
1251
  if FTargetObject <> nil then
1252
    if FOwner is TGLSmoothNavigator then
1253
      FTargetObject.RemoveFreeNotification(TGLSmoothNavigator(FOwner));
1254

1255
  FTargetObject := Value;
1256

1257
  if FTargetObject <> nil then
1258
    if FOwner is TGLSmoothNavigator then
1259
      FTargetObject.FreeNotification(TGLSmoothNavigator(FOwner));
1260
end;
1261

1262
function TGLNavigatorMoveAroundParameters.StoreCutoff: Boolean;
1263
begin
1264
  Result := Abs(FCutoff - EPS2) > EPS8;
1265
end;
1266

1267
function TGLNavigatorMoveAroundParameters.StoreInertia: Boolean;
1268
begin
1269
  Result := Abs(FInertia - 65) > EPS;
1270
end;
1271

1272
function TGLNavigatorMoveAroundParameters.StoreMaxAngle: Boolean;
1273
begin
1274
  Result := Abs(FMaxAngle - 1.5) > EPS;
1275
end;
1276

1277
function TGLNavigatorMoveAroundParameters.StorePitchSpeed: Boolean;
1278
begin
1279
  Result := Abs(FPitchSpeed - 500) > EPS;
1280
end;
1281

1282
function TGLNavigatorMoveAroundParameters.StoreTurnSpeed: Boolean;
1283
begin
1284
  Result := Abs(FTurnSpeed - 500) > EPS;
1285
end;
1286

1287
{ TGLNavigatorAdjustDistanceParameters }
1288

1289
procedure TGLNavigatorAdjustDistanceParameters.AddImpulse(
1290
  const Impulse: Single);
1291
begin
1292
  FOldDistanceRatio := FOldDistanceRatio + Impulse * FSpeed / FInertia * FImpulseSpeed;
1293
end;
1294

1295
procedure TGLNavigatorAdjustDistanceParameters.Assign(Source: TPersistent);
1296
begin
1297
  inherited Assign(Source);
1298
  if Source is TGLNavigatorAdjustDistanceParameters then
1299
  begin
1300
    FImpulseSpeed := TGLNavigatorAdjustDistanceParameters(Source).FImpulseSpeed;
1301
  end;
1302
end;
1303

1304
constructor TGLNavigatorAdjustDistanceParameters.Create(
1305
  AOwner: TPersistent);
1306
begin
1307
  inherited;
1308
  FImpulseSpeed := 0.02;
1309
end;
1310

1311

1312
procedure TGLNavigatorAdjustDistanceParameters.ScaleParameters(
1313
  const Value: Single);
1314
begin
1315
  inherited;
1316
  FImpulseSpeed := FImpulseSpeed / Value;
1317
end;
1318

1319
function TGLNavigatorAdjustDistanceParameters.StoreImpulseSpeed: Boolean;
1320
begin
1321
  Result := Abs(FImpulseSpeed - 0.02) > EPS;
1322
end;
1323

1324
{ TGLNavigatorAbstractParameters }
1325

1326

1327
procedure TGLNavigatorAbstractParameters.Assign(Source: TPersistent);
1328
begin
1329
  if Source is TGLNavigatorAbstractParameters then
1330
  begin
1331
    FInertia := TGLNavigatorAbstractParameters(Source).FInertia;
1332
    FSpeed :=   TGLNavigatorAbstractParameters(Source).FSpeed;
1333
    FCutoff :=  TGLNavigatorAbstractParameters(Source).FCutoff;
1334
  end
1335
  else
1336
    inherited; //to the pit of doom ;)
1337
end;
1338

1339
constructor TGLNavigatorAbstractParameters.Create(
1340
  AOwner: TPersistent);
1341
begin
1342
  FOwner := AOwner;
1343
  FInertia := 100;
1344
  FSpeed := 0.005;
1345
  FCutoff := EPS;
1346
end;
1347

1348
function TGLNavigatorAbstractParameters.GetOwner: TPersistent;
1349
begin
1350
  Result := FOwner;
1351
end;
1352

1353
procedure TGLNavigatorAbstractParameters.ScaleParameters(
1354
  const Value: Single);
1355
begin
1356
  Assert(Value > 0);
1357

1358
  if Value < 1 then
1359
    FInertia := FInertia / GLVectorGeometry.Power(2, Value)
1360
  else
1361
    FInertia := FInertia * GLVectorGeometry.Power(2, 1 / Value);
1362
end;
1363

1364
function TGLNavigatorAbstractParameters.StoreCutoff: Boolean;
1365
begin
1366
  Result := Abs(FCutoff - EPS) > EPS2;
1367
end;
1368

1369
function TGLNavigatorAbstractParameters.StoreInertia: Boolean;
1370
begin
1371
  Result := Abs(FInertia - 100) > EPS;
1372
end;
1373

1374
function TGLNavigatorAbstractParameters.StoreSpeed: Boolean;
1375
begin
1376
  Result := Abs(FSpeed - 0.005) > EPS2;
1377
end;
1378

1379
{ TGLNavigatorAdjustDistanceParametersEx }
1380

1381
procedure TGLNavigatorAdjustDistanceParametersEx.Assign(
1382
  Source: TPersistent);
1383
begin
1384
  if Source is TGLNavigatorAdjustDistanceParametersEx then
1385
  begin
1386
    FTargetDistance := TGLNavigatorAdjustDistanceParametersEx(Source).FTargetDistance;
1387
    FSpeedLimit := TGLNavigatorAdjustDistanceParametersEx(Source).FSpeedLimit;
1388
  end
1389
  else
1390
    inherited;
1391
end;
1392

1393
constructor TGLNavigatorAdjustDistanceParametersEx.Create(
1394
  AOwner: TPersistent);
1395
begin
1396
  inherited;
1397
  FInertia := 0.5;
1398
  FTargetDistance := 100;
1399
  FSpeed := 100;
1400
  FSpeedLimit := 20000;
1401
end;
1402

1403
function TGLNavigatorAdjustDistanceParametersEx.StoreInertia: Boolean;
1404
begin
1405
  Result := Abs(FInertia - 0.5) > EPS2;
1406
end;
1407

1408
function TGLNavigatorAdjustDistanceParametersEx.StoreSpeed: Boolean;
1409
begin
1410
  Result := Abs(FSpeed - 100) > EPS2;
1411
end;
1412

1413
function TGLNavigatorAdjustDistanceParametersEx.StoreSpeedLimit: Boolean;
1414
begin
1415
  Result := Abs(FSpeedLimit - 20000) > EPS2;
1416
end;
1417

1418
function TGLNavigatorAdjustDistanceParametersEx.StoreTargetDistance: Boolean;
1419
begin
1420
  Result := Abs(FTargetDistance - 100) > EPS2;
1421
end;
1422

1423
{ TGLNavigatorSmoothChangeItem }
1424

1425
procedure TGLNavigatorSmoothChangeItem.Assign(Source: TPersistent);
1426
begin
1427
  inherited Assign(Source);
1428

1429
  if Source is TGLNavigatorSmoothChangeItem then
1430
  begin
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;
1436
  end;
1437
end;
1438

1439
constructor TGLNavigatorSmoothChangeItem.Create(aOwner: TGLXCollection);
1440
begin
1441
  inherited;
1442
  FInertia := 1;
1443
  FSpeed := 5.5;
1444
  FSpeedLimit := 20000;
1445
  FCutoff := EPS;
1446
  FEnabled := True;
1447
end;
1448

1449
function TGLNavigatorSmoothChangeItem.GetNavigator: TGLSmoothNavigator;
1450
begin
1451
  Result := TGLSmoothNavigator(TGLNavigatorSmoothChangeItems(GetOwner).Owner);
1452
end;
1453

1454
procedure TGLNavigatorSmoothChangeItem.ScaleParameters(
1455
  const Value: Single);
1456
begin
1457
  Assert(Value > 0);
1458

1459
  if Value < 1 then
1460
    FInertia := FInertia / GLVectorGeometry.Power(2, Value)
1461
  else
1462
    FInertia := FInertia * GLVectorGeometry.Power(2, 1 / Value);
1463
end;
1464

1465
function TGLNavigatorSmoothChangeItem.StoreCutoff: Boolean;
1466
begin
1467
  Result := Abs(FCutoff - EPS) > EPS8;
1468
end;
1469

1470
function TGLNavigatorSmoothChangeItem.StoreInertia: Boolean;
1471
begin
1472
  Result := Abs(FInertia - 1) > EPS;
1473
end;
1474

1475
function TGLNavigatorSmoothChangeItem.StoreSpeed: Boolean;
1476
begin
1477
  Result := Abs(FSpeed - 5.5) > EPS2;
1478
end;
1479

1480
function TGLNavigatorSmoothChangeItem.StoreSpeedLimit: Boolean;
1481
begin
1482
  Result := Abs(FSpeedLimit - 20000) > EPS2;
1483
end;
1484

1485
{ TGLNavigatorSmoothChangeItems }
1486

1487
function TGLNavigatorSmoothChangeItems.Add(AClass : TGLNavigatorSmoothChangeItemClass): TGLNavigatorSmoothChangeItem;
1488
begin
1489
  Result := AClass.Create(Self);
1490
end;
1491

1492
function TGLNavigatorSmoothChangeItems.CanAdd(AClass: TGLXCollectionItemClass): Boolean;
1493
begin
1494
  Result := AClass.InheritsFrom(TGLNavigatorSmoothChangeItem);
1495
end;
1496

1497
procedure TGLNavigatorSmoothChangeItems.DoProceed(ADeltaTime: Double);
1498
var
1499
  I: Integer;
1500
begin
1501
  for I := 0 to Count - 1 do
1502
    GetItems(I).Proceed(ADeltaTime);
1503
end;
1504

1505
function TGLNavigatorSmoothChangeItems.GetItems(const Index : Integer): TGLNavigatorSmoothChangeItem;
1506
begin
1507
  Result := TGLNavigatorSmoothChangeItem(inherited GetItems(Index));
1508
end;
1509

1510
class function TGLNavigatorSmoothChangeItems.ItemsClass: TGLXCollectionItemClass;
1511
begin
1512
  Result := TGLNavigatorSmoothChangeItem;
1513
end;
1514

1515
procedure TGLNavigatorSmoothChangeItems.SetItems(const Index : Integer; const Value:
1516
        TGLNavigatorSmoothChangeItem);
1517
begin
1518
  GetItems(Index).Assign(Value);
1519
end;
1520

1521
{ TGLNavigatorSmoothChangeSingle }
1522

1523
procedure TGLNavigatorSmoothChangeSingle.Assign(Source: TPersistent);
1524
begin
1525
  inherited Assign(Source);
1526
  
1527
  if Source is TGLNavigatorSmoothChangeVector then
1528
  begin
1529
    FTargetValue := TGLNavigatorSmoothChangeSingle(Source).TargetValue;
1530
    FOnGetCurrentValue := TGLNavigatorSmoothChangeSingle(Source).FOnGetCurrentValue;
1531
    FOnSetCurrentValue := TGLNavigatorSmoothChangeSingle(Source).FOnSetCurrentValue;
1532
  end;
1533
end;
1534

1535
class function TGLNavigatorSmoothChangeSingle.FriendlyName: string;
1536
begin
1537
  Result := 'Navigator SmoothChange Single';
1538
end;
1539

1540
function TGLNavigatorSmoothChangeSingle.Proceed(ADeltaTime: Double): Boolean;
1541
var
1542
  lCurrentValue: Single;
1543
  lCurrentDifference: Single;
1544
  lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
1545
  lMaxExpectedDeltaTime: Double;
1546

1547
begin
1548
  Result := False;
1549
  if not FEnabled then Exit;
1550
  if not Assigned(FOnGetCurrentValue) then Exit;
1551
  if not Assigned(FOnSetCurrentValue) then Exit;
1552

1553
  lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
1554
  lCurrentValue := FOnGetCurrentValue(Self);
1555
  lCurrentDifference := FTargetValue - lCurrentValue;
1556

1557
  lTotalDistanceToTravelThisTime := 0;
1558

1559
  while ADeltaTime > lMaxExpectedDeltaTime do
1560
  begin
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.
1563

1564
    lCurrentDifference := lCurrentDifference - lDistanceToTravelThisTime;
1565
    lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
1566
    ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
1567
  end;
1568

1569
  if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
1570
  begin
1571
    FOnSetCurrentValue(Self, lCurrentValue + lTotalDistanceToTravelThisTime);
1572
    Result := True;
1573
  end;  
1574
end;
1575

1576
procedure TGLNavigatorSmoothChangeSingle.ResetTargetValue;
1577
begin
1578
  FTargetValue := FOnGetCurrentValue(Self);
1579
end;
1580

1581
{ TGLNavigatorSmoothChangeVector }
1582

1583
procedure TGLNavigatorSmoothChangeVector.Assign(Source: TPersistent);
1584
begin
1585
  inherited Assign(Source);
1586
  
1587
  if Source is TGLNavigatorSmoothChangeVector then
1588
  begin
1589
    FTargetValue.Assign(TGLNavigatorSmoothChangeVector(Source).TargetValue);
1590
    FOnGetCurrentValue := TGLNavigatorSmoothChangeVector(Source).FOnGetCurrentValue;
1591
    FOnSetCurrentValue := TGLNavigatorSmoothChangeVector(Source).FOnSetCurrentValue;
1592
  end;
1593
end;
1594

1595
constructor TGLNavigatorSmoothChangeVector.Create(aOwner: TGLXCollection);
1596
begin
1597
  inherited;
1598
  FTargetValue := TGLCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
1599
end;
1600

1601
destructor TGLNavigatorSmoothChangeVector.Destroy;
1602
begin
1603
  FTargetValue.Free;
1604
  inherited;
1605
end;
1606

1607
class function TGLNavigatorSmoothChangeVector.FriendlyName: string;
1608
begin
1609
  Result := 'Navigator SmoothChange Vector';
1610
end;
1611

1612
function TGLNavigatorSmoothChangeVector.Proceed(ADeltaTime: Double): Boolean;
1613
var
1614
  lAbsolutePosition: TVector;
1615
  lCurrentDistance: Single;
1616
  lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
1617
  lMaxExpectedDeltaTime: Double;
1618

1619
  procedure DoAdjustDistanceToPoint();
1620
  var
1621
    vect: TVector;
1622
  begin
1623
    vect := VectorScale(VectorNormalize(VectorSubtract(FTargetValue.DirectVector, lAbsolutePosition)), lTotalDistanceToTravelThisTime);
1624
    AddVector(vect, lAbsolutePosition);
1625

1626
    // Did we go too far?
1627
    if VectorDistance(vect, FTargetValue.DirectVector) > VectorDistance(lAbsolutePosition, FTargetValue.DirectVector) then
1628
      vect := FTargetValue.DirectVector;
1629

1630
    FOnSetCurrentValue(Self, vect);
1631
    Result := True;
1632
  end;
1633

1634
begin
1635
  Result := False;
1636
  if not FEnabled then Exit;
1637
  if not Assigned(FOnGetCurrentValue) then Exit;
1638
  if not Assigned(FOnSetCurrentValue) then Exit;
1639

1640
  lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
1641
  lAbsolutePosition := FOnGetCurrentValue(Self);
1642
  lCurrentDistance := VectorDistance(lAbsolutePosition, FTargetValue.DirectVector);
1643

1644
  lTotalDistanceToTravelThisTime := 0;
1645

1646

1647
  while ADeltaTime > lMaxExpectedDeltaTime do
1648
  begin
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.
1651

1652
    lCurrentDistance := lCurrentDistance - lDistanceToTravelThisTime;
1653
    lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
1654
    ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
1655
  end;
1656

1657
  if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
1658
    DoAdjustDistanceToPoint();
1659
end;
1660

1661
procedure TGLNavigatorSmoothChangeVector.ResetTargetValue;
1662
begin
1663
  FTargetValue.DirectVector := FOnGetCurrentValue(Self);
1664
end;
1665

1666
procedure TGLNavigatorSmoothChangeVector.SetTargetValue(
1667
  const Value: TGLCoordinates);
1668
begin
1669
  FTargetValue.Assign(Value);
1670
end;
1671

1672
initialization
1673
  RegisterClasses([
1674
      TGLSmoothNavigator, TGLSmoothUserInterface,
1675
      TGLNavigatorInertiaParameters, TGLNavigatorGeneralParameters,
1676
      TGLNavigatorMoveAroundParameters,
1677
      TGLNavigatorAdjustDistanceParameters, TGLNavigatorAdjustDistanceParametersEx
1678
                   ]);
1679

1680
  RegisterXCollectionItemClass(TGLNavigatorSmoothChangeSingle);
1681
  RegisterXCollectionItemClass(TGLNavigatorSmoothChangeVector);
1682
end.
1683

1684

1685

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.