GXS.SmoothNavigator.pas 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.SmoothNavigator;
  5. (*
  6. An extention of TgxNavigator, which allows to move objects with inertia
  7. Note: it is not completely FPS-independant. Only Moving code is, but
  8. MoveAroundTarget, Turn[Vertical/Horizontal] and AdjustDistanceTo[..] is not.
  9. Don't know why, but when I make their code identical, these function stop
  10. working completely. So you probably have to call the AutoScaleParameters
  11. procedure once in a while for it to adjust to the current framerate.
  12. TODO:
  13. 1) Scale "Old values" too, when callin the Scale parameter procedure to
  14. avoid the temporary "freeze" of controls.
  15. 2) AddImpulse procedures.
  16. *)
  17. interface
  18. {$I Stage.Defines.inc}
  19. uses
  20. System.Types,
  21. System.Classes,
  22. GXS.XCollection,
  23. Stage.VectorTypes,
  24. GXS.Navigator,
  25. Stage.VectorGeometry,
  26. GXS.Scene,
  27. GXS.Coordinates,
  28. GXS.Screen,
  29. GXS.PersistentClasses;
  30. type
  31. { Includes a basic set of parameters that control the smoothness of movement. }
  32. TgxNavigatorAbstractParameters = class(TPersistent)
  33. private
  34. FOwner: TPersistent;
  35. FInertia: Single;
  36. FSpeed: Single;
  37. FCutoff: Single;
  38. function StoreCutoff: Boolean;
  39. protected
  40. function StoreInertia: Boolean; virtual;
  41. function StoreSpeed: Boolean; virtual;
  42. function GetOwner: TPersistent; override;
  43. public
  44. constructor Create(AOwner: TPersistent); virtual;
  45. procedure Assign(Source: TPersistent); override;
  46. procedure ScaleParameters(const Value: Single); virtual;
  47. published
  48. property Inertia: Single read FInertia write FInertia stored StoreInertia;
  49. property Speed: Single read FSpeed write FSpeed stored StoreSpeed;
  50. property Cutoff: Single read FCutoff write FCutoff stored StoreCutoff;
  51. end;
  52. TgxSmoothNavigator = class;
  53. { Includes a basic set of parameters that control the smoothness of movement }
  54. TgxNavigatorSmoothChangeItem = class(TXCollectionItem)
  55. private
  56. FInertia: Single;
  57. FSpeed: Single;
  58. FEnabled: Boolean;
  59. FSpeedLimit: Single;
  60. FCutoff: Double;
  61. function StoreInertia: Boolean;
  62. function StoreSpeed: Boolean;
  63. function StoreSpeedLimit: Boolean;
  64. function StoreCutoff: Boolean;
  65. protected
  66. function GetNavigator: TgxSmoothNavigator;
  67. public
  68. { Returns False if there was no change. }
  69. function Proceed(ADeltaTime: Double): Boolean; virtual; abstract;
  70. constructor Create(aOwner: TXCollection); override;
  71. procedure Assign(Source: TPersistent); override;
  72. procedure ScaleParameters(const Value: Single); virtual;
  73. procedure ResetTargetValue(); virtual; abstract;
  74. published
  75. property Inertia: Single read FInertia write FInertia stored StoreInertia;
  76. property Speed: Single read FSpeed write FSpeed stored StoreSpeed;
  77. property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
  78. property Cutoff: Double read FCutoff write FCutoff stored StoreCutoff;
  79. property Enabled: Boolean read FEnabled write FEnabled default True;
  80. end;
  81. TgxNavigatorSmoothChangeSingle = class;
  82. TgxNavigatorSmoothChangeSingleGetEvent = function(const ASender: TgxNavigatorSmoothChangeSingle): Single of object;
  83. TgxNavigatorSmoothChangeSingleSetEvent = procedure(const ASender: TgxNavigatorSmoothChangeSingle; const AValue: Single) of object;
  84. { Smoothly change any Single value, so it will become TargetValue in the end. }
  85. TgxNavigatorSmoothChangeSingle = class(TgxNavigatorSmoothChangeItem)
  86. private
  87. FTargetValue: Single;
  88. FOnGetCurrentValue: TgxNavigatorSmoothChangeSingleGetEvent;
  89. FOnSetCurrentValue: TgxNavigatorSmoothChangeSingleSetEvent;
  90. public
  91. class function FriendlyName: string; override;
  92. function Proceed(ADeltaTime: Double): Boolean; override;
  93. procedure Assign(Source: TPersistent); override;
  94. procedure ResetTargetValue(); override;
  95. published
  96. property TargetValue: Single read FTargetValue write FTargetValue;
  97. property OnGetCurrentValue: TgxNavigatorSmoothChangeSingleGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
  98. property OnSetCurrentValue: TgxNavigatorSmoothChangeSingleSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
  99. end;
  100. TgxNavigatorSmoothChangeVector = class;
  101. TgxNavigatorSmoothChangeVectorGetEvent = function(const ASender: TgxNavigatorSmoothChangeVector): TVector4f of object;
  102. TgxNavigatorSmoothChangeVectorSetEvent = procedure(const ASender: TgxNavigatorSmoothChangeVector; const AValue: TVector4f) of object;
  103. { Smoothly change any Vector4f value, so it will become TargetValue in the end. }
  104. TgxNavigatorSmoothChangeVector = class(TgxNavigatorSmoothChangeItem)
  105. private
  106. FTargetValue: TgxCoordinates;
  107. FOnGetCurrentValue: TgxNavigatorSmoothChangeVectorGetEvent;
  108. FOnSetCurrentValue: TgxNavigatorSmoothChangeVectorSetEvent;
  109. procedure SetTargetValue(const Value: TgxCoordinates);
  110. public
  111. class function FriendlyName: string; override;
  112. function Proceed(ADeltaTime: Double): Boolean; override;
  113. procedure Assign(Source: TPersistent); override;
  114. constructor Create(aOwner: TXCollection); override;
  115. destructor Destroy; override;
  116. procedure ResetTargetValue(); override;
  117. published
  118. property TargetValue: TgxCoordinates read FTargetValue write SetTargetValue;
  119. property OnGetCurrentValue: TgxNavigatorSmoothChangeVectorGetEvent read FOnGetCurrentValue write FOnGetCurrentValue;
  120. property OnSetCurrentValue: TgxNavigatorSmoothChangeVectorSetEvent read FOnSetCurrentValue write FOnSetCurrentValue;
  121. end;
  122. TgxNavigatorSmoothChangeItemClass = class of TgxNavigatorSmoothChangeItem;
  123. { XCollection of TgxNavigatorSmoothChangeItem. }
  124. TgxNavigatorSmoothChangeItems = class(TXCollection)
  125. private
  126. function GetItems(const Index : Integer): TgxNavigatorSmoothChangeItem;
  127. procedure SetItems(const Index : Integer; const Value: TgxNavigatorSmoothChangeItem);
  128. protected
  129. procedure DoProceed(ADeltaTime: Double);
  130. public
  131. function Add(AClass : TgxNavigatorSmoothChangeItemClass): TgxNavigatorSmoothChangeItem;
  132. function CanAdd(AClass: TXCollectionItemClass): Boolean; override;
  133. class function ItemsClass: TXCollectionItemClass; override;
  134. property Items[const Index : Integer]: TgxNavigatorSmoothChangeItem read GetItems write
  135. SetItems; default;
  136. end;
  137. { This is wrapper for all parameters that affect how the AdjustDisanceTo[...] methods work }
  138. TgxNavigatorAdjustDistanceParameters = class(TgxNavigatorAbstractParameters)
  139. private
  140. FOldDistanceRatio: Single;
  141. FImpulseSpeed: Single;
  142. function StoreImpulseSpeed: Boolean;
  143. public
  144. constructor Create(AOwner: TPersistent); override;
  145. procedure Assign(Source: TPersistent); override;
  146. procedure ScaleParameters(const Value: Single); override;
  147. procedure AddImpulse(const Impulse: Single); virtual;
  148. published
  149. property ImpulseSpeed: Single read FImpulseSpeed write FImpulseSpeed stored StoreImpulseSpeed;
  150. end;
  151. { This is a wrapper for all parameters that affect how the AdjustDisanceTo[...]Ex methods work
  152. You need to set the TargetObject and desired distance to it,
  153. then call AdjustDisanceTo[...]Ex() in your Cadencer.OnProgress code. }
  154. TgxNavigatorAdjustDistanceParametersEx = class(TgxNavigatorAbstractParameters)
  155. private
  156. FSpeedLimit: Single;
  157. FTargetDistance: Single;
  158. function StoreSpeedLimit: Boolean;
  159. function StoreTargetDistance: Boolean;
  160. protected
  161. function StoreSpeed: Boolean; override;
  162. function StoreInertia: Boolean; override;
  163. public
  164. constructor Create(AOwner: TPersistent); override;
  165. procedure Assign(Source: TPersistent); override;
  166. published
  167. property TargetDistance: Single read FTargetDistance write FTargetDistance stored StoreTargetDistance;
  168. property SpeedLimit: Single read FSpeedLimit write FSpeedLimit stored StoreSpeedLimit;
  169. end;
  170. { This is a wrapper for all parameters that affect the smoothness of movement }
  171. TgxNavigatorInertiaParameters = class(TPersistent)
  172. private
  173. FOwner: TPersistent;
  174. OldTurnHorizontalAngle: Single;
  175. OldTurnVerticalAngle: Single;
  176. OldMoveForwardDistance: Single;
  177. OldStrafeHorizontalDistance: Single;
  178. OldStrafeVerticalDistance: Single;
  179. FTurnInertia: Single;
  180. FTurnSpeed: Single;
  181. FTurnMaxAngle: Single;
  182. FMovementAcceleration: Single;
  183. FMovementInertia: Single;
  184. FMovementSpeed: Single;
  185. function StoreTurnMaxAngle: Boolean;
  186. function StoreMovementAcceleration: Boolean;
  187. function StoreMovementInertia: Boolean;
  188. function StoreMovementSpeed: Boolean;
  189. function StoreTurnInertia: Boolean;
  190. function StoreTurnSpeed: Boolean;
  191. protected
  192. function GetOwner: TPersistent; override;
  193. public
  194. constructor Create(AOwner: TPersistent); virtual;
  195. procedure Assign(Source: TPersistent); override;
  196. procedure ScaleParameters(const Value: Single); virtual;
  197. published
  198. property MovementAcceleration: Single read FMovementAcceleration write FMovementAcceleration stored StoreMovementAcceleration;
  199. property MovementInertia: Single read FMovementInertia write FMovementInertia stored StoreMovementInertia;
  200. property MovementSpeed: Single read FMovementSpeed write FMovementSpeed stored StoreMovementSpeed;
  201. property TurnMaxAngle: Single read FTurnMaxAngle write FTurnMaxAngle stored StoreTurnMaxAngle;
  202. property TurnInertia: Single read FTurnInertia write FTurnInertia stored StoreTurnInertia;
  203. property TurnSpeed: Single read FTurnSpeed write FTurnSpeed stored StoreTurnSpeed;
  204. end;
  205. { This is a wrapper for all general inertia parameters.
  206. These properties mean that if ExpectedMaxFPS is 100, FAutoScaleMin is 0.1,
  207. FAutoScaleMax is 0.75 then the "safe range" for it to change is [10..75].
  208. If these bounds are violated, then ExpectedMaxFPS is automaticly increased
  209. or decreased by AutoScaleMult. }
  210. TgxNavigatorGeneralParameters = class(TPersistent)
  211. private
  212. FOwner: TPersistent;
  213. FAutoScaleMin: Single;
  214. FAutoScaleMax: Single;
  215. FAutoScaleMult: Single;
  216. function StoreAutoScaleMax: Boolean;
  217. function StoreAutoScaleMin: Boolean;
  218. function StoreAutoScaleMult: Boolean;
  219. protected
  220. function GetOwner: TPersistent; override;
  221. public
  222. constructor Create(AOwner: TPersistent); virtual;
  223. procedure Assign(Source: TPersistent); override;
  224. published
  225. property AutoScaleMin: Single read FAutoScaleMin write FAutoScaleMin stored StoreAutoScaleMin;
  226. property AutoScaleMax: Single read FAutoScaleMax write FAutoScaleMax stored StoreAutoScaleMax;
  227. property AutoScaleMult: Single read FAutoScaleMult write FAutoScaleMult stored StoreAutoScaleMult;
  228. end;
  229. { This is a wrapper for all parameters that effect how the TgxBaseSceneObject.MoveObjectAround() procedure works}
  230. TgxNavigatorMoveAroundParameters = class(TPersistent)
  231. private
  232. FOwner: TPersistent;
  233. FTargetObject: TgxBaseSceneObject;
  234. FOldPitchInertiaAngle : Single;
  235. FOldTurnInertiaAngle : Single;
  236. FPitchSpeed : Single;
  237. FTurnSpeed : Single;
  238. FInertia : Single;
  239. FMaxAngle : Single;
  240. FCutoff: Double;
  241. function StoreInertia: Boolean;
  242. function StoreMaxAngle: Boolean;
  243. function StorePitchSpeed: Boolean;
  244. function StoreTurnSpeed: Boolean;
  245. procedure SetTargetObject(const Value: TgxBaseSceneObject);
  246. function StoreCutoff: Boolean;
  247. protected
  248. function GetOwner: TPersistent; override;
  249. public
  250. constructor Create(AOwner: TPersistent); virtual;
  251. procedure Assign(Source: TPersistent); override;
  252. procedure ScaleParameters(const Value: Single); virtual;
  253. published
  254. property Inertia: Single read FInertia write FInertia stored StoreInertia;
  255. property MaxAngle: Single read FMaxAngle write FMaxAngle stored StoreMaxAngle;
  256. property PitchSpeed: Single read FPitchSpeed write FPitchSpeed stored StorePitchSpeed;
  257. property TurnSpeed: Single read FTurnSpeed write FTurnSpeed stored StoreTurnSpeed;
  258. property TargetObject: TgxBaseSceneObject read FTargetObject write SetTargetObject;
  259. property Cutoff: Double read FCutoff write FCutoff stored StoreCutoff;
  260. end;
  261. { This is the component for moving a TgxBaseSceneObject, and all
  262. classes based on it, this includes all the objects from the Scene Editor.
  263. It uses complex smoothing algorithms, most of which are FPS-dependant.
  264. Make sure your limit your FPS and set MaxExpectedDeltaTime to a value
  265. that is aproximatly 5 times less than your usual deltatime. }
  266. TgxSmoothNavigator = class(TgxNavigator)
  267. private
  268. FMaxExpectedDeltaTime: Double;
  269. FInertiaParams: TgxNavigatorInertiaParameters;
  270. FGeneralParams: TgxNavigatorGeneralParameters;
  271. FMoveAroundParams: TgxNavigatorMoveAroundParameters;
  272. FAdjustDistanceParams: TgxNavigatorAdjustDistanceParameters;
  273. FAdjustDistanceParamsEx: TgxNavigatorAdjustDistanceParametersEx;
  274. FCustomAnimatedItems: TgxNavigatorSmoothChangeItems;
  275. procedure SetInertiaParams(const Value: TgxNavigatorInertiaParameters);
  276. function StoreMaxExpectedDeltaTime: Boolean;
  277. procedure SetGeneralParams(const Value: TgxNavigatorGeneralParameters);
  278. procedure SetMoveAroundParams(const Value: TgxNavigatorMoveAroundParameters);
  279. procedure SetAdjustDistanceParams(const Value: TgxNavigatorAdjustDistanceParameters);
  280. procedure SetAdjustDistanceParamsEx(
  281. const Value: TgxNavigatorAdjustDistanceParametersEx);
  282. procedure SetCustomAnimatedItems(
  283. const Value: TgxNavigatorSmoothChangeItems);
  284. protected
  285. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  286. public
  287. // Constructors-destructors.
  288. constructor Create(AOwner: TComponent); override;
  289. destructor Destroy; override;
  290. // From TgxNavigator. Probably, should not be public.
  291. procedure SetObject(Value: TgxBaseSceneObject); override;
  292. // Uses InertiaParams.
  293. procedure TurnHorizontal(Angle: Single; ADeltaTime: Double); virtual;
  294. procedure TurnVertical(Angle: Single; ADeltaTime: Double); virtual;
  295. procedure FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
  296. procedure MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
  297. procedure StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
  298. procedure StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False); virtual;
  299. // Uses MoveAroundParams. Returns True, if object was actually moved.
  300. function MoveAroundTarget(const PitchDelta, TurnDelta : Single; const ADeltaTime: Double): Boolean; virtual;
  301. function MoveObjectAround(const AObject: TgxBaseSceneObject; PitchDelta, TurnDelta : Single; ADeltaTime: Double): Boolean; virtual;
  302. // Uses AdjustDistanceParams.
  303. function AdjustDistanceToPoint(const APoint: TVector4f; const DistanceRatio : Single; ADeltaTime: Double): Boolean; virtual;
  304. function AdjustDistanceToTarget(const DistanceRatio : Single; const ADeltaTime: Double): Boolean; virtual;
  305. // Uses AdjustDistanceParamsEx.
  306. function AdjustDistanceToPointEx(const APoint: TVector4f; ADeltaTime: Double): Boolean; virtual;
  307. function AdjustDistanceToTargetEx(const ADeltaTime: Double): Boolean; virtual;
  308. // Uses CustomAnimatedItems.
  309. procedure AnimateCustomItems(const ADeltaTime: Double); virtual;
  310. // Uses GeneralParams.
  311. { In ScaleParameters, Value should be around 1. }
  312. procedure ScaleParameters(const Value: Single); virtual;
  313. procedure AutoScaleParameters(const FPS: Single); virtual;
  314. procedure AutoScaleParametersUp(const FPS: Single); virtual;
  315. published
  316. property MaxExpectedDeltaTime: Double read FMaxExpectedDeltaTime write FMaxExpectedDeltaTime stored StoreMaxExpectedDeltaTime;
  317. property InertiaParams: TgxNavigatorInertiaParameters read FInertiaParams write SetInertiaParams;
  318. property GeneralParams: TgxNavigatorGeneralParameters read FGeneralParams write SetGeneralParams;
  319. property MoveAroundParams: TgxNavigatorMoveAroundParameters read FMoveAroundParams write SetMoveAroundParams;
  320. property AdjustDistanceParams: TgxNavigatorAdjustDistanceParameters read FAdjustDistanceParams write SetAdjustDistanceParams;
  321. property AdjustDistanceParamsEx: TgxNavigatorAdjustDistanceParametersEx read FAdjustDistanceParamsEx write SetAdjustDistanceParamsEx;
  322. property CustomAnimatedItems: TgxNavigatorSmoothChangeItems read FCustomAnimatedItems write SetCustomAnimatedItems;
  323. end;
  324. { This is the component which reads the userinput and transform it into action.
  325. Mouselook(ADeltaTime: double) : handles mouse look... Should be called
  326. in the Cadencer event. (Though it works everywhere!)
  327. The four properties to get you started are:
  328. InvertMouse : Inverts the mouse Y axis.
  329. AutoUpdateMouse : If enabled (by defaul), than handles all mouse updates.
  330. GLNavigator : The Navigator which receives the user movement.
  331. GLVertNavigator : The Navigator which if set receives the vertical user
  332. movement. Used mostly for cameras.... }
  333. TgxSmoothUserInterface = class(TComponent)
  334. private
  335. FAutoUpdateMouse: Boolean;
  336. FMouseLookActive: Boolean;
  337. FSmoothNavigator: TgxSmoothNavigator;
  338. FSmoothVertNavigator: TgxSmoothNavigator;
  339. FInvertMouse: Boolean;
  340. FOriginalMousePos: TgxCoordinates2;
  341. procedure SetSmoothNavigator(const Value: TgxSmoothNavigator); virtual;
  342. procedure SetOriginalMousePos(const Value: TgxCoordinates2); virtual;
  343. procedure SetSmoothVertNavigator(const Value: TgxSmoothNavigator); virtual;
  344. procedure SetMouseLookActive(const Value: Boolean); virtual;
  345. protected
  346. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  347. public
  348. constructor Create(AOwner: TComponent); override;
  349. destructor Destroy; override;
  350. procedure TurnHorizontal(const Angle : Single; const ADeltaTime: Double); virtual;
  351. procedure TurnVertical(const Angle : Single; const ADeltaTime: Double); virtual;
  352. procedure MouseLookActiveToggle; virtual;
  353. function MouseLook(const ADeltaTime: Double): Boolean; overload;
  354. function MouseLook(const NewXY: TPoint; const ADeltaTime: Double): Boolean; overload;
  355. function MouseLook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean; overload;
  356. published
  357. property AutoUpdateMouse: Boolean read FAutoUpdateMouse write FAutoUpdateMouse default True;
  358. property MouseLookActive: Boolean read FMouseLookActive write SetMouseLookActive default False;
  359. property SmoothVertNavigator: TgxSmoothNavigator read FSmoothVertNavigator write SetSmoothVertNavigator;
  360. property SmoothNavigator: TgxSmoothNavigator read FSmoothNavigator write SetSmoothNavigator;
  361. property InvertMouse: Boolean read FInvertMouse write FInvertMouse default False;
  362. property OriginalMousePos: TgxCoordinates2 read FOriginalMousePos write SetOriginalMousePos;
  363. end;
  364. //-----------------------------------------------------------
  365. implementation
  366. //-----------------------------------------------------------
  367. const
  368. EPS = 0.001;
  369. EPS2 = 0.0001;
  370. EPS8 = 0.00000001;
  371. { TgxSmoothNavigator }
  372. constructor TgxSmoothNavigator.Create(AOwner: TComponent);
  373. begin
  374. inherited;
  375. FMaxExpectedDeltaTime := 0.001;
  376. FInertiaParams := TgxNavigatorInertiaParameters.Create(Self);
  377. FGeneralParams := TgxNavigatorGeneralParameters.Create(Self);
  378. FMoveAroundParams := TgxNavigatorMoveAroundParameters.Create(Self);
  379. FAdjustDistanceParams := TgxNavigatorAdjustDistanceParameters.Create(Self);
  380. FAdjustDistanceParamsEx := TgxNavigatorAdjustDistanceParametersEx.Create(Self);
  381. FCustomAnimatedItems := TgxNavigatorSmoothChangeItems.Create(Self);
  382. end;
  383. destructor TgxSmoothNavigator.Destroy;
  384. begin
  385. FInertiaParams.Free;
  386. FGeneralParams.Free;
  387. FMoveAroundParams.Free;
  388. FAdjustDistanceParams.Free;
  389. FAdjustDistanceParamsEx.Free;
  390. FCustomAnimatedItems.Free;
  391. inherited;
  392. end;
  393. procedure TgxSmoothNavigator.SetInertiaParams(
  394. const Value: TgxNavigatorInertiaParameters);
  395. begin
  396. FInertiaParams.Assign(Value);
  397. end;
  398. procedure TgxSmoothNavigator.TurnHorizontal(Angle: Single; ADeltaTime: Double);
  399. var
  400. FinalAngle: Single;
  401. begin
  402. with FInertiaParams do
  403. begin
  404. FinalAngle := 0;
  405. Angle := Angle * FTurnSpeed;
  406. while ADeltaTime > FMaxExpectedDeltaTime do
  407. begin
  408. Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnHorizontalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
  409. OldTurnHorizontalAngle := Angle;
  410. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  411. FinalAngle := FinalAngle + Angle;
  412. end;
  413. end;
  414. if (Abs(FinalAngle) > EPS) then
  415. inherited TurnHorizontal(FinalAngle);
  416. end;
  417. procedure TgxSmoothNavigator.TurnVertical(Angle: Single; ADeltaTime: Double);
  418. var
  419. FinalAngle: Single;
  420. begin
  421. with FInertiaParams do
  422. begin
  423. FinalAngle := 0;
  424. Angle := Angle * FTurnSpeed;
  425. while ADeltaTime > FMaxExpectedDeltaTime do
  426. begin
  427. Angle := ClampValue((Angle * FMaxExpectedDeltaTime + OldTurnVerticalAngle * FTurnInertia) / (FTurnInertia + 1), -FTurnMaxAngle, FTurnMaxAngle);
  428. OldTurnVerticalAngle := Angle;
  429. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  430. FinalAngle := FinalAngle + Angle;
  431. end;
  432. end;
  433. if (Abs(FinalAngle) > EPS) then
  434. inherited TurnVertical(FinalAngle);
  435. end;
  436. procedure TgxSmoothNavigator.MoveForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
  437. var
  438. FinalDistance: Single;
  439. Distance: Single;
  440. begin
  441. with FInertiaParams do
  442. begin
  443. if Plus then
  444. Distance := FMovementSpeed
  445. else if Minus then
  446. Distance := -FMovementSpeed
  447. else
  448. Distance := 0;
  449. if Accelerate then
  450. Distance := Distance * FMovementAcceleration;
  451. FinalDistance := 0;
  452. while ADeltaTime > FMaxExpectedDeltaTime do
  453. begin
  454. OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
  455. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  456. FinalDistance := FinalDistance + OldMoveForwardDistance;
  457. end;
  458. end;
  459. if Abs(FinalDistance) > EPS then
  460. inherited MoveForward(FinalDistance);
  461. end;
  462. procedure TgxSmoothNavigator.FlyForward(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
  463. var
  464. FinalDistance: Single;
  465. Distance: Single;
  466. begin
  467. with FInertiaParams do
  468. begin
  469. if Plus then
  470. Distance := FMovementSpeed
  471. else if Minus then
  472. Distance := -FMovementSpeed
  473. else
  474. Distance := 0;
  475. if Accelerate then
  476. Distance := Distance * FMovementAcceleration;
  477. FinalDistance := 0;
  478. while ADeltaTime > FMaxExpectedDeltaTime do
  479. begin
  480. OldMoveForwardDistance := (Distance * FMaxExpectedDeltaTime + OldMoveForwardDistance * FMovementInertia) / (FMovementInertia + 1);
  481. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  482. FinalDistance := FinalDistance + OldMoveForwardDistance;
  483. end;
  484. end;
  485. if Abs(FinalDistance) > EPS then
  486. inherited FlyForward(FinalDistance);
  487. end;
  488. procedure TgxSmoothNavigator.StrafeHorizontal(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
  489. var
  490. FinalDistance: Single;
  491. Distance: Single;
  492. begin
  493. with FInertiaParams do
  494. begin
  495. if Plus then
  496. Distance := FMovementSpeed
  497. else if Minus then
  498. Distance := -FMovementSpeed
  499. else
  500. Distance := 0;
  501. if Accelerate then
  502. Distance := Distance * FMovementAcceleration;
  503. FinalDistance := 0;
  504. while ADeltaTime > FMaxExpectedDeltaTime do
  505. begin
  506. OldStrafeHorizontalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeHorizontalDistance * FMovementInertia) / (FMovementInertia + 1);
  507. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  508. FinalDistance := FinalDistance + OldStrafeHorizontalDistance;
  509. end;
  510. end;
  511. if Abs(FinalDistance) > EPS then
  512. inherited StrafeHorizontal(FinalDistance);
  513. end;
  514. procedure TgxSmoothNavigator.StrafeVertical(const Plus, Minus: Boolean; ADeltaTime: Double; const Accelerate: Boolean = False);
  515. var
  516. FinalDistance: Single;
  517. Distance: Single;
  518. begin
  519. with FInertiaParams do
  520. begin
  521. if Plus then
  522. Distance := FMovementSpeed
  523. else if Minus then
  524. Distance := -FMovementSpeed
  525. else
  526. Distance := 0;
  527. if Accelerate then
  528. Distance := Distance * FMovementAcceleration;
  529. FinalDistance := 0;
  530. while ADeltaTime > FMaxExpectedDeltaTime do
  531. begin
  532. OldStrafeVerticalDistance := (Distance * FMaxExpectedDeltaTime + OldStrafeVerticalDistance * FMovementInertia) / (FMovementInertia + 1);
  533. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  534. FinalDistance := FinalDistance + OldStrafeVerticalDistance;
  535. end;
  536. end;
  537. if Abs(FinalDistance) > EPS then
  538. inherited StrafeVertical(FinalDistance);
  539. end;
  540. procedure TgxSmoothNavigator.AutoScaleParameters(const FPS: Single);
  541. begin
  542. with FGeneralParams do
  543. begin
  544. if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
  545. ScaleParameters(FAutoScaleMult)
  546. else if FPS < FAutoScaleMin / FMaxExpectedDeltatime then
  547. ScaleParameters(1/FAutoScaleMult);
  548. end;
  549. end;
  550. procedure TgxSmoothNavigator.AutoScaleParametersUp(const FPS: Single);
  551. begin
  552. with FGeneralParams do
  553. begin
  554. if FPS > FAutoScaleMax / FMaxExpectedDeltatime then
  555. ScaleParameters(FAutoScaleMult)
  556. end;
  557. end;
  558. procedure TgxSmoothNavigator.ScaleParameters(const Value: Single);
  559. begin
  560. Assert(Value > 0);
  561. FMaxExpectedDeltatime := FMaxExpectedDeltatime / Value;
  562. FInertiaParams.ScaleParameters(Value);
  563. FMoveAroundParams.ScaleParameters(Value);
  564. FAdjustDistanceParams.ScaleParameters(Value);
  565. end;
  566. function TgxSmoothNavigator.StoreMaxExpectedDeltaTime: Boolean;
  567. begin
  568. Result := Abs(FMaxExpectedDeltaTime - 0.001) > EPS2;
  569. end;
  570. procedure TgxSmoothNavigator.SetGeneralParams(
  571. const Value: TgxNavigatorGeneralParameters);
  572. begin
  573. FGeneralParams.Assign(Value);
  574. end;
  575. procedure TgxSmoothNavigator.SetMoveAroundParams(
  576. const Value: TgxNavigatorMoveAroundParameters);
  577. begin
  578. FMoveAroundParams.Assign(Value);
  579. end;
  580. procedure TgxSmoothNavigator.Notification(AComponent: TComponent;
  581. Operation: TOperation);
  582. begin
  583. inherited;
  584. if Operation = opRemove then
  585. begin
  586. if AComponent = FMoveAroundParams.FTargetObject then
  587. FMoveAroundParams.FTargetObject := nil;
  588. end;
  589. end;
  590. procedure TgxSmoothNavigator.SetObject(Value: TgxBaseSceneObject);
  591. var
  592. I: Integer;
  593. begin
  594. inherited;
  595. // Try to detect a TargetObject.
  596. if Value <> nil then
  597. if FMoveAroundParams.TargetObject = nil then
  598. begin
  599. // May be it is a camera...
  600. if Value is TgxCamera then
  601. FMoveAroundParams.TargetObject := TgxCamera(Value).TargetObject
  602. else
  603. begin
  604. // May be it has camera children...
  605. if Value.Count <> 0 then
  606. for I := 0 to Value.Count - 1 do
  607. if Value.Children[I] is TgxCamera then
  608. begin
  609. FMoveAroundParams.TargetObject := TgxCamera(Value.Children[I]).TargetObject;
  610. Exit;
  611. end;
  612. end;
  613. end;
  614. end;
  615. function TgxSmoothNavigator.MoveAroundTarget(const PitchDelta, TurnDelta: Single;
  616. const ADeltaTime: Double): Boolean;
  617. begin
  618. Result := MoveObjectAround(FMoveAroundParams.FTargetObject, PitchDelta, TurnDelta, ADeltaTime);
  619. end;
  620. function TgxSmoothNavigator.MoveObjectAround(
  621. const AObject: TgxBaseSceneObject; PitchDelta, TurnDelta: Single;
  622. ADeltaTime: Double): Boolean;
  623. var
  624. FinalPitch: Single;
  625. FinalTurn: Single;
  626. lUp: TVector4f;
  627. begin
  628. Result := False;
  629. FinalPitch := 0;
  630. FinalTurn := 0;
  631. with FMoveAroundParams do
  632. begin
  633. PitchDelta := PitchDelta * FPitchSpeed;
  634. TurnDelta := TurnDelta * FTurnSpeed;
  635. while ADeltaTime > FMaxExpectedDeltatime do
  636. begin
  637. PitchDelta := ClampValue((PitchDelta * FMaxExpectedDeltatime + FOldPitchInertiaAngle * FInertia) / (FInertia + 1), - FMaxAngle, FMaxAngle);
  638. FOldPitchInertiaAngle := PitchDelta;
  639. FinalPitch := FinalPitch + PitchDelta;
  640. TurnDelta := ClampValue((TurnDelta * FMaxExpectedDeltatime + FOldTurnInertiaAngle * FInertia) / (FInertia + 1), - FMaxAngle, FMaxAngle);
  641. FOldTurnInertiaAngle := TurnDelta;
  642. FinalTurn := FinalTurn + TurnDelta;
  643. ADeltaTime := ADeltaTime - FMaxExpectedDeltatime;
  644. end;
  645. if UseVirtualUp then
  646. lUp := VirtualUp.AsVector
  647. else
  648. lUp := MovingObject.AbsoluteUp;
  649. if (Abs(FinalPitch) > FCutOff) or (Abs(FinalTurn) > FCutOff) then
  650. begin
  651. MovingObject.AbsolutePosition := Stage.VectorGeometry.MoveObjectAround(
  652. MovingObject.AbsolutePosition, lUp, AObject.AbsolutePosition, FinalPitch, FinalTurn);
  653. Result := True;
  654. end;
  655. end;
  656. end;
  657. function TgxSmoothNavigator.AdjustDistanceToPoint(const APoint: TVector4f;
  658. const DistanceRatio: Single; ADeltaTime: Double): Boolean;
  659. // Based on TgxCamera.AdjustDistanceToTarget
  660. procedure DoAdjustDistanceToPoint(const DistanceRatio: Single);
  661. var
  662. vect: TVector4f;
  663. begin
  664. vect := VectorSubtract(MovingObject.AbsolutePosition, APoint);
  665. ScaleVector(vect, (distanceRatio - 1));
  666. AddVector(vect, MovingObject.AbsolutePosition);
  667. if Assigned(MovingObject.Parent) then
  668. vect := MovingObject.Parent.AbsoluteToLocal(vect);
  669. MovingObject.Position.AsVector := vect;
  670. Result := True;
  671. end;
  672. var
  673. FinalDistanceRatio: Single;
  674. TempDistanceRatio: Single;
  675. begin
  676. with FAdjustDistanceParams do
  677. begin
  678. TempDistanceRatio := DistanceRatio * FSpeed;
  679. FinalDistanceRatio := 0;
  680. while ADeltaTime > FMaxExpectedDeltaTime do
  681. begin
  682. TempDistanceRatio := (TempDistanceRatio * FMaxExpectedDeltaTime + FOldDistanceRatio * FInertia) / (FInertia + 1);
  683. FOldDistanceRatio := TempDistanceRatio;
  684. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  685. FinalDistanceRatio := FinalDistanceRatio + FOldDistanceRatio / FMaxExpectedDeltaTime;
  686. end;
  687. if Abs(FinalDistanceRatio) > FCutoff then
  688. begin
  689. if FinalDistanceRatio > 0 then
  690. DoAdjustDistanceToPoint(1 / (1 + FinalDistanceRatio))
  691. else
  692. DoAdjustDistanceToPoint(1 * (1 - FinalDistanceRatio))
  693. end
  694. else
  695. Result := False;
  696. end;
  697. end;
  698. function TgxSmoothNavigator.AdjustDistanceToTarget(const DistanceRatio: Single;
  699. const ADeltaTime: Double): Boolean;
  700. begin
  701. Assert(FMoveAroundParams.FTargetObject <> nil);
  702. Result := AdjustDistanceToPoint(FMoveAroundParams.FTargetObject.AbsolutePosition,
  703. DistanceRatio, ADeltaTime);
  704. end;
  705. procedure TgxSmoothNavigator.SetAdjustDistanceParams(
  706. const Value: TgxNavigatorAdjustDistanceParameters);
  707. begin
  708. FAdjustDistanceParams.Assign(Value);
  709. end;
  710. function TgxSmoothNavigator.AdjustDistanceToPointEx(const APoint: TVector4f;
  711. ADeltaTime: Double): Boolean;
  712. var
  713. lAbsolutePosition: TVector4f;
  714. lCurrentDistance: Single;
  715. lDistanceDifference, lTempCurrentDistance: Single;
  716. procedure DoAdjustDistanceToPoint(const DistanceValue: Single);
  717. var
  718. vect: TVector4f;
  719. begin
  720. vect := VectorSubtract(APoint, lAbsolutePosition);
  721. NormalizeVector(vect);
  722. ScaleVector(vect, DistanceValue);
  723. MovingObject.AbsolutePosition := VectorAdd(lAbsolutePosition, vect);
  724. Result := True;
  725. end;
  726. begin
  727. lAbsolutePosition := MovingObject.AbsolutePosition;
  728. lCurrentDistance := VectorDistance(lAbsolutePosition, APoint);
  729. lDistanceDifference := lCurrentDistance - FAdjustDistanceParamsEx.FTargetDistance;
  730. with FAdjustDistanceParamsEx do
  731. begin
  732. lTempCurrentDistance := 0;
  733. while ADeltaTime > FMaxExpectedDeltaTime do
  734. begin
  735. lTempCurrentDistance := (FSpeed * FMaxExpectedDeltaTime * lDistanceDifference * FInertia) / (FInertia + 1);
  736. // lTempCurrentDistance := (FSpeed * FMaxExpectedDeltaTime + lDistanceDifference * FInertia) / (FInertia + 1);- this also works, but a bit different.
  737. ADeltaTime := ADeltaTime - FMaxExpectedDeltaTime;
  738. end;
  739. lTempCurrentDistance := ClampValue(lTempCurrentDistance, -FSpeedLimit * ADeltaTime, FSpeedLimit * ADeltaTime);
  740. if Abs(lTempCurrentDistance) > FCutoff then
  741. DoAdjustDistanceToPoint(lTempCurrentDistance)
  742. else
  743. Result := False;
  744. end;
  745. end;
  746. function TgxSmoothNavigator.AdjustDistanceToTargetEx(
  747. const ADeltaTime: Double): Boolean;
  748. begin
  749. Assert(FMoveAroundParams.FTargetObject <> nil);
  750. Result := AdjustDistanceToPointEx(FMoveAroundParams.FTargetObject.AbsolutePosition,
  751. ADeltaTime);
  752. end;
  753. procedure TgxSmoothNavigator.SetAdjustDistanceParamsEx(
  754. const Value: TgxNavigatorAdjustDistanceParametersEx);
  755. begin
  756. FAdjustDistanceParamsEx.Assign(Value);
  757. end;
  758. procedure TgxSmoothNavigator.AnimateCustomItems(const ADeltaTime: Double);
  759. begin
  760. FCustomAnimatedItems.DoProceed(ADeltaTime);
  761. end;
  762. procedure TgxSmoothNavigator.SetCustomAnimatedItems(
  763. const Value: TgxNavigatorSmoothChangeItems);
  764. begin
  765. FCustomAnimatedItems.Assign(Value);
  766. end;
  767. { TgxSmoothUserInterface }
  768. function TgxSmoothUserInterface.MouseLook(
  769. const ADeltaTime: Double): Boolean;
  770. var
  771. MousePos: TPoint;
  772. begin
  773. Assert(FAutoUpdateMouse, 'AutoUpdateMouse must be True to use this function');
  774. if FMouseLookActive then
  775. begin
  776. GLGetCursorPos(MousePos);
  777. Result := Mouselook(MousePos.X, MousePos.Y, ADeltaTime);
  778. GLSetCursorPos(Round(OriginalMousePos.X), Round(OriginalMousePos.Y));
  779. end
  780. else
  781. Result := False;
  782. end;
  783. function TgxSmoothUserInterface.Mouselook(const NewX, NewY: Integer; const ADeltaTime: Double): Boolean;
  784. var
  785. DeltaX, DeltaY: Single;
  786. begin
  787. Result := False;
  788. if FMouseLookActive then
  789. begin
  790. Deltax := (NewX - FOriginalMousePos.X);
  791. Deltay := (FOriginalMousePos.Y - NewY);
  792. if InvertMouse then
  793. DeltaY := -DeltaY;
  794. SmoothNavigator.TurnHorizontal(DeltaX, ADeltaTime);
  795. SmoothNavigator.TurnVertical(DeltaY, ADeltaTime);
  796. Result := (DeltaX <> 0) or (DeltaY <> 0);
  797. end;
  798. end;
  799. function TgxSmoothUserInterface.MouseLook(const NewXY: TPoint; const ADeltaTime: Double): Boolean;
  800. begin
  801. Result := Mouselook(NewXY.X, NewXY.Y, ADeltaTime);
  802. end;
  803. constructor TgxSmoothUserInterface.Create(AOwner: TComponent);
  804. begin
  805. inherited;
  806. FMouseLookActive := False;
  807. FAutoUpdateMouse := True;
  808. FOriginalMousePos := TgxCoordinates2.CreateInitialized(Self,
  809. VectorMake(GLGetScreenWidth div 2,
  810. GLGetScreenHeight div 2, 0, 0), csPoint2D);
  811. end;
  812. procedure TgxSmoothUserInterface.Notification(AComponent: TComponent;
  813. Operation: TOperation);
  814. begin
  815. inherited;
  816. if (Operation = opRemove) then
  817. begin
  818. if AComponent = FSmoothNavigator then
  819. FSmoothNavigator := nil;
  820. if AComponent = FSmoothVertNavigator then
  821. FSmoothNavigator := nil;
  822. end;
  823. end;
  824. procedure TgxSmoothUserInterface.SetSmoothNavigator(
  825. const Value: TgxSmoothNavigator);
  826. begin
  827. if FSmoothNavigator <> nil then
  828. FSmoothNavigator.RemoveFreeNotification(Self);
  829. FSmoothNavigator := Value;
  830. if FSmoothNavigator <> nil then
  831. FSmoothNavigator.FreeNotification(Self);
  832. end;
  833. destructor TgxSmoothUserInterface.Destroy;
  834. begin
  835. FOriginalMousePos.Destroy;
  836. inherited;
  837. end;
  838. procedure TgxSmoothUserInterface.SetOriginalMousePos(
  839. const Value: TgxCoordinates2);
  840. begin
  841. FOriginalMousePos.Assign(Value);
  842. end;
  843. procedure TgxSmoothUserInterface.SetSmoothVertNavigator(
  844. const Value: TgxSmoothNavigator);
  845. begin
  846. if FSmoothVertNavigator <> nil then
  847. FSmoothVertNavigator.RemoveFreeNotification(Self);
  848. FSmoothVertNavigator := Value;
  849. if FSmoothVertNavigator <> nil then
  850. FSmoothVertNavigator.FreeNotification(Self);
  851. end;
  852. procedure TgxSmoothUserInterface.MouseLookActiveToggle;
  853. begin
  854. if FMouseLookActive then
  855. SetMouseLookActive(False)
  856. else
  857. SetMouseLookActive(True)
  858. end;
  859. procedure TgxSmoothUserInterface.SetMouseLookActive(const Value: Boolean);
  860. var
  861. MousePos: TPoint;
  862. begin
  863. if FMouseLookActive = Value then Exit;
  864. FMouseLookActive := Value;
  865. if FMouseLookActive then
  866. begin
  867. if FAutoUpdateMouse then
  868. begin
  869. GLGetCursorPos(MousePos);
  870. FOriginalMousePos.SetPoint2D(MousePos.X, MousePos.Y);
  871. GLShowCursor(False);
  872. end;
  873. end
  874. else
  875. begin
  876. if FAutoUpdateMouse then
  877. GLShowCursor(True);
  878. end;
  879. end;
  880. procedure TgxSmoothUserInterface.TurnHorizontal(const Angle: Single;
  881. const ADeltaTime: Double);
  882. begin
  883. FSmoothNavigator.TurnHorizontal(Angle, ADeltaTime);
  884. end;
  885. procedure TgxSmoothUserInterface.TurnVertical(const Angle: Single;
  886. const ADeltaTime: Double);
  887. begin
  888. if Assigned(FSmoothNavigator) then
  889. FSmoothNavigator.TurnVertical(Angle, ADeltaTime)
  890. else
  891. FSmoothVertNavigator.TurnVertical(Angle, ADeltaTime);
  892. end;
  893. { TgxNavigatorInertiaParameters }
  894. procedure TgxNavigatorInertiaParameters.Assign(Source: TPersistent);
  895. begin
  896. if Source is TgxNavigatorInertiaParameters then
  897. begin
  898. FMovementAcceleration := TgxNavigatorInertiaParameters(Source).FMovementAcceleration;
  899. FMovementInertia := TgxNavigatorInertiaParameters(Source).FMovementInertia;
  900. FMovementSpeed := TgxNavigatorInertiaParameters(Source).FMovementSpeed;
  901. FTurnMaxAngle := TgxNavigatorInertiaParameters(Source).FTurnMaxAngle;
  902. FTurnInertia := TgxNavigatorInertiaParameters(Source).FTurnInertia;
  903. FTurnSpeed := TgxNavigatorInertiaParameters(Source).FTurnSpeed;
  904. end
  905. else
  906. inherited; //to the pit of doom ;)
  907. end;
  908. constructor TgxNavigatorInertiaParameters.Create(AOwner: TPersistent);
  909. begin
  910. FOwner := AOwner;
  911. FTurnInertia := 150;
  912. FTurnSpeed := 50;
  913. FTurnMaxAngle := 0.5;
  914. FMovementAcceleration := 7;
  915. FMovementInertia := 200;
  916. FMovementSpeed := 200;
  917. end;
  918. function TgxNavigatorInertiaParameters.GetOwner: TPersistent;
  919. begin
  920. Result := FOwner;
  921. end;
  922. procedure TgxNavigatorInertiaParameters.ScaleParameters(
  923. const Value: Single);
  924. begin
  925. Assert(Value > 0);
  926. if Value > 1 then
  927. begin
  928. FMovementInertia := FMovementInertia * PowerSingle(2, 1 / Value);
  929. FTurnInertia := FTurnInertia * PowerSingle(2, 1 / Value);
  930. end
  931. else
  932. begin
  933. FMovementInertia := FMovementInertia / PowerSingle(2, Value);
  934. FTurnInertia := FTurnInertia / PowerSingle(2, Value);
  935. end;
  936. FTurnMaxAngle := FTurnMaxAngle / Value;
  937. FTurnSpeed := FTurnSpeed * Value;
  938. end;
  939. function TgxNavigatorInertiaParameters.StoreTurnMaxAngle: Boolean;
  940. begin
  941. Result := Abs(FTurnMaxAngle - 0.5) > EPS;
  942. end;
  943. function TgxNavigatorInertiaParameters.StoreMovementAcceleration: Boolean;
  944. begin
  945. Result := Abs(FMovementAcceleration - 7) > EPS;
  946. end;
  947. function TgxNavigatorInertiaParameters.StoreMovementInertia: Boolean;
  948. begin
  949. Result := Abs(FMovementInertia - 200) > EPS;
  950. end;
  951. function TgxNavigatorInertiaParameters.StoreMovementSpeed: Boolean;
  952. begin
  953. Result := Abs(FMovementSpeed - 200) > EPS;
  954. end;
  955. function TgxNavigatorInertiaParameters.StoreTurnInertia: Boolean;
  956. begin
  957. Result := Abs(FTurnInertia - 150) > EPS;
  958. end;
  959. function TgxNavigatorInertiaParameters.StoreTurnSpeed: Boolean;
  960. begin
  961. Result := Abs(FTurnSpeed - 50) > EPS;
  962. end;
  963. { TgxNavigatorGeneralParameters }
  964. procedure TgxNavigatorGeneralParameters.Assign(Source: TPersistent);
  965. begin
  966. if Source is TgxNavigatorGeneralParameters then
  967. begin
  968. FAutoScaleMin := TgxNavigatorGeneralParameters(Source).FAutoScaleMin;
  969. FAutoScaleMax := TgxNavigatorGeneralParameters(Source).FAutoScaleMax;
  970. FAutoScaleMult := TgxNavigatorGeneralParameters(Source).FAutoScaleMult;
  971. end
  972. else
  973. inherited; //die!
  974. end;
  975. constructor TgxNavigatorGeneralParameters.Create(AOwner: TPersistent);
  976. begin
  977. FOwner := AOwner;
  978. FAutoScaleMin := 0.1;
  979. FAutoScaleMax := 0.75;
  980. FAutoScaleMult := 2;
  981. end;
  982. function TgxNavigatorGeneralParameters.GetOwner: TPersistent;
  983. begin
  984. Result := FOwner;
  985. end;
  986. function TgxNavigatorGeneralParameters.StoreAutoScaleMax: Boolean;
  987. begin
  988. Result := Abs(FAutoScaleMax - 0.75) > EPS;
  989. end;
  990. function TgxNavigatorGeneralParameters.StoreAutoScaleMin: Boolean;
  991. begin
  992. Result := Abs(FAutoScaleMin - 0.1) > EPS;
  993. end;
  994. function TgxNavigatorGeneralParameters.StoreAutoScaleMult: Boolean;
  995. begin
  996. Result := Abs(FAutoScaleMult - 2) > EPS;
  997. end;
  998. { TgxNavigatorMoveAroundParameters }
  999. procedure TgxNavigatorMoveAroundParameters.Assign(Source: TPersistent);
  1000. begin
  1001. if Source is TgxNavigatorMoveAroundParameters then
  1002. begin
  1003. FMaxAngle := TgxNavigatorMoveAroundParameters(Source).FMaxAngle;
  1004. FInertia := TgxNavigatorMoveAroundParameters(Source).FInertia;
  1005. FPitchSpeed := TgxNavigatorMoveAroundParameters(Source).FPitchSpeed;
  1006. FTurnSpeed := TgxNavigatorMoveAroundParameters(Source).FTurnSpeed;
  1007. FCutoff := TgxNavigatorMoveAroundParameters(Source).FCutoff;
  1008. SetTargetObject(TgxNavigatorMoveAroundParameters(Source).FTargetObject);
  1009. end
  1010. else
  1011. inherited; //die
  1012. end;
  1013. constructor TgxNavigatorMoveAroundParameters.Create(AOwner: TPersistent);
  1014. begin
  1015. FOwner := AOwner;
  1016. FPitchSpeed := 500;
  1017. FTurnSpeed := 500;
  1018. FInertia := 65;
  1019. FMaxAngle := 1.5;
  1020. FCutoff := EPS2;
  1021. end;
  1022. function TgxNavigatorMoveAroundParameters.GetOwner: TPersistent;
  1023. begin
  1024. Result := FOwner;
  1025. end;
  1026. procedure TgxNavigatorMoveAroundParameters.ScaleParameters(
  1027. const Value: Single);
  1028. begin
  1029. Assert(Value > 0);
  1030. if Value < 1 then
  1031. FInertia := FInertia / PowerSingle(2, Value)
  1032. else
  1033. FInertia := FInertia * PowerSingle(2, 1 / Value);
  1034. FMaxAngle := FMaxAngle / Value;
  1035. FPitchSpeed := FPitchSpeed * Value;
  1036. FTurnSpeed := FTurnSpeed * Value;
  1037. end;
  1038. procedure TgxNavigatorMoveAroundParameters.SetTargetObject(
  1039. const Value: TgxBaseSceneObject);
  1040. begin
  1041. if FTargetObject <> nil then
  1042. if FOwner is TgxSmoothNavigator then
  1043. FTargetObject.RemoveFreeNotification(TgxSmoothNavigator(FOwner));
  1044. FTargetObject := Value;
  1045. if FTargetObject <> nil then
  1046. if FOwner is TgxSmoothNavigator then
  1047. FTargetObject.FreeNotification(TgxSmoothNavigator(FOwner));
  1048. end;
  1049. function TgxNavigatorMoveAroundParameters.StoreCutoff: Boolean;
  1050. begin
  1051. Result := Abs(FCutoff - EPS2) > EPS8;
  1052. end;
  1053. function TgxNavigatorMoveAroundParameters.StoreInertia: Boolean;
  1054. begin
  1055. Result := Abs(FInertia - 65) > EPS;
  1056. end;
  1057. function TgxNavigatorMoveAroundParameters.StoreMaxAngle: Boolean;
  1058. begin
  1059. Result := Abs(FMaxAngle - 1.5) > EPS;
  1060. end;
  1061. function TgxNavigatorMoveAroundParameters.StorePitchSpeed: Boolean;
  1062. begin
  1063. Result := Abs(FPitchSpeed - 500) > EPS;
  1064. end;
  1065. function TgxNavigatorMoveAroundParameters.StoreTurnSpeed: Boolean;
  1066. begin
  1067. Result := Abs(FTurnSpeed - 500) > EPS;
  1068. end;
  1069. { TgxNavigatorAdjustDistanceParameters }
  1070. procedure TgxNavigatorAdjustDistanceParameters.AddImpulse(
  1071. const Impulse: Single);
  1072. begin
  1073. FOldDistanceRatio := FOldDistanceRatio + Impulse * FSpeed / FInertia * FImpulseSpeed;
  1074. end;
  1075. procedure TgxNavigatorAdjustDistanceParameters.Assign(Source: TPersistent);
  1076. begin
  1077. inherited Assign(Source);
  1078. if Source is TgxNavigatorAdjustDistanceParameters then
  1079. begin
  1080. FImpulseSpeed := TgxNavigatorAdjustDistanceParameters(Source).FImpulseSpeed;
  1081. end;
  1082. end;
  1083. constructor TgxNavigatorAdjustDistanceParameters.Create(
  1084. AOwner: TPersistent);
  1085. begin
  1086. inherited;
  1087. FImpulseSpeed := 0.02;
  1088. end;
  1089. procedure TgxNavigatorAdjustDistanceParameters.ScaleParameters(
  1090. const Value: Single);
  1091. begin
  1092. inherited;
  1093. FImpulseSpeed := FImpulseSpeed / Value;
  1094. end;
  1095. function TgxNavigatorAdjustDistanceParameters.StoreImpulseSpeed: Boolean;
  1096. begin
  1097. Result := Abs(FImpulseSpeed - 0.02) > EPS;
  1098. end;
  1099. { TgxNavigatorAbstractParameters }
  1100. procedure TgxNavigatorAbstractParameters.Assign(Source: TPersistent);
  1101. begin
  1102. if Source is TgxNavigatorAbstractParameters then
  1103. begin
  1104. FInertia := TgxNavigatorAbstractParameters(Source).FInertia;
  1105. FSpeed := TgxNavigatorAbstractParameters(Source).FSpeed;
  1106. FCutoff := TgxNavigatorAbstractParameters(Source).FCutoff;
  1107. end
  1108. else
  1109. inherited; //to the pit of doom ;)
  1110. end;
  1111. constructor TgxNavigatorAbstractParameters.Create(
  1112. AOwner: TPersistent);
  1113. begin
  1114. FOwner := AOwner;
  1115. FInertia := 100;
  1116. FSpeed := 0.005;
  1117. FCutoff := EPS;
  1118. end;
  1119. function TgxNavigatorAbstractParameters.GetOwner: TPersistent;
  1120. begin
  1121. Result := FOwner;
  1122. end;
  1123. procedure TgxNavigatorAbstractParameters.ScaleParameters(
  1124. const Value: Single);
  1125. begin
  1126. Assert(Value > 0);
  1127. if Value < 1 then
  1128. FInertia := FInertia / PowerSingle(2, Value)
  1129. else
  1130. FInertia := FInertia * PowerSingle(2, 1 / Value);
  1131. end;
  1132. function TgxNavigatorAbstractParameters.StoreCutoff: Boolean;
  1133. begin
  1134. Result := Abs(FCutoff - EPS) > EPS2;
  1135. end;
  1136. function TgxNavigatorAbstractParameters.StoreInertia: Boolean;
  1137. begin
  1138. Result := Abs(FInertia - 100) > EPS;
  1139. end;
  1140. function TgxNavigatorAbstractParameters.StoreSpeed: Boolean;
  1141. begin
  1142. Result := Abs(FSpeed - 0.005) > EPS2;
  1143. end;
  1144. { TgxNavigatorAdjustDistanceParametersEx }
  1145. procedure TgxNavigatorAdjustDistanceParametersEx.Assign(
  1146. Source: TPersistent);
  1147. begin
  1148. if Source is TgxNavigatorAdjustDistanceParametersEx then
  1149. begin
  1150. FTargetDistance := TgxNavigatorAdjustDistanceParametersEx(Source).FTargetDistance;
  1151. FSpeedLimit := TgxNavigatorAdjustDistanceParametersEx(Source).FSpeedLimit;
  1152. end
  1153. else
  1154. inherited;
  1155. end;
  1156. constructor TgxNavigatorAdjustDistanceParametersEx.Create(
  1157. AOwner: TPersistent);
  1158. begin
  1159. inherited;
  1160. FInertia := 0.5;
  1161. FTargetDistance := 100;
  1162. FSpeed := 100;
  1163. FSpeedLimit := 20000;
  1164. end;
  1165. function TgxNavigatorAdjustDistanceParametersEx.StoreInertia: Boolean;
  1166. begin
  1167. Result := Abs(FInertia - 0.5) > EPS2;
  1168. end;
  1169. function TgxNavigatorAdjustDistanceParametersEx.StoreSpeed: Boolean;
  1170. begin
  1171. Result := Abs(FSpeed - 100) > EPS2;
  1172. end;
  1173. function TgxNavigatorAdjustDistanceParametersEx.StoreSpeedLimit: Boolean;
  1174. begin
  1175. Result := Abs(FSpeedLimit - 20000) > EPS2;
  1176. end;
  1177. function TgxNavigatorAdjustDistanceParametersEx.StoreTargetDistance: Boolean;
  1178. begin
  1179. Result := Abs(FTargetDistance - 100) > EPS2;
  1180. end;
  1181. { TgxNavigatorSmoothChangeItem }
  1182. procedure TgxNavigatorSmoothChangeItem.Assign(Source: TPersistent);
  1183. begin
  1184. inherited Assign(Source);
  1185. if Source is TgxNavigatorSmoothChangeItem then
  1186. begin
  1187. FInertia := TgxNavigatorSmoothChangeItem(Source).FInertia;
  1188. FSpeed := TgxNavigatorSmoothChangeItem(Source).FSpeed;
  1189. FSpeedLimit := TgxNavigatorSmoothChangeItem(Source).FSpeedLimit;
  1190. FCutoff := TgxNavigatorSmoothChangeItem(Source).FCutoff;
  1191. FEnabled := TgxNavigatorSmoothChangeItem(Source).FEnabled;
  1192. end;
  1193. end;
  1194. constructor TgxNavigatorSmoothChangeItem.Create(aOwner: TXCollection);
  1195. begin
  1196. inherited;
  1197. FInertia := 1;
  1198. FSpeed := 5.5;
  1199. FSpeedLimit := 20000;
  1200. FCutoff := EPS;
  1201. FEnabled := True;
  1202. end;
  1203. function TgxNavigatorSmoothChangeItem.GetNavigator: TgxSmoothNavigator;
  1204. begin
  1205. Result := TgxSmoothNavigator(TgxNavigatorSmoothChangeItems(GetOwner).Owner);
  1206. end;
  1207. procedure TgxNavigatorSmoothChangeItem.ScaleParameters(
  1208. const Value: Single);
  1209. begin
  1210. Assert(Value > 0);
  1211. if Value < 1 then
  1212. FInertia := FInertia / PowerSingle(2, Value)
  1213. else
  1214. FInertia := FInertia * PowerSingle(2, 1 / Value);
  1215. end;
  1216. function TgxNavigatorSmoothChangeItem.StoreCutoff: Boolean;
  1217. begin
  1218. Result := Abs(FCutoff - EPS) > EPS8;
  1219. end;
  1220. function TgxNavigatorSmoothChangeItem.StoreInertia: Boolean;
  1221. begin
  1222. Result := Abs(FInertia - 1) > EPS;
  1223. end;
  1224. function TgxNavigatorSmoothChangeItem.StoreSpeed: Boolean;
  1225. begin
  1226. Result := Abs(FSpeed - 5.5) > EPS2;
  1227. end;
  1228. function TgxNavigatorSmoothChangeItem.StoreSpeedLimit: Boolean;
  1229. begin
  1230. Result := Abs(FSpeedLimit - 20000) > EPS2;
  1231. end;
  1232. { TgxNavigatorSmoothChangeItems }
  1233. function TgxNavigatorSmoothChangeItems.Add(AClass : TgxNavigatorSmoothChangeItemClass): TgxNavigatorSmoothChangeItem;
  1234. begin
  1235. Result := AClass.Create(Self);
  1236. end;
  1237. function TgxNavigatorSmoothChangeItems.CanAdd(AClass: TXCollectionItemClass): Boolean;
  1238. begin
  1239. Result := AClass.InheritsFrom(TgxNavigatorSmoothChangeItem);
  1240. end;
  1241. procedure TgxNavigatorSmoothChangeItems.DoProceed(ADeltaTime: Double);
  1242. var
  1243. I: Integer;
  1244. begin
  1245. for I := 0 to Count - 1 do
  1246. GetItems(I).Proceed(ADeltaTime);
  1247. end;
  1248. function TgxNavigatorSmoothChangeItems.GetItems(const Index : Integer): TgxNavigatorSmoothChangeItem;
  1249. begin
  1250. Result := TgxNavigatorSmoothChangeItem(inherited GetItems(Index));
  1251. end;
  1252. class function TgxNavigatorSmoothChangeItems.ItemsClass: TXCollectionItemClass;
  1253. begin
  1254. Result := TgxNavigatorSmoothChangeItem;
  1255. end;
  1256. procedure TgxNavigatorSmoothChangeItems.SetItems(const Index : Integer; const Value:
  1257. TgxNavigatorSmoothChangeItem);
  1258. begin
  1259. GetItems(Index).Assign(Value);
  1260. end;
  1261. { TgxNavigatorSmoothChangeSingle }
  1262. procedure TgxNavigatorSmoothChangeSingle.Assign(Source: TPersistent);
  1263. begin
  1264. inherited Assign(Source);
  1265. if Source is TgxNavigatorSmoothChangeVector then
  1266. begin
  1267. FTargetValue := TgxNavigatorSmoothChangeSingle(Source).TargetValue;
  1268. FOnGetCurrentValue := TgxNavigatorSmoothChangeSingle(Source).FOnGetCurrentValue;
  1269. FOnSetCurrentValue := TgxNavigatorSmoothChangeSingle(Source).FOnSetCurrentValue;
  1270. end;
  1271. end;
  1272. class function TgxNavigatorSmoothChangeSingle.FriendlyName: string;
  1273. begin
  1274. Result := 'Navigator SmoothChange Single';
  1275. end;
  1276. function TgxNavigatorSmoothChangeSingle.Proceed(ADeltaTime: Double): Boolean;
  1277. var
  1278. lCurrentValue: Single;
  1279. lCurrentDifference: Single;
  1280. lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
  1281. lMaxExpectedDeltaTime: Double;
  1282. begin
  1283. Result := False;
  1284. if not FEnabled then Exit;
  1285. if not Assigned(FOnGetCurrentValue) then Exit;
  1286. if not Assigned(FOnSetCurrentValue) then Exit;
  1287. lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
  1288. lCurrentValue := FOnGetCurrentValue(Self);
  1289. lCurrentDifference := FTargetValue - lCurrentValue;
  1290. lTotalDistanceToTravelThisTime := 0;
  1291. while ADeltaTime > lMaxExpectedDeltaTime do
  1292. begin
  1293. lDistanceToTravelThisTime := MinFloat((lCurrentDifference * ADeltaTime * FSpeed * FInertia) / (FInertia + 1), FSpeedLimit);
  1294. // lDistanceToTravelThisTime := (lCurrentDistance * ADeltaTime + FSpeed * FInertia) / (FInertia + 1);- this also works, but a bit different.
  1295. lCurrentDifference := lCurrentDifference - lDistanceToTravelThisTime;
  1296. lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
  1297. ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
  1298. end;
  1299. if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
  1300. begin
  1301. FOnSetCurrentValue(Self, lCurrentValue + lTotalDistanceToTravelThisTime);
  1302. Result := True;
  1303. end;
  1304. end;
  1305. procedure TgxNavigatorSmoothChangeSingle.ResetTargetValue;
  1306. begin
  1307. FTargetValue := FOnGetCurrentValue(Self);
  1308. end;
  1309. { TgxNavigatorSmoothChangeVector }
  1310. procedure TgxNavigatorSmoothChangeVector.Assign(Source: TPersistent);
  1311. begin
  1312. inherited Assign(Source);
  1313. if Source is TgxNavigatorSmoothChangeVector then
  1314. begin
  1315. FTargetValue.Assign(TgxNavigatorSmoothChangeVector(Source).TargetValue);
  1316. FOnGetCurrentValue := TgxNavigatorSmoothChangeVector(Source).FOnGetCurrentValue;
  1317. FOnSetCurrentValue := TgxNavigatorSmoothChangeVector(Source).FOnSetCurrentValue;
  1318. end;
  1319. end;
  1320. constructor TgxNavigatorSmoothChangeVector.Create(aOwner: TXCollection);
  1321. begin
  1322. inherited;
  1323. FTargetValue := TgxCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
  1324. end;
  1325. destructor TgxNavigatorSmoothChangeVector.Destroy;
  1326. begin
  1327. FTargetValue.Free;
  1328. inherited;
  1329. end;
  1330. class function TgxNavigatorSmoothChangeVector.FriendlyName: string;
  1331. begin
  1332. Result := 'Navigator SmoothChange Vector';
  1333. end;
  1334. function TgxNavigatorSmoothChangeVector.Proceed(ADeltaTime: Double): Boolean;
  1335. var
  1336. lAbsolutePosition: TVector4f;
  1337. lCurrentDistance: Single;
  1338. lTotalDistanceToTravelThisTime, lDistanceToTravelThisTime: Single;
  1339. lMaxExpectedDeltaTime: Double;
  1340. procedure DoAdjustDistanceToPoint();
  1341. var
  1342. vect: TVector4f;
  1343. begin
  1344. vect := VectorScale(VectorNormalize(VectorSubtract(FTargetValue.DirectVector, lAbsolutePosition)), lTotalDistanceToTravelThisTime);
  1345. AddVector(vect, lAbsolutePosition);
  1346. // Did we go too far?
  1347. if VectorDistance(vect, FTargetValue.DirectVector) > VectorDistance(lAbsolutePosition, FTargetValue.DirectVector) then
  1348. vect := FTargetValue.DirectVector;
  1349. FOnSetCurrentValue(Self, vect);
  1350. Result := True;
  1351. end;
  1352. begin
  1353. Result := False;
  1354. if not FEnabled then Exit;
  1355. if not Assigned(FOnGetCurrentValue) then Exit;
  1356. if not Assigned(FOnSetCurrentValue) then Exit;
  1357. lMaxExpectedDeltaTime := GetNavigator.FMaxExpectedDeltaTime;
  1358. lAbsolutePosition := FOnGetCurrentValue(Self);
  1359. lCurrentDistance := VectorDistance(lAbsolutePosition, FTargetValue.DirectVector);
  1360. lTotalDistanceToTravelThisTime := 0;
  1361. while ADeltaTime > lMaxExpectedDeltaTime do
  1362. begin
  1363. lDistanceToTravelThisTime := MinFloat((lCurrentDistance * ADeltaTime * FSpeed * FInertia) / (FInertia + 1), FSpeedLimit);
  1364. // lDistanceToTravelThisTime := (lCurrentDistance * ADeltaTime + FSpeed * FInertia) / (FInertia + 1);- this also works, but a bit different.
  1365. lCurrentDistance := lCurrentDistance - lDistanceToTravelThisTime;
  1366. lTotalDistanceToTravelThisTime := lTotalDistanceToTravelThisTime + lDistanceToTravelThisTime;
  1367. ADeltaTime := ADeltaTime - lMaxExpectedDeltaTime;
  1368. end;
  1369. if Abs(lTotalDistanceToTravelThisTime) > FCutoff then
  1370. DoAdjustDistanceToPoint();
  1371. end;
  1372. procedure TgxNavigatorSmoothChangeVector.ResetTargetValue;
  1373. begin
  1374. FTargetValue.DirectVector := FOnGetCurrentValue(Self);
  1375. end;
  1376. procedure TgxNavigatorSmoothChangeVector.SetTargetValue(
  1377. const Value: TgxCoordinates);
  1378. begin
  1379. FTargetValue.Assign(Value);
  1380. end;
  1381. initialization
  1382. RegisterClasses([
  1383. TgxSmoothNavigator, TgxSmoothUserInterface,
  1384. TgxNavigatorInertiaParameters, TgxNavigatorGeneralParameters,
  1385. TgxNavigatorMoveAroundParameters,
  1386. TgxNavigatorAdjustDistanceParameters, TgxNavigatorAdjustDistanceParametersEx
  1387. ]);
  1388. RegisterXCollectionItemClass(TgxNavigatorSmoothChangeSingle);
  1389. RegisterXCollectionItemClass(TgxNavigatorSmoothChangeVector);
  1390. end.