2
0

GLS.SmoothNavigator.pas 53 KB

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