|
@@ -0,0 +1,1654 @@
|
|
|
|
+//
|
|
|
|
+// This unit is part of the GLScene Engine, http://glscene.org
|
|
|
|
+//
|
|
|
|
+
|
|
|
|
+unit GLSmoothNavigator;
|
|
|
|
+
|
|
|
|
+(*
|
|
|
|
+ An extention of TGLNavigator, which allows to move objects with inertia
|
|
|
|
+ Note: it is not completely FPS-independant. Only Moving code is, but
|
|
|
|
+ MoveAroundTarget, Turn[Vertical/Horizontal] and AdjustDistanceTo[..] is not.
|
|
|
|
+ Don't know why, but when I make their code identical, these function stop
|
|
|
|
+ working completely. So you probably have to call the AutoScaleParameters
|
|
|
|
+ procedure once in a while for it to adjust to the current framerate.
|
|
|
|
+ If someone knows a better way to solve this issue, please contact me via
|
|
|
|
+ glscene newsgroups.
|
|
|
|
+
|
|
|
|
+ TODO:
|
|
|
|
+ 1) Scale "Old values" too, when callin the Scale parameter procedure to
|
|
|
|
+ avoid the temporary "freeze" of controls.
|
|
|
|
+ 2) AddImpulse procedures.
|
|
|
|
+*)
|
|
|
|
+
|
|
|
|
+interface
|
|
|
|
+
|
|
|
|
+{$I GLScene.inc}
|
|
|
|
+
|
|
|
|
+uses
|
|
|
|
+ System.Types,
|
|
|
|
+ System.Classes,
|
|
|
|
+
|
|
|
|
+ GLScene,
|
|
|
|
+ GLPersistentClasses,
|
|
|
|
+ GLVectorTypes,
|
|
|
|
+ GLNavigator,
|
|
|
|
+ GLVectorGeometry,
|
|
|
|
+ GLCoordinates,
|
|
|
|
+ GLScreen,
|
|
|
|
+ XCollection;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+
|
|
|
|
+ (* TGLNavigatorAdjustDistanceParameters includes a basic set of parameters
|
|
|
|
+ that control the smoothness of movement. *)
|
|
|
|
+ TGLNavigatorAbstractParameters = class(TPersistent)
|
|
|
|
+ private
|
|
|
|
+ FOwner: TPersistent;
|
|
|
|
+ FInertia: Single;
|
|
|
|
+ FSpeed: Single;
|
|
|
|
+ FCutoff: Single;
|
|
|
|
+ function StoreCutoff: Boolean;
|
|
|
|
+ protected
|
|
|
|
+ function StoreInertia: Boolean; virtual;
|
|
|
|
+ function StoreSpeed: Boolean; virtual;
|
|
|
|
+
|
|
|
|
+ function GetOwner: TPersistent; override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TPersistent); virtual;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ procedure ScaleParameters(const Value: Single); virtual;
|
|
|
|
+ published
|
|
|
|
+ property Inertia: Single read FInertia write FInertia stored StoreInertia;
|
|
|
|
+ property Speed: Single read FSpeed write FSpeed stored StoreSpeed;
|
|
|
|
+ property Cutoff: Single read FCutoff write FCutoff stored StoreCutoff;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ TGLSmoothNavigator = class;
|
|
|
|
+
|
|
|
|
+ (* TGLNavigatorSmoothChangeItem includes a basic set of parameters
|
|
|
|
+ that control the smoothness of movement. *)
|
|
|
|
+ TGLNavigatorSmoothChangeItem = class(TXCollectionItem)
|
|
|
|
+ private
|
|
|
|
+ FInertia: Single;
|
|
|
|
+ FSpeed: Single;
|
|
|
|
+ FEnabled: Boolean;
|
|
|
|
+ FSpeedLimit: Single;
|
|
|
|
+ FCutoff: Double;
|
|
|
|
+ function StoreInertia: Boolean;
|
|
|
|
+ function StoreSpeed: Boolean;
|
|
|
|
+ function StoreSpeedLimit: Boolean;
|
|
|
|
+ function StoreCutoff: Boolean;
|
|
|
|
+ protected
|
|
|
|
+ function GetNavigator: TGLSmoothNavigator;
|
|
|
|
+ public
|
|
|
|
+ // Returns False if there was no change.
|
|
|
|
+ function Proceed(ADeltaTime: Double): Boolean; virtual; abstract;
|
|
|
|
+ constructor Create(aOwner: TXCollection); override;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ procedure ScaleParameters(const Value: Single); virtual;
|
|
|
|
+ procedure ResetTargetValue(); virtual; abstract;
|
|
|
|
+ published
|
|
|
|
+ property Inertia: Single read FInertia write FInertia stored StoreInertia;
|
|
|
|
+ property Speed: Single read FSpeed write FSpeed stored StoreSpeed;
|
|
|
|
+ property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
|
|
|
|
+ property Cutoff: Double read FCutoff write FCutoff stored StoreCutoff;
|
|
|
|
+ property Enabled: Boolean read FEnabled write FEnabled default True;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ TGLNavigatorSmoothChangeSingle = class;
|
|
|
|
+ TGLNavigatorSmoothChangeSingleGetEvent = function(const ASender: TGLNavigatorSmoothChangeSingle): Single of object;
|
|
|
|
+ TGLNavigatorSmoothChangeSingleSetEvent = procedure(const ASender: TGLNavigatorSmoothChangeSingle; const AValue: Single) of object;
|
|
|
|
+
|
|
|
|
+ // Smoothly change any Single value, so it will become TargetValue in the end.
|
|
|
|
+ TGLNavigatorSmoothChangeSingle = class(TGLNavigatorSmoothChangeItem)
|
|
|
|
+ private
|
|
|
|
+ FTargetValue: Single;
|
|
|
|
+ FOnGetCurrentValue: TGLNavigatorSmoothChangeSingleGetEvent;
|
|
|
|
+ FOnSetCurrentValue: TGLNavigatorSmoothChangeSingleSetEvent;
|
|
|
|
+ public
|
|
|
|
+ class function FriendlyName: string; override;
|
|
|
|
+ function Proceed(ADeltaTime: Double): Boolean; override;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ procedure ResetTargetValue(); override;
|
|
|
|
+ published
|
|
|
|
+ property TargetValue: Single read FTargetValue write FTargetValue;
|
|
|
|
+ property OnGetCurrentValue: TGLNavigatorSmoothChangeSingleGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
|
|
|
|
+ property OnSetCurrentValue: TGLNavigatorSmoothChangeSingleSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ TGLNavigatorSmoothChangeVector = class;
|
|
|
|
+ TGLNavigatorSmoothChangeVectorGetEvent = function(const ASender: TGLNavigatorSmoothChangeVector): TVector of object;
|
|
|
|
+ TGLNavigatorSmoothChangeVectorSetEvent = procedure(const ASender: TGLNavigatorSmoothChangeVector; const AValue: TVector) of object;
|
|
|
|
+
|
|
|
|
+ // Smoothly change any Vector4f value, so it will become TargetValue in the end.
|
|
|
|
+ TGLNavigatorSmoothChangeVector = class(TGLNavigatorSmoothChangeItem)
|
|
|
|
+ private
|
|
|
|
+ FTargetValue: TGLCoordinates;
|
|
|
|
+ FOnGetCurrentValue: TGLNavigatorSmoothChangeVectorGetEvent;
|
|
|
|
+ FOnSetCurrentValue: TGLNavigatorSmoothChangeVectorSetEvent;
|
|
|
|
+ procedure SetTargetValue(const Value: TGLCoordinates);
|
|
|
|
+ public
|
|
|
|
+ class function FriendlyName: string; override;
|
|
|
|
+ function Proceed(ADeltaTime: Double): Boolean; override;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ constructor Create(aOwner: TXCollection); override;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+ procedure ResetTargetValue(); override;
|
|
|
|
+ published
|
|
|
|
+ property TargetValue: TGLCoordinates read FTargetValue write SetTargetValue;
|
|
|
|
+ property OnGetCurrentValue: TGLNavigatorSmoothChangeVectorGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
|
|
|
|
+ property OnSetCurrentValue: TGLNavigatorSmoothChangeVectorSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ TGLNavigatorSmoothChangeItemClass = class of TGLNavigatorSmoothChangeItem;
|
|
|
|
+
|
|
|
|
+ // XCollection of TGLNavigatorSmoothChangeItem.
|
|
|
|
+ TGLNavigatorSmoothChangeItems = class(TXCollection)
|
|
|
|
+ private
|
|
|
|
+ function GetItems(const Index : Integer): TGLNavigatorSmoothChangeItem;
|
|
|
|
+ procedure SetItems(const Index : Integer; const Value: TGLNavigatorSmoothChangeItem);
|
|
|
|
+ protected
|
|
|
|
+ procedure DoProceed(ADeltaTime: Double);
|
|
|
|
+ public
|
|
|
|
+ function Add(AClass : TGLNavigatorSmoothChangeItemClass): TGLNavigatorSmoothChangeItem;
|
|
|
|
+ function CanAdd(AClass: TXCollectionItemClass): Boolean; override;
|
|
|
|
+ class function ItemsClass: TXCollectionItemClass; override;
|
|
|
|
+ property Items[const Index : Integer]: TGLNavigatorSmoothChangeItem read GetItems write
|
|
|
|
+ SetItems; default;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ (* TGLNavigatorAdjustDistanceParameters is wrapper for all parameters that
|
|
|
|
+ affect how the AdjustDisanceTo[...] methods work *)
|
|
|
|
+ TGLNavigatorAdjustDistanceParameters = class(TGLNavigatorAbstractParameters)
|
|
|
|
+ private
|
|
|
|
+ FOldDistanceRatio: Single;
|
|
|
|
+ FImpulseSpeed: Single;
|
|
|
|
+ function StoreImpulseSpeed: Boolean;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TPersistent); override;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ procedure ScaleParameters(const Value: Single); override;
|
|
|
|
+
|
|
|
|
+ procedure AddImpulse(const Impulse: Single); virtual;
|
|
|
|
+ published
|
|
|
|
+ property ImpulseSpeed: Single read FImpulseSpeed write FImpulseSpeed stored StoreImpulseSpeed;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ (* TGLNavigatorAdjustDistanceParameters is wrapper for all parameters that
|
|
|
|
+ affect how the AdjustDisanceTo[...]Ex methods work
|
|
|
|
+ You need to set the TargetObject and desired distance to it,
|
|
|
|
+ then call AdjustDisanceTo[...]Ex() in your Cadencer.OnProgress code. *)
|
|
|
|
+ TGLNavigatorAdjustDistanceParametersEx = class(TGLNavigatorAbstractParameters)
|
|
|
|
+ private
|
|
|
|
+ FSpeedLimit: Single;
|
|
|
|
+ FTargetDistance: Single;
|
|
|
|
+ function StoreSpeedLimit: Boolean;
|
|
|
|
+ function StoreTargetDistance: Boolean;
|
|
|
|
+ protected
|
|
|
|
+ function StoreSpeed: Boolean; override;
|
|
|
|
+ function StoreInertia: Boolean; override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TPersistent); override;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ published
|
|
|
|
+ property TargetDistance: Single read FTargetDistance write FTargetDistance stored StoreTargetDistance;
|
|
|
|
+ property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ {TGLNavigatorInertiaParameters is wrapper for all parameters that affect the
|
|
|
|
+ smoothness of movement
|
|
|
|
+ }
|
|
|
|
+ TGLNavigatorInertiaParameters = class(TPersistent)
|
|
|
|
+ private
|
|
|
|
+ FOwner: TPersistent;
|
|
|
|
+
|
|
|
|
+ OldTurnHorizontalAngle: Single;
|
|
|
|
+ OldTurnVerticalAngle: Single;
|
|
|
|
+
|
|
|
|
+ OldMoveForwardDistance: Single;
|
|
|
|
+ OldStrafeHorizontalDistance: Single;
|
|
|
|
+ OldStrafeVerticalDistance: Single;
|
|
|
|
+
|
|
|
|
+ FTurnInertia: Single;
|
|
|
|
+ FTurnSpeed: Single;
|
|
|
|
+ FTurnMaxAngle: Single;
|
|
|
|
+ FMovementAcceleration: Single;
|
|
|
|
+ FMovementInertia: Single;
|
|
|
|
+ FMovementSpeed: Single;
|
|
|
|
+
|
|
|
|
+ function StoreTurnMaxAngle: Boolean;
|
|
|
|
+ function StoreMovementAcceleration: Boolean;
|
|
|
|
+ function StoreMovementInertia: Boolean;
|
|
|
|
+ function StoreMovementSpeed: Boolean;
|
|
|
|
+ function StoreTurnInertia: Boolean;
|
|
|
|
+ function StoreTurnSpeed: Boolean;
|
|
|
|
+ protected
|
|
|
|
+ function GetOwner: TPersistent; override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TPersistent); virtual;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ procedure ScaleParameters(const Value: Single); virtual;
|
|
|
|
+ published
|
|
|
|
+ property MovementAcceleration: Single read FMovementAcceleration write FMovementAcceleration stored StoreMovementAcceleration;
|
|
|
|
+ property MovementInertia: Single read FMovementInertia write FMovementInertia stored StoreMovementInertia;
|
|
|
|
+ property MovementSpeed: Single read FMovementSpeed write FMovementSpeed stored StoreMovementSpeed;
|
|
|
|
+
|
|
|
|
+ property TurnMaxAngle: Single read FTurnMaxAngle write FTurnMaxAngle stored StoreTurnMaxAngle;
|
|
|
|
+ property TurnInertia: Single read FTurnInertia write FTurnInertia stored StoreTurnInertia;
|
|
|
|
+ property TurnSpeed: Single read FTurnSpeed write FTurnSpeed stored StoreTurnSpeed;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ {TGLNavigatorGeneralParameters is a wrapper for all general inertia parameters.
|
|
|
|
+
|
|
|
|
+ These properties mean that if ExpectedMaxFPS is 100, FAutoScaleMin is 0.1,
|
|
|
|
+ FAutoScaleMax is 0.75 then the "safe range" for it to change is [10..75].
|
|
|
|
+ If these bounds are violated, then ExpectedMaxFPS is automaticly increased
|
|
|
|
+ or decreased by AutoScaleMult.
|
|
|
|
+ }
|
|
|
|
+ TGLNavigatorGeneralParameters = class(TPersistent)
|
|
|
|
+ private
|
|
|
|
+ FOwner: TPersistent;
|
|
|
|
+ FAutoScaleMin: Single;
|
|
|
|
+ FAutoScaleMax: Single;
|
|
|
|
+ FAutoScaleMult: Single;
|
|
|
|
+
|
|
|
|
+ function StoreAutoScaleMax: Boolean;
|
|
|
|
+ function StoreAutoScaleMin: Boolean;
|
|
|
|
+ function StoreAutoScaleMult: Boolean;
|
|
|
|
+ protected
|
|
|
|
+ function GetOwner: TPersistent; override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TPersistent); virtual;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ published
|
|
|
|
+ property AutoScaleMin: Single read FAutoScaleMin write FAutoScaleMin stored StoreAutoScaleMin;
|
|
|
|
+ property AutoScaleMax: Single read FAutoScaleMax write FAutoScaleMax stored StoreAutoScaleMax;
|
|
|
|
+ property AutoScaleMult: Single read FAutoScaleMult write FAutoScaleMult stored StoreAutoScaleMult;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ {TGLNavigatorMoveAroundParameters is a wrapper for all parameters that
|
|
|
|
+ effect how the TGLBaseSceneObject.MoveObjectAround() procedure works
|
|
|
|
+ }
|
|
|
|
+ TGLNavigatorMoveAroundParameters = class(TPersistent)
|
|
|
|
+ private
|
|
|
|
+ FOwner: TPersistent;
|
|
|
|
+ FTargetObject: TGLBaseSceneObject;
|
|
|
|
+
|
|
|
|
+ FOldPitchInertiaAngle : Single;
|
|
|
|
+ FOldTurnInertiaAngle : Single;
|
|
|
|
+
|
|
|
|
+ FPitchSpeed : Single;
|
|
|
|
+ FTurnSpeed : Single;
|
|
|
|
+ FInertia : Single;
|
|
|
|
+ FMaxAngle : Single;
|
|
|
|
+ FCutoff: Double;
|
|
|
|
+
|
|
|
|
+ function StoreInertia: Boolean;
|
|
|
|
+ function StoreMaxAngle: Boolean;
|
|
|
|
+ function StorePitchSpeed: Boolean;
|
|
|
|
+ function StoreTurnSpeed: Boolean;
|
|
|
|
+ procedure SetTargetObject(const Value: TGLBaseSceneObject);
|
|
|
|
+ function StoreCutoff: Boolean;
|
|
|
|
+ protected
|
|
|
|
+ function GetOwner: TPersistent; override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TPersistent); virtual;
|
|
|
|
+ procedure Assign(Source: TPersistent); override;
|
|
|
|
+ procedure ScaleParameters(const Value: Single); virtual;
|
|
|
|
+ published
|
|
|
|
+ property Inertia: Single read FInertia write FInertia stored StoreInertia;
|
|
|
|
+ property MaxAngle: Single read FMaxAngle write FMaxAngle stored StoreMaxAngle;
|
|
|
|
+ property PitchSpeed: Single read FPitchSpeed write FPitchSpeed stored StorePitchSpeed;
|
|
|
|
+ property TurnSpeed: Single read FTurnSpeed write FTurnSpeed stored StoreTurnSpeed;
|
|
|
|
+ property TargetObject: TGLBaseSceneObject read FTargetObject write SetTargetObject;
|
|
|
|
+ property Cutoff: Double read FCutoff write FCutoff stored StoreCutoff;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ {TGLSmoothNavigator is the component for moving a TGLBaseSceneObject, and all
|
|
|
|
+ classes based on it, this includes all the objects from the Scene Editor.
|
|
|
|
+
|
|
|
|
+ It uses complex smoothing algorithms, most of which are FPS-dependant.
|
|
|
|
+ Make sure your limit your FPS and set MaxExpectedDeltaTime to a value
|
|
|
|
+ that is aproximatly 5 times less than your usual deltatime.
|
|
|
|
+ }
|
|
|
|
+ TGLSmoothNavigator = class(TGLNavigator)
|
|
|
|
+ private
|
|
|
|
+ FMaxExpectedDeltaTime: Double;
|
|
|
|
+ FInertiaParams: TGLNavigatorInertiaParameters;
|
|
|
|
+ FGeneralParams: TGLNavigatorGeneralParameters;
|
|
|
|
+ FMoveAroundParams: TGLNavigatorMoveAroundParameters;
|
|
|
|
+ FAdjustDistanceParams: TGLNavigatorAdjustDistanceParameters;
|
|
|
|
+ FAdjustDistanceParamsEx: TGLNavigatorAdjustDistanceParametersEx;
|
|
|
|
+ FCustomAnimatedItems: TGLNavigatorSmoothChangeItems;
|
|
|
|
+ procedure SetInertiaParams(const Value: TGLNavigatorInertiaParameters);
|
|
|
|
+ function StoreMaxExpectedDeltaTime: Boolean;
|
|
|
|
+ procedure SetGeneralParams(const Value: TGLNavigatorGeneralParameters);
|
|
|
|
+ procedure SetMoveAroundParams(const Value: TGLNavigatorMoveAroundParameters);
|
|
|
|
+ procedure SetAdjustDistanceParams(const Value: TGLNavigatorAdjustDistanceParameters);
|
|
|
|
+ procedure SetAdjustDistanceParamsEx(
|
|
|
|
+ const Value: TGLNavigatorAdjustDistanceParametersEx);
|
|
|
|
+ procedure SetCustomAnimatedItems(
|
|
|
|
+ const Value: TGLNavigatorSmoothChangeItems);
|
|
|
|
+ protected
|
|
|
|
+ procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
|
|
+ public
|
|
|
|
+ // Constructors-destructors.
|
|
|
|
+ constructor Create(AOwner: TComponent); override;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+
|
|
|
|
+ // From TGLNavigator. Probably, should not be public.
|
|
|
|
+ procedure SetObject(Value: TGLBaseSceneObject); override;
|
|
|
|
+
|
|
|
|
+ // Uses InertiaParams.
|
|
|
|
+ procedure TurnHorizontal(Angle: Single; ADeltaTime: Double); virtual;
|
|
|
|
+ procedure TurnVertical(Angle: Single; ADeltaTime: Double); virtual;
|
|
|
|
+ procedure FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
|
|
|
|
+ procedure MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
|
|
|
|
+ procedure StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
|
|
|
|
+ procedure StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
|
|
|
|
+
|
|
|
|
+ // Uses MoveAroundParams. Returns True, if object was actually moved.
|
|
|
|
+ function MoveAroundTarget(const PitchDelta, TurnDelta : Single; const ADeltaTime: Double): Boolean;
|
|
|
|
+ function MoveObjectAround(const AObject: TGLBaseSceneObject; PitchDelta, TurnDelta : Single; ADeltaTime: Double): Boolean;
|
|
|
|
+
|
|
|
|
+ // Uses AdjustDistanceParams.
|
|
|
|
+ function AdjustDistanceToPoint(const APoint: TVector; const DistanceRatio : Single; ADeltaTime: Double): Boolean;
|
|
|
|
+ function AdjustDistanceToTarget(const DistanceRatio : Single; const ADeltaTime: Double): Boolean;
|
|
|
|
+
|
|
|
|
+ // Uses AdjustDistanceParamsEx.
|
|
|
|
+ function AdjustDistanceToPointEx(const APoint: TVector; ADeltaTime: Double): Boolean;
|
|
|
|
+ function AdjustDistanceToTargetEx(const ADeltaTime: Double): Boolean;
|
|
|
|
+
|
|
|
|
+ // Uses CustomAnimatedItems.
|
|
|
|
+ procedure AnimateCustomItems(const ADeltaTime: Double); virtual;
|
|
|
|
+
|
|
|
|
+ // Uses GeneralParams.
|
|
|
|
+ {In ScaleParameters, Value should be around 1. }
|
|
|
|
+ procedure ScaleParameters(const Value: Single); virtual;
|
|
|
|
+ procedure AutoScaleParameters(const FPS: Single); virtual;
|
|
|
|
+ procedure AutoScaleParametersUp(const FPS: Single); virtual;
|
|
|
|
+ published
|
|
|
|
+ property MaxExpectedDeltaTime: Double read FMaxExpectedDeltaTime write FMaxExpectedDeltaTime stored StoreMaxExpectedDeltaTime;
|
|
|
|
+ property InertiaParams: TGLNavigatorInertiaParameters read FInertiaParams write SetInertiaParams;
|
|
|
|
+ property GeneralParams: TGLNavigatorGeneralParameters read FGeneralParams write SetGeneralParams;
|
|
|
|
+ property MoveAroundParams: TGLNavigatorMoveAroundParameters read FMoveAroundParams write SetMoveAroundParams;
|
|
|
|
+ property AdjustDistanceParams: TGLNavigatorAdjustDistanceParameters read FAdjustDistanceParams write SetAdjustDistanceParams;
|
|
|
|
+ property AdjustDistanceParamsEx: TGLNavigatorAdjustDistanceParametersEx read FAdjustDistanceParamsEx write SetAdjustDistanceParamsEx;
|
|
|
|
+ property CustomAnimatedItems: TGLNavigatorSmoothChangeItems read FCustomAnimatedItems write SetCustomAnimatedItems;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ {TGLSmoothUserInterface is the component which reads the userinput and transform it into action.
|
|
|
|
+ Mouselook(ADeltaTime: double) : handles mouse look... Should be called
|
|
|
|
+ in the Cadencer event. (Though it works everywhere!)
|
|
|
|
+ The four properties to get you started are:
|
|
|
|
+ InvertMouse : Inverts the mouse Y axis.
|
|
|
|
+ AutoUpdateMouse : If enabled (by defaul), than handles all mouse updates.
|
|
|
|
+ GLNavigator : The Navigator which receives the user movement.
|
|
|
|
+ GLVertNavigator : The Navigator which if set receives the vertical user
|
|
|
|
+ movement. Used mostly for cameras....
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ TGLSmoothUserInterface = class(TComponent)
|
|
|
|
+ private
|
|
|
|
+ FAutoUpdateMouse: Boolean;
|
|
|
|
+ FMouseLookActive: Boolean;
|
|
|
|
+ FSmoothNavigator: TGLSmoothNavigator;
|
|
|
|
+ FSmoothVertNavigator: TGLSmoothNavigator;
|
|
|
|
+ FInvertMouse: Boolean;
|
|
|
|
+ FOriginalMousePos: TGLCoordinates2;
|
|
|
|
+ procedure SetSmoothNavigator(const Value: TGLSmoothNavigator); virtual;
|
|
|
|
+ procedure SetOriginalMousePos(const Value: TGLCoordinates2); virtual;
|
|
|
|
+ procedure SetSmoothVertNavigator(const Value: TGLSmoothNavigator); virtual;
|
|
|
|
+ procedure SetMouseLookActive(const Value: Boolean); virtual;
|
|
|
|
+ protected
|
|
|
|
+ procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TComponent); override;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+
|
|
|
|
+ procedure TurnHorizontal(const Angle : Single; const ADeltaTime: Double); virtual;
|
|
|
|
+ procedure TurnVertical(const Angle : Single; const ADeltaTime: Double); virtual;
|
|
|
|
+ procedure MouseLookActiveToggle; virtual;
|
|
|
|
+
|
|
|
|
+ function MouseLook(const ADeltaTime: Double): Boolean; overload;
|
|
|
|
+ function MouseLook(const NewXY: TPoint; const ADeltaTime: Double): Boolean; overload;
|
|
|
|
+ function MouseLook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean; overload;
|
|
|
|
+ published
|
|
|
|
+ property AutoUpdateMouse: Boolean read FAutoUpdateMouse write FAutoUpdateMouse default True;
|
|
|
|
+ property MouseLookActive: Boolean read FMouseLookActive write SetMouseLookActive default False;
|
|
|
|
+ property SmoothVertNavigator: TGLSmoothNavigator read FSmoothVertNavigator write SetSmoothVertNavigator;
|
|
|
|
+ property SmoothNavigator: TGLSmoothNavigator read FSmoothNavigator write SetSmoothNavigator;
|
|
|
|
+ property InvertMouse: Boolean read FInvertMouse write FInvertMouse default False;
|
|
|
|
+ property OriginalMousePos: TGLCoordinates2 read FOriginalMousePos write SetOriginalMousePos;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+implementation
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ EPS = 0.001;
|
|
|
|
+ EPS2 = 0.0001;
|
|
|
|
+ EPS8 = 0.00000001;
|
|
|
|
+
|
|
|
|
+{ TGLSmoothNavigator }
|
|
|
|
+
|
|
|
|
+constructor TGLSmoothNavigator.Create(AOwner: TComponent);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FMaxExpectedDeltaTime := 0.001;
|
|
|
|
+ FInertiaParams := TGLNavigatorInertiaParameters.Create(Self);
|
|
|
|
+ FGeneralParams := TGLNavigatorGeneralParameters.Create(Self);
|
|
|
|
+ FMoveAroundParams := TGLNavigatorMoveAroundParameters.Create(Self);
|
|
|
|
+ FAdjustDistanceParams := TGLNavigatorAdjustDistanceParameters.Create(Self);
|
|
|
|
+ FAdjustDistanceParamsEx := TGLNavigatorAdjustDistanceParametersEx.Create(Self);
|
|
|
|
+ FCustomAnimatedItems := TGLNavigatorSmoothChangeItems.Create(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+destructor TGLSmoothNavigator.Destroy;
|
|
|
|
+begin
|
|
|
|
+ FInertiaParams.Free;
|
|
|
|
+ FGeneralParams.Free;
|
|
|
|
+ FMoveAroundParams.Free;
|
|
|
|
+ FAdjustDistanceParams.Free;
|
|
|
|
+ FAdjustDistanceParamsEx.Free;
|
|
|
|
+ FCustomAnimatedItems.Free;
|
|
|
|
+ inherited;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetInertiaParams(
|
|
|
|
+ const Value: TGLNavigatorInertiaParameters);
|
|
|
|
+begin
|
|
|
|
+ FInertiaParams.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.TurnHorizontal(Angle: Single; ADeltaTime: Double);
|
|
|
|
+var
|
|
|
|
+ FinalAngle: Single;
|
|
|
|
+begin
|
|
|
|
+ with FInertiaParams do
|
|
|
|
+ begin
|
|
|
|
+ FinalAngle := 0;
|
|
|
|
+ Angle := Angle * FTurnSpeed;
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnHorizontalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
|
|
|
|
+ OldTurnHorizontalAngle := Angle;
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalAngle := FinalAngle + Angle;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if (Abs(FinalAngle) > EPS) then
|
|
|
|
+ inherited TurnHorizontal(FinalAngle);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.TurnVertical(Angle: Single; ADeltaTime: Double);
|
|
|
|
+var
|
|
|
|
+ FinalAngle: Single;
|
|
|
|
+begin
|
|
|
|
+ with FInertiaParams do
|
|
|
|
+ begin
|
|
|
|
+ FinalAngle := 0;
|
|
|
|
+ Angle := Angle * FTurnSpeed;
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnVerticalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
|
|
|
|
+ OldTurnVerticalAngle := Angle;
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalAngle := FinalAngle + Angle;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if (Abs(FinalAngle) > EPS) then
|
|
|
|
+ inherited TurnVertical(FinalAngle);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
|
|
|
|
+var
|
|
|
|
+ FinalDistance: Single;
|
|
|
|
+ Distance: Single;
|
|
|
|
+begin
|
|
|
|
+ with FInertiaParams do
|
|
|
|
+ begin
|
|
|
|
+ if Plus then
|
|
|
|
+ Distance := FMovementSpeed
|
|
|
|
+ else if Minus then
|
|
|
|
+ Distance := -FMovementSpeed
|
|
|
|
+ else
|
|
|
|
+ Distance := 0;
|
|
|
|
+
|
|
|
|
+ if Accelerate then
|
|
|
|
+ Distance := Distance * FMovementAcceleration;
|
|
|
|
+
|
|
|
|
+ FinalDistance := 0;
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalDistance := FinalDistance + OldMoveForwardDistance;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(FinalDistance) > EPS then
|
|
|
|
+ inherited MoveForward(FinalDistance);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
|
|
|
|
+var
|
|
|
|
+ FinalDistance: Single;
|
|
|
|
+ Distance: Single;
|
|
|
|
+begin
|
|
|
|
+ with FInertiaParams do
|
|
|
|
+ begin
|
|
|
|
+ if Plus then
|
|
|
|
+ Distance := FMovementSpeed
|
|
|
|
+ else if Minus then
|
|
|
|
+ Distance := -FMovementSpeed
|
|
|
|
+ else
|
|
|
|
+ Distance := 0;
|
|
|
|
+
|
|
|
|
+ if Accelerate then
|
|
|
|
+ Distance := Distance * FMovementAcceleration;
|
|
|
|
+
|
|
|
|
+ FinalDistance := 0;
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalDistance := FinalDistance + OldMoveForwardDistance;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(FinalDistance) > EPS then
|
|
|
|
+ inherited FlyForward(FinalDistance);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
|
|
|
|
+var
|
|
|
|
+ FinalDistance: Single;
|
|
|
|
+ Distance: Single;
|
|
|
|
+begin
|
|
|
|
+ with FInertiaParams do
|
|
|
|
+ begin
|
|
|
|
+ if Plus then
|
|
|
|
+ Distance := FMovementSpeed
|
|
|
|
+ else if Minus then
|
|
|
|
+ Distance := -FMovementSpeed
|
|
|
|
+ else
|
|
|
|
+ Distance := 0;
|
|
|
|
+
|
|
|
|
+ if Accelerate then
|
|
|
|
+ Distance := Distance * FMovementAcceleration;
|
|
|
|
+
|
|
|
|
+ FinalDistance := 0;
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ OldStrafeHorizontalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeHorizontalDistance * FMovementInertia) / (FMovementInertia + 1);
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalDistance := FinalDistance + OldStrafeHorizontalDistance;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(FinalDistance) > EPS then
|
|
|
|
+ inherited StrafeHorizontal(FinalDistance);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
|
|
|
|
+var
|
|
|
|
+ FinalDistance: Single;
|
|
|
|
+ Distance: Single;
|
|
|
|
+begin
|
|
|
|
+ with FInertiaParams do
|
|
|
|
+ begin
|
|
|
|
+ if Plus then
|
|
|
|
+ Distance := FMovementSpeed
|
|
|
|
+ else if Minus then
|
|
|
|
+ Distance := -FMovementSpeed
|
|
|
|
+ else
|
|
|
|
+ Distance := 0;
|
|
|
|
+
|
|
|
|
+ if Accelerate then
|
|
|
|
+ Distance := Distance * FMovementAcceleration;
|
|
|
|
+
|
|
|
|
+ FinalDistance := 0;
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ OldStrafeVerticalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeVerticalDistance * FMovementInertia) / (FMovementInertia + 1);
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalDistance := FinalDistance + OldStrafeVerticalDistance;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(FinalDistance) > EPS then
|
|
|
|
+ inherited StrafeVertical(FinalDistance);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.AutoScaleParameters(const FPS: Single);
|
|
|
|
+begin
|
|
|
|
+ with FGeneralParams do
|
|
|
|
+ begin
|
|
|
|
+ if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
|
|
|
|
+ ScaleParameters(FAutoScaleMult)
|
|
|
|
+ else if FPS < FAutoScaleMin / FMaxExpectedDeltatime then
|
|
|
|
+ ScaleParameters(1/FAutoScaleMult);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.AutoScaleParametersUp(const FPS: Single);
|
|
|
|
+begin
|
|
|
|
+ with FGeneralParams do
|
|
|
|
+ begin
|
|
|
|
+ if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
|
|
|
|
+ ScaleParameters(FAutoScaleMult)
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.ScaleParameters(const Value: Single);
|
|
|
|
+begin
|
|
|
|
+ Assert(Value > 0);
|
|
|
|
+ FMaxExpectedDeltatime := FMaxExpectedDeltatime / Value;
|
|
|
|
+ FInertiaParams.ScaleParameters(Value);
|
|
|
|
+ FMoveAroundParams.ScaleParameters(Value);
|
|
|
|
+ FAdjustDistanceParams.ScaleParameters(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.StoreMaxExpectedDeltaTime: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FMaxExpectedDeltaTime - 0.001) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetGeneralParams(
|
|
|
|
+ const Value: TGLNavigatorGeneralParameters);
|
|
|
|
+begin
|
|
|
|
+ FGeneralParams.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetMoveAroundParams(
|
|
|
|
+ const Value: TGLNavigatorMoveAroundParameters);
|
|
|
|
+begin
|
|
|
|
+ FMoveAroundParams.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.Notification(AComponent: TComponent;
|
|
|
|
+ Operation: TOperation);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ if Operation = opRemove then
|
|
|
|
+ begin
|
|
|
|
+ if AComponent = FMoveAroundParams.FTargetObject then
|
|
|
|
+ FMoveAroundParams.FTargetObject := nil;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetObject(Value: TGLBaseSceneObject);
|
|
|
|
+var
|
|
|
|
+ I: Integer;
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ // Try to detect a TargetObject.
|
|
|
|
+ if Value <> nil then
|
|
|
|
+ if FMoveAroundParams.TargetObject = nil then
|
|
|
|
+ begin
|
|
|
|
+ // May be it is a camera...
|
|
|
|
+ if Value is TGLCamera then
|
|
|
|
+ FMoveAroundParams.TargetObject := TGLCamera(Value).TargetObject
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ // May be it has camera children...
|
|
|
|
+ if Value.Count <> 0 then
|
|
|
|
+ for I := 0 to Value.Count - 1 do
|
|
|
|
+ if Value.Children[I] is TGLCamera then
|
|
|
|
+ begin
|
|
|
|
+ FMoveAroundParams.TargetObject := TGLCamera(Value.Children[I]).TargetObject;
|
|
|
|
+ Exit;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.MoveAroundTarget(const PitchDelta, TurnDelta: Single;
|
|
|
|
+ const ADeltaTime: Double): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := MoveObjectAround(FMoveAroundParams.FTargetObject, PitchDelta, TurnDelta, ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.MoveObjectAround(
|
|
|
|
+ const AObject: TGLBaseSceneObject; PitchDelta, TurnDelta: Single;
|
|
|
|
+ ADeltaTime: Double): Boolean;
|
|
|
|
+var
|
|
|
|
+ FinalPitch: Single;
|
|
|
|
+ FinalTurn: Single;
|
|
|
|
+
|
|
|
|
+ lUp: TVector;
|
|
|
|
+begin
|
|
|
|
+ Result := False;
|
|
|
|
+ FinalPitch := 0;
|
|
|
|
+ FinalTurn := 0;
|
|
|
|
+ with FMoveAroundParams do
|
|
|
|
+ begin
|
|
|
|
+ PitchDelta := PitchDelta * FPitchSpeed;
|
|
|
|
+ TurnDelta := TurnDelta * FTurnSpeed;
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltatime do
|
|
|
|
+ begin
|
|
|
|
+ PitchDelta := ClampValue((PitchDelta * FMaxExpectedDeltatime + FOldPitchInertiaAngle * FInertia) / (FInertia + 1), - FMaxAngle, FMaxAngle);
|
|
|
|
+ FOldPitchInertiaAngle := PitchDelta;
|
|
|
|
+ FinalPitch := FinalPitch + PitchDelta;
|
|
|
|
+ TurnDelta := ClampValue((TurnDelta * FMaxExpectedDeltatime + FOldTurnInertiaAngle * FInertia) / (FInertia + 1), - FMaxAngle, FMaxAngle);
|
|
|
|
+ FOldTurnInertiaAngle := TurnDelta;
|
|
|
|
+ FinalTurn := FinalTurn + TurnDelta;
|
|
|
|
+
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltatime;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if UseVirtualUp then
|
|
|
|
+ lUp := VirtualUp.AsVector
|
|
|
|
+ else
|
|
|
|
+ lUp := MovingObject.AbsoluteUp;
|
|
|
|
+
|
|
|
|
+ if (Abs(FinalPitch) > FCutOff) or (Abs(FinalTurn) > FCutOff) then
|
|
|
|
+ begin
|
|
|
|
+ MovingObject.AbsolutePosition := GLVectorGeometry.MoveObjectAround(
|
|
|
|
+ MovingObject.AbsolutePosition, lUp, AObject.AbsolutePosition, FinalPitch, FinalTurn);
|
|
|
|
+ Result := True;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.AdjustDistanceToPoint(const APoint: TVector;
|
|
|
|
+ const DistanceRatio: Single; ADeltaTime: Double): Boolean;
|
|
|
|
+
|
|
|
|
+ // Based on TGLCamera.AdjustDistanceToTarget
|
|
|
|
+ procedure DoAdjustDistanceToPoint(const DistanceRatio: Single);
|
|
|
|
+ var
|
|
|
|
+ vect: TVector;
|
|
|
|
+ begin
|
|
|
|
+ vect := VectorSubtract(MovingObject.AbsolutePosition, APoint);
|
|
|
|
+ ScaleVector(vect, (distanceRatio - 1));
|
|
|
|
+ AddVector(vect, MovingObject.AbsolutePosition);
|
|
|
|
+ if Assigned(MovingObject.Parent) then
|
|
|
|
+ vect := MovingObject.Parent.AbsoluteToLocal(vect);
|
|
|
|
+ MovingObject.Position.AsVector := vect;
|
|
|
|
+ Result := True;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ FinalDistanceRatio: Single;
|
|
|
|
+ TempDistanceRatio: Single;
|
|
|
|
+begin
|
|
|
|
+ with FAdjustDistanceParams do
|
|
|
|
+ begin
|
|
|
|
+ TempDistanceRatio := DistanceRatio * FSpeed;
|
|
|
|
+ FinalDistanceRatio := 0;
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ TempDistanceRatio := (TempDistanceRatio * FMaxExpectedDeltaTime + FOldDistanceRatio * FInertia) / (FInertia + 1);
|
|
|
|
+ FOldDistanceRatio := TempDistanceRatio;
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ FinalDistanceRatio := FinalDistanceRatio + FOldDistanceRatio / FMaxExpectedDeltaTime;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(FinalDistanceRatio) > FCutoff then
|
|
|
|
+ begin
|
|
|
|
+ if FinalDistanceRatio > 0 then
|
|
|
|
+ DoAdjustDistanceToPoint(1 / (1 + FinalDistanceRatio))
|
|
|
|
+ else
|
|
|
|
+ DoAdjustDistanceToPoint(1 * (1 - FinalDistanceRatio))
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Result := False;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.AdjustDistanceToTarget(const DistanceRatio: Single;
|
|
|
|
+ const ADeltaTime: Double): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Assert(FMoveAroundParams.FTargetObject <> nil);
|
|
|
|
+ Result := AdjustDistanceToPoint(FMoveAroundParams.FTargetObject.AbsolutePosition,
|
|
|
|
+ DistanceRatio, ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetAdjustDistanceParams(
|
|
|
|
+ const Value: TGLNavigatorAdjustDistanceParameters);
|
|
|
|
+begin
|
|
|
|
+ FAdjustDistanceParams.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.AdjustDistanceToPointEx(const APoint: TVector;
|
|
|
|
+ ADeltaTime: Double): Boolean;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lAbsolutePosition: TVector;
|
|
|
|
+ lCurrentDistance: Single;
|
|
|
|
+ lDistanceDifference, lTempCurrentDistance: Single;
|
|
|
|
+
|
|
|
|
+ procedure DoAdjustDistanceToPoint(const DistanceValue: Single);
|
|
|
|
+ var
|
|
|
|
+ vect: TVector;
|
|
|
|
+ begin
|
|
|
|
+ vect := VectorSubtract(APoint, lAbsolutePosition);
|
|
|
|
+ NormalizeVector(vect);
|
|
|
|
+ ScaleVector(vect, DistanceValue);
|
|
|
|
+ MovingObject.AbsolutePosition := VectorAdd(lAbsolutePosition, vect);
|
|
|
|
+ Result := True;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ lAbsolutePosition := MovingObject.AbsolutePosition;
|
|
|
|
+ lCurrentDistance := VectorDistance(lAbsolutePosition, APoint);
|
|
|
|
+ lDistanceDifference := lCurrentDistance - FAdjustDistanceParamsEx.FTargetDistance;
|
|
|
|
+
|
|
|
|
+ with FAdjustDistanceParamsEx do
|
|
|
|
+ begin
|
|
|
|
+ lTempCurrentDistance := 0;
|
|
|
|
+ while ADeltaTime > FMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ lTempCurrentDistance := (FSpeed * FMaxExpectedDeltaTime * lDistanceDifference * FInertia) / (FInertia + 1);
|
|
|
|
+// lTempCurrentDistance := (FSpeed * FMaxExpectedDeltaTime + lDistanceDifference * FInertia) / (FInertia + 1);- this also works, but a bit different.
|
|
|
|
+ ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ lTempCurrentDistance := ClampValue(lTempCurrentDistance, -FSpeedLimit * ADeltaTime, FSpeedLimit * ADeltaTime);
|
|
|
|
+
|
|
|
|
+ if Abs(lTempCurrentDistance) > FCutoff then
|
|
|
|
+ DoAdjustDistanceToPoint(lTempCurrentDistance)
|
|
|
|
+ else
|
|
|
|
+ Result := False;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothNavigator.AdjustDistanceToTargetEx(
|
|
|
|
+ const ADeltaTime: Double): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Assert(FMoveAroundParams.FTargetObject <> nil);
|
|
|
|
+ Result := AdjustDistanceToPointEx(FMoveAroundParams.FTargetObject.AbsolutePosition,
|
|
|
|
+ ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetAdjustDistanceParamsEx(
|
|
|
|
+ const Value: TGLNavigatorAdjustDistanceParametersEx);
|
|
|
|
+begin
|
|
|
|
+ FAdjustDistanceParamsEx.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.AnimateCustomItems(const ADeltaTime: Double);
|
|
|
|
+begin
|
|
|
|
+ FCustomAnimatedItems.DoProceed(ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothNavigator.SetCustomAnimatedItems(
|
|
|
|
+ const Value: TGLNavigatorSmoothChangeItems);
|
|
|
|
+begin
|
|
|
|
+ FCustomAnimatedItems.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLSmoothUserInterface }
|
|
|
|
+
|
|
|
|
+function TGLSmoothUserInterface.MouseLook(
|
|
|
|
+ const ADeltaTime: Double): Boolean;
|
|
|
|
+var
|
|
|
|
+ MousePos: TPoint;
|
|
|
|
+begin
|
|
|
|
+ Assert(FAutoUpdateMouse, 'AutoUpdateMouse must be True to use this function');
|
|
|
|
+ if FMouseLookActive then
|
|
|
|
+ begin
|
|
|
|
+ GLGetCursorPos(MousePos);
|
|
|
|
+ Result := Mouselook(MousePos.X, MousePos.Y, ADeltaTime);
|
|
|
|
+ GLSetCursorPos(Round(OriginalMousePos.X), Round(OriginalMousePos.Y));
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Result := False;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLSmoothUserInterface.Mouselook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean;
|
|
|
|
+var
|
|
|
|
+ DeltaX, DeltaY: Single;
|
|
|
|
+begin
|
|
|
|
+ Result := False;
|
|
|
|
+ if FMouseLookActive then
|
|
|
|
+ begin
|
|
|
|
+ Deltax := (NewX - FOriginalMousePos.X);
|
|
|
|
+ Deltay := (FOriginalMousePos.Y - NewY);
|
|
|
|
+
|
|
|
|
+ if InvertMouse then
|
|
|
|
+ DeltaY := -DeltaY;
|
|
|
|
+
|
|
|
|
+ SmoothNavigator.TurnHorizontal(DeltaX, ADeltaTime);
|
|
|
|
+ SmoothNavigator.TurnVertical(DeltaY, ADeltaTime);
|
|
|
|
+
|
|
|
|
+ Result := (DeltaX <> 0) or (DeltaY <> 0);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function TGLSmoothUserInterface.MouseLook(const NewXY: TPoint; const ADeltaTime: Double): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Mouselook(NewXY.X, NewXY.Y, ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLSmoothUserInterface.Create(AOwner: TComponent);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FMouseLookActive := False;
|
|
|
|
+ FAutoUpdateMouse := True;
|
|
|
|
+ FOriginalMousePos := TGLCoordinates2.CreateInitialized(Self,
|
|
|
|
+ VectorMake(GLGetScreenWidth div 2,
|
|
|
|
+ GLGetScreenHeight div 2, 0, 0), csPoint2D);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.Notification(AComponent: TComponent;
|
|
|
|
+ Operation: TOperation);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ if (Operation = opRemove) then
|
|
|
|
+ begin
|
|
|
|
+ if AComponent = FSmoothNavigator then
|
|
|
|
+ FSmoothNavigator := nil;
|
|
|
|
+ if AComponent = FSmoothVertNavigator then
|
|
|
|
+ FSmoothNavigator := nil;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.SetSmoothNavigator(
|
|
|
|
+ const Value: TGLSmoothNavigator);
|
|
|
|
+begin
|
|
|
|
+ if FSmoothNavigator <> nil then
|
|
|
|
+ FSmoothNavigator.RemoveFreeNotification(Self);
|
|
|
|
+
|
|
|
|
+ FSmoothNavigator := Value;
|
|
|
|
+
|
|
|
|
+ if FSmoothNavigator <> nil then
|
|
|
|
+ FSmoothNavigator.FreeNotification(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+destructor TGLSmoothUserInterface.Destroy;
|
|
|
|
+begin
|
|
|
|
+ FOriginalMousePos.Destroy;
|
|
|
|
+ inherited;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.SetOriginalMousePos(
|
|
|
|
+ const Value: TGLCoordinates2);
|
|
|
|
+begin
|
|
|
|
+ FOriginalMousePos.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.SetSmoothVertNavigator(
|
|
|
|
+ const Value: TGLSmoothNavigator);
|
|
|
|
+begin
|
|
|
|
+ if FSmoothVertNavigator <> nil then
|
|
|
|
+ FSmoothVertNavigator.RemoveFreeNotification(Self);
|
|
|
|
+
|
|
|
|
+ FSmoothVertNavigator := Value;
|
|
|
|
+
|
|
|
|
+ if FSmoothVertNavigator <> nil then
|
|
|
|
+ FSmoothVertNavigator.FreeNotification(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.MouseLookActiveToggle;
|
|
|
|
+begin
|
|
|
|
+ if FMouseLookActive then
|
|
|
|
+ SetMouseLookActive(False)
|
|
|
|
+ else
|
|
|
|
+ SetMouseLookActive(True)
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.SetMouseLookActive(const Value: Boolean);
|
|
|
|
+var
|
|
|
|
+ MousePos: TPoint;
|
|
|
|
+begin
|
|
|
|
+ if FMouseLookActive = Value then Exit;
|
|
|
|
+ FMouseLookActive := Value;
|
|
|
|
+ if FMouseLookActive then
|
|
|
|
+ begin
|
|
|
|
+ if FAutoUpdateMouse then
|
|
|
|
+ begin
|
|
|
|
+ GLGetCursorPos(MousePos);
|
|
|
|
+ FOriginalMousePos.SetPoint2D(MousePos.X, MousePos.Y);
|
|
|
|
+ GLShowCursor(False);
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ if FAutoUpdateMouse then
|
|
|
|
+ GLShowCursor(True);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.TurnHorizontal(const Angle: Single;
|
|
|
|
+ const ADeltaTime: Double);
|
|
|
|
+begin
|
|
|
|
+ FSmoothNavigator.TurnHorizontal(Angle, ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLSmoothUserInterface.TurnVertical(const Angle: Single;
|
|
|
|
+ const ADeltaTime: Double);
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FSmoothNavigator) then
|
|
|
|
+ FSmoothNavigator.TurnVertical(Angle, ADeltaTime)
|
|
|
|
+ else
|
|
|
|
+ FSmoothVertNavigator.TurnVertical(Angle, ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorInertiaParameters }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorInertiaParameters.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ if Source is TGLNavigatorInertiaParameters then
|
|
|
|
+ begin
|
|
|
|
+ FMovementAcceleration := TGLNavigatorInertiaParameters(Source).FMovementAcceleration;
|
|
|
|
+ FMovementInertia := TGLNavigatorInertiaParameters(Source).FMovementInertia;
|
|
|
|
+ FMovementSpeed := TGLNavigatorInertiaParameters(Source).FMovementSpeed;
|
|
|
|
+ FTurnMaxAngle := TGLNavigatorInertiaParameters(Source).FTurnMaxAngle;
|
|
|
|
+ FTurnInertia := TGLNavigatorInertiaParameters(Source).FTurnInertia;
|
|
|
|
+ FTurnSpeed := TGLNavigatorInertiaParameters(Source).FTurnSpeed;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited; //to the pit of doom ;)
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorInertiaParameters.Create(AOwner: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ FOwner := AOwner;
|
|
|
|
+
|
|
|
|
+ FTurnInertia := 150;
|
|
|
|
+ FTurnSpeed := 50;
|
|
|
|
+ FTurnMaxAngle := 0.5;
|
|
|
|
+
|
|
|
|
+ FMovementAcceleration := 7;
|
|
|
|
+ FMovementInertia := 200;
|
|
|
|
+ FMovementSpeed := 200;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.GetOwner: TPersistent;
|
|
|
|
+begin
|
|
|
|
+ Result := FOwner;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorInertiaParameters.ScaleParameters(
|
|
|
|
+ const Value: Single);
|
|
|
|
+begin
|
|
|
|
+ Assert(Value > 0);
|
|
|
|
+
|
|
|
|
+ if Value > 1 then
|
|
|
|
+ begin
|
|
|
|
+ FMovementInertia := FMovementInertia * PowerSingle(2, 1 / Value);
|
|
|
|
+ FTurnInertia := FTurnInertia * PowerSingle(2, 1 / Value);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ FMovementInertia := FMovementInertia / PowerSingle(2, Value);
|
|
|
|
+ FTurnInertia := FTurnInertia / PowerSingle(2, Value);
|
|
|
|
+ end;
|
|
|
|
+ FTurnMaxAngle := FTurnMaxAngle / Value;
|
|
|
|
+ FTurnSpeed := FTurnSpeed * Value;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.StoreTurnMaxAngle: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FTurnMaxAngle - 0.5) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.StoreMovementAcceleration: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FMovementAcceleration - 7) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.StoreMovementInertia: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FMovementInertia - 200) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.StoreMovementSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FMovementSpeed - 200) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.StoreTurnInertia: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FTurnInertia - 150) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorInertiaParameters.StoreTurnSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FTurnSpeed - 50) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorGeneralParameters }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorGeneralParameters.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ if Source is TGLNavigatorGeneralParameters then
|
|
|
|
+ begin
|
|
|
|
+ FAutoScaleMin := TGLNavigatorGeneralParameters(Source).FAutoScaleMin;
|
|
|
|
+ FAutoScaleMax := TGLNavigatorGeneralParameters(Source).FAutoScaleMax;
|
|
|
|
+ FAutoScaleMult := TGLNavigatorGeneralParameters(Source).FAutoScaleMult;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited; //die!
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorGeneralParameters.Create(AOwner: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ FOwner := AOwner;
|
|
|
|
+ FAutoScaleMin := 0.1;
|
|
|
|
+ FAutoScaleMax := 0.75;
|
|
|
|
+ FAutoScaleMult := 2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorGeneralParameters.GetOwner: TPersistent;
|
|
|
|
+begin
|
|
|
|
+ Result := FOwner;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorGeneralParameters.StoreAutoScaleMax: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FAutoScaleMax - 0.75) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorGeneralParameters.StoreAutoScaleMin: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FAutoScaleMin - 0.1) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorGeneralParameters.StoreAutoScaleMult: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FAutoScaleMult - 2) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorMoveAroundParameters }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorMoveAroundParameters.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ if Source is TGLNavigatorMoveAroundParameters then
|
|
|
|
+ begin
|
|
|
|
+ FMaxAngle := TGLNavigatorMoveAroundParameters(Source).FMaxAngle;
|
|
|
|
+ FInertia := TGLNavigatorMoveAroundParameters(Source).FInertia;
|
|
|
|
+ FPitchSpeed := TGLNavigatorMoveAroundParameters(Source).FPitchSpeed;
|
|
|
|
+ FTurnSpeed := TGLNavigatorMoveAroundParameters(Source).FTurnSpeed;
|
|
|
|
+ FCutoff := TGLNavigatorMoveAroundParameters(Source).FCutoff;
|
|
|
|
+ SetTargetObject(TGLNavigatorMoveAroundParameters(Source).FTargetObject);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited; //die
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorMoveAroundParameters.Create(AOwner: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ FOwner := AOwner;
|
|
|
|
+ FPitchSpeed := 500;
|
|
|
|
+ FTurnSpeed := 500;
|
|
|
|
+ FInertia := 65;
|
|
|
|
+ FMaxAngle := 1.5;
|
|
|
|
+ FCutoff := EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorMoveAroundParameters.GetOwner: TPersistent;
|
|
|
|
+begin
|
|
|
|
+ Result := FOwner;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorMoveAroundParameters.ScaleParameters(
|
|
|
|
+ const Value: Single);
|
|
|
|
+begin
|
|
|
|
+ Assert(Value > 0);
|
|
|
|
+
|
|
|
|
+ if Value < 1 then
|
|
|
|
+ FInertia := FInertia / PowerSingle(2, Value)
|
|
|
|
+ else
|
|
|
|
+ FInertia := FInertia * PowerSingle(2, 1 / Value);
|
|
|
|
+
|
|
|
|
+ FMaxAngle := FMaxAngle / Value;
|
|
|
|
+ FPitchSpeed := FPitchSpeed * Value;
|
|
|
|
+ FTurnSpeed := FTurnSpeed * Value;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorMoveAroundParameters.SetTargetObject(
|
|
|
|
+ const Value: TGLBaseSceneObject);
|
|
|
|
+begin
|
|
|
|
+ if FTargetObject <> nil then
|
|
|
|
+ if FOwner is TGLSmoothNavigator then
|
|
|
|
+ FTargetObject.RemoveFreeNotification(TGLSmoothNavigator(FOwner));
|
|
|
|
+
|
|
|
|
+ FTargetObject := Value;
|
|
|
|
+
|
|
|
|
+ if FTargetObject <> nil then
|
|
|
|
+ if FOwner is TGLSmoothNavigator then
|
|
|
|
+ FTargetObject.FreeNotification(TGLSmoothNavigator(FOwner));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorMoveAroundParameters.StoreCutoff: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FCutoff - EPS2) > EPS8;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorMoveAroundParameters.StoreInertia: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FInertia - 65) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorMoveAroundParameters.StoreMaxAngle: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FMaxAngle - 1.5) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorMoveAroundParameters.StorePitchSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FPitchSpeed - 500) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorMoveAroundParameters.StoreTurnSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FTurnSpeed - 500) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorAdjustDistanceParameters }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorAdjustDistanceParameters.AddImpulse(
|
|
|
|
+ const Impulse: Single);
|
|
|
|
+begin
|
|
|
|
+ FOldDistanceRatio := FOldDistanceRatio + Impulse * FSpeed / FInertia * FImpulseSpeed;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorAdjustDistanceParameters.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+ if Source is TGLNavigatorAdjustDistanceParameters then
|
|
|
|
+ begin
|
|
|
|
+ FImpulseSpeed := TGLNavigatorAdjustDistanceParameters(Source).FImpulseSpeed;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorAdjustDistanceParameters.Create(
|
|
|
|
+ AOwner: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FImpulseSpeed := 0.02;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorAdjustDistanceParameters.ScaleParameters(
|
|
|
|
+ const Value: Single);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FImpulseSpeed := FImpulseSpeed / Value;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAdjustDistanceParameters.StoreImpulseSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FImpulseSpeed - 0.02) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorAbstractParameters }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorAbstractParameters.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ if Source is TGLNavigatorAbstractParameters then
|
|
|
|
+ begin
|
|
|
|
+ FInertia := TGLNavigatorAbstractParameters(Source).FInertia;
|
|
|
|
+ FSpeed := TGLNavigatorAbstractParameters(Source).FSpeed;
|
|
|
|
+ FCutoff := TGLNavigatorAbstractParameters(Source).FCutoff;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited; //to the pit of doom ;)
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorAbstractParameters.Create(
|
|
|
|
+ AOwner: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ FOwner := AOwner;
|
|
|
|
+ FInertia := 100;
|
|
|
|
+ FSpeed := 0.005;
|
|
|
|
+ FCutoff := EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAbstractParameters.GetOwner: TPersistent;
|
|
|
|
+begin
|
|
|
|
+ Result := FOwner;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorAbstractParameters.ScaleParameters(
|
|
|
|
+ const Value: Single);
|
|
|
|
+begin
|
|
|
|
+ Assert(Value > 0);
|
|
|
|
+
|
|
|
|
+ if Value < 1 then
|
|
|
|
+ FInertia := FInertia / PowerSingle(2, Value)
|
|
|
|
+ else
|
|
|
|
+ FInertia := FInertia * PowerSingle(2, 1 / Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAbstractParameters.StoreCutoff: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FCutoff - EPS) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAbstractParameters.StoreInertia: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FInertia - 100) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAbstractParameters.StoreSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FSpeed - 0.005) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorAdjustDistanceParametersEx }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorAdjustDistanceParametersEx.Assign(
|
|
|
|
+ Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ if Source is TGLNavigatorAdjustDistanceParametersEx then
|
|
|
|
+ begin
|
|
|
|
+ FTargetDistance := TGLNavigatorAdjustDistanceParametersEx(Source).FTargetDistance;
|
|
|
|
+ FSpeedLimit := TGLNavigatorAdjustDistanceParametersEx(Source).FSpeedLimit;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorAdjustDistanceParametersEx.Create(
|
|
|
|
+ AOwner: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FInertia := 0.5;
|
|
|
|
+ FTargetDistance := 100;
|
|
|
|
+ FSpeed := 100;
|
|
|
|
+ FSpeedLimit := 20000;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAdjustDistanceParametersEx.StoreInertia: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FInertia - 0.5) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAdjustDistanceParametersEx.StoreSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FSpeed - 100) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAdjustDistanceParametersEx.StoreSpeedLimit: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FSpeedLimit - 20000) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorAdjustDistanceParametersEx.StoreTargetDistance: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FTargetDistance - 100) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorSmoothChangeItem }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeItem.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+
|
|
|
|
+ if Source is TGLNavigatorSmoothChangeItem then
|
|
|
|
+ begin
|
|
|
|
+ FInertia := TGLNavigatorSmoothChangeItem(Source).FInertia;
|
|
|
|
+ FSpeed := TGLNavigatorSmoothChangeItem(Source).FSpeed;
|
|
|
|
+ FSpeedLimit := TGLNavigatorSmoothChangeItem(Source).FSpeedLimit;
|
|
|
|
+ FCutoff := TGLNavigatorSmoothChangeItem(Source).FCutoff;
|
|
|
|
+ FEnabled := TGLNavigatorSmoothChangeItem(Source).FEnabled;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorSmoothChangeItem.Create(aOwner: TXCollection);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FInertia := 1;
|
|
|
|
+ FSpeed := 5.5;
|
|
|
|
+ FSpeedLimit := 20000;
|
|
|
|
+ FCutoff := EPS;
|
|
|
|
+ FEnabled := True;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItem.GetNavigator: TGLSmoothNavigator;
|
|
|
|
+begin
|
|
|
|
+ Result := TGLSmoothNavigator(TGLNavigatorSmoothChangeItems(GetOwner).Owner);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeItem.ScaleParameters(
|
|
|
|
+ const Value: Single);
|
|
|
|
+begin
|
|
|
|
+ Assert(Value > 0);
|
|
|
|
+
|
|
|
|
+ if Value < 1 then
|
|
|
|
+ FInertia := FInertia / PowerSingle(2, Value)
|
|
|
|
+ else
|
|
|
|
+ FInertia := FInertia * PowerSingle(2, 1 / Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItem.StoreCutoff: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FCutoff - EPS) > EPS8;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItem.StoreInertia: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FInertia - 1) > EPS;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItem.StoreSpeed: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FSpeed - 5.5) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItem.StoreSpeedLimit: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := Abs(FSpeedLimit - 20000) > EPS2;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorSmoothChangeItems }
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItems.Add(AClass : TGLNavigatorSmoothChangeItemClass): TGLNavigatorSmoothChangeItem;
|
|
|
|
+begin
|
|
|
|
+ Result := AClass.Create(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItems.CanAdd(AClass: TXCollectionItemClass): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := AClass.InheritsFrom(TGLNavigatorSmoothChangeItem);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeItems.DoProceed(ADeltaTime: Double);
|
|
|
|
+var
|
|
|
|
+ I: Integer;
|
|
|
|
+begin
|
|
|
|
+ for I := 0 to Count - 1 do
|
|
|
|
+ GetItems(I).Proceed(ADeltaTime);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeItems.GetItems(const Index : Integer): TGLNavigatorSmoothChangeItem;
|
|
|
|
+begin
|
|
|
|
+ Result := TGLNavigatorSmoothChangeItem(inherited GetItems(Index));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TGLNavigatorSmoothChangeItems.ItemsClass: TXCollectionItemClass;
|
|
|
|
+begin
|
|
|
|
+ Result := TGLNavigatorSmoothChangeItem;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeItems.SetItems(const Index : Integer; const Value:
|
|
|
|
+ TGLNavigatorSmoothChangeItem);
|
|
|
|
+begin
|
|
|
|
+ GetItems(Index).Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorSmoothChangeSingle }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeSingle.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+
|
|
|
|
+ if Source is TGLNavigatorSmoothChangeVector then
|
|
|
|
+ begin
|
|
|
|
+ FTargetValue := TGLNavigatorSmoothChangeSingle(Source).TargetValue;
|
|
|
|
+ FOnGetCurrentValue := TGLNavigatorSmoothChangeSingle(Source).FOnGetCurrentValue;
|
|
|
|
+ FOnSetCurrentValue := TGLNavigatorSmoothChangeSingle(Source).FOnSetCurrentValue;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TGLNavigatorSmoothChangeSingle.FriendlyName: string;
|
|
|
|
+begin
|
|
|
|
+ Result := 'Navigator SmoothChange Single';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeSingle.Proceed(ADeltaTime: Double): Boolean;
|
|
|
|
+var
|
|
|
|
+ lCurrentValue: Single;
|
|
|
|
+ lCurrentDifference: Single;
|
|
|
|
+ lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
|
|
|
|
+ lMaxExpectedDeltaTime: Double;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Result := False;
|
|
|
|
+ if not FEnabled then Exit;
|
|
|
|
+ if not Assigned(FOnGetCurrentValue) then Exit;
|
|
|
|
+ if not Assigned(FOnSetCurrentValue) then Exit;
|
|
|
|
+
|
|
|
|
+ lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
|
|
|
|
+ lCurrentValue := FOnGetCurrentValue(Self);
|
|
|
|
+ lCurrentDifference := FTargetValue - lCurrentValue;
|
|
|
|
+
|
|
|
|
+ lTotalDistanceToTravelThisTime := 0;
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > lMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ lDistanceToTravelThisTime := MinFloat((lCurrentDifference * ADeltaTime * FSpeed * FInertia) / (FInertia + 1), FSpeedLimit);
|
|
|
|
+// lDistanceToTravelThisTime := (lCurrentDistance * ADeltaTime + FSpeed * FInertia) / (FInertia + 1);- this also works, but a bit different.
|
|
|
|
+
|
|
|
|
+ lCurrentDifference := lCurrentDifference - lDistanceToTravelThisTime;
|
|
|
|
+ lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
|
|
|
|
+ ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
|
|
|
|
+ begin
|
|
|
|
+ FOnSetCurrentValue(Self, lCurrentValue + lTotalDistanceToTravelThisTime);
|
|
|
|
+ Result := True;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeSingle.ResetTargetValue;
|
|
|
|
+begin
|
|
|
|
+ FTargetValue := FOnGetCurrentValue(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGLNavigatorSmoothChangeVector }
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeVector.Assign(Source: TPersistent);
|
|
|
|
+begin
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+
|
|
|
|
+ if Source is TGLNavigatorSmoothChangeVector then
|
|
|
|
+ begin
|
|
|
|
+ FTargetValue.Assign(TGLNavigatorSmoothChangeVector(Source).TargetValue);
|
|
|
|
+ FOnGetCurrentValue := TGLNavigatorSmoothChangeVector(Source).FOnGetCurrentValue;
|
|
|
|
+ FOnSetCurrentValue := TGLNavigatorSmoothChangeVector(Source).FOnSetCurrentValue;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGLNavigatorSmoothChangeVector.Create(aOwner: TXCollection);
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FTargetValue := TGLCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+destructor TGLNavigatorSmoothChangeVector.Destroy;
|
|
|
|
+begin
|
|
|
|
+ FTargetValue.Free;
|
|
|
|
+ inherited;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TGLNavigatorSmoothChangeVector.FriendlyName: string;
|
|
|
|
+begin
|
|
|
|
+ Result := 'Navigator SmoothChange Vector';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGLNavigatorSmoothChangeVector.Proceed(ADeltaTime: Double): Boolean;
|
|
|
|
+var
|
|
|
|
+ lAbsolutePosition: TVector;
|
|
|
|
+ lCurrentDistance: Single;
|
|
|
|
+ lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
|
|
|
|
+ lMaxExpectedDeltaTime: Double;
|
|
|
|
+
|
|
|
|
+ procedure DoAdjustDistanceToPoint();
|
|
|
|
+ var
|
|
|
|
+ vect: TVector;
|
|
|
|
+ begin
|
|
|
|
+ vect := VectorScale(VectorNormalize(VectorSubtract(FTargetValue.DirectVector, lAbsolutePosition)), lTotalDistanceToTravelThisTime);
|
|
|
|
+ AddVector(vect, lAbsolutePosition);
|
|
|
|
+
|
|
|
|
+ // Did we go too far?
|
|
|
|
+ if VectorDistance(vect, FTargetValue.DirectVector) > VectorDistance(lAbsolutePosition, FTargetValue.DirectVector) then
|
|
|
|
+ vect := FTargetValue.DirectVector;
|
|
|
|
+
|
|
|
|
+ FOnSetCurrentValue(Self, vect);
|
|
|
|
+ Result := True;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Result := False;
|
|
|
|
+ if not FEnabled then Exit;
|
|
|
|
+ if not Assigned(FOnGetCurrentValue) then Exit;
|
|
|
|
+ if not Assigned(FOnSetCurrentValue) then Exit;
|
|
|
|
+
|
|
|
|
+ lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
|
|
|
|
+ lAbsolutePosition := FOnGetCurrentValue(Self);
|
|
|
|
+ lCurrentDistance := VectorDistance(lAbsolutePosition, FTargetValue.DirectVector);
|
|
|
|
+
|
|
|
|
+ lTotalDistanceToTravelThisTime := 0;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ while ADeltaTime > lMaxExpectedDeltaTime do
|
|
|
|
+ begin
|
|
|
|
+ lDistanceToTravelThisTime := MinFloat((lCurrentDistance * ADeltaTime * FSpeed * FInertia) / (FInertia + 1), FSpeedLimit);
|
|
|
|
+// lDistanceToTravelThisTime := (lCurrentDistance * ADeltaTime + FSpeed * FInertia) / (FInertia + 1);- this also works, but a bit different.
|
|
|
|
+
|
|
|
|
+ lCurrentDistance := lCurrentDistance - lDistanceToTravelThisTime;
|
|
|
|
+ lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
|
|
|
|
+ ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
|
|
|
|
+ DoAdjustDistanceToPoint();
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeVector.ResetTargetValue;
|
|
|
|
+begin
|
|
|
|
+ FTargetValue.DirectVector := FOnGetCurrentValue(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TGLNavigatorSmoothChangeVector.SetTargetValue(
|
|
|
|
+ const Value: TGLCoordinates);
|
|
|
|
+begin
|
|
|
|
+ FTargetValue.Assign(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+//==========================================================
|
|
|
|
+initialization
|
|
|
|
+//==========================================================
|
|
|
|
+
|
|
|
|
+ RegisterClasses([
|
|
|
|
+ TGLSmoothNavigator, TGLSmoothUserInterface,
|
|
|
|
+ TGLNavigatorInertiaParameters, TGLNavigatorGeneralParameters,
|
|
|
|
+ TGLNavigatorMoveAroundParameters,
|
|
|
|
+ TGLNavigatorAdjustDistanceParameters, TGLNavigatorAdjustDistanceParametersEx
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ RegisterXCollectionItemClass(TGLNavigatorSmoothChangeSingle);
|
|
|
|
+ RegisterXCollectionItemClass(TGLNavigatorSmoothChangeVector);
|
|
|
|
+end.
|
|
|
|
+
|
|
|
|
+
|