GXS.CameraController.pas 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.CameraController;
  5. (*
  6. Component for animating camera movement.
  7. Can be used to zoom in/out, for linear movement, orbiting and Google Earth - like "fly-to"
  8. Main purpose was the SafeOrbitAndZoomToPos method, the others are usable as well
  9. IMPORTANT!
  10. You should block user GUI access to the GLSceneViewer
  11. while movement is being done, check the AllowUserAction property!
  12. Block user GUI access while AllowUserAction is false to avoid behaviour errors
  13. simply put
  14. if GLCameraController1.AllowUserAction then
  15. do whatever you want on mouse move, form wheel etc
  16. methods and properties are explained in the interface section (through comments)
  17. additional comments might apear in implementation section where needed
  18. *)
  19. interface
  20. uses
  21. System.Classes,
  22. System.SysUtils,
  23. System.Math,
  24. System.Contnrs,
  25. GXS.PersistentClasses,
  26. GXS.Scene,
  27. Stage.VectorGeometry,
  28. GXS.Coordinates,
  29. GXS.SmoothNavigator,
  30. Stage.VectorTypes;
  31. type
  32. EGLCameraController = class(Exception);
  33. // Forward declaration of the camera controller main class
  34. TgxCameraController = class;
  35. // Forward declaration of a generic camera job
  36. TgxCameraJob = class;
  37. TgxCameraJobList = class(TObjectList)
  38. private
  39. FController : TgxCameraController;
  40. function GetCameraJob(const AIndex: integer): TgxCameraJob;
  41. procedure SetCameraJob(const AIndex: integer; const Value: TgxCameraJob);
  42. public
  43. constructor Create(AController: TgxCameraController);
  44. function Add(ACameraJob: TgxCameraJob): integer;
  45. property Items[const AIndex: integer]: TgxCameraJob read GetCameraJob write SetCameraJob; default;
  46. function First: TgxCameraJob;
  47. function Last: TgxCameraJob;
  48. end;
  49. TgxCameraJob = class(TObject)
  50. private
  51. FJoblist : TgxCameraJobList;
  52. protected
  53. FAbort : boolean;
  54. FInit : boolean;
  55. FRunning : Boolean;
  56. FElapsedTime : Double;
  57. FDeltaTime : Double;
  58. FStartTime : Double;
  59. FProceedTime : Double;
  60. public
  61. constructor Create(const AJoblist : TgxCameraJobList); virtual;
  62. destructor Destroy; override;
  63. procedure Abort;
  64. procedure Step; virtual; abstract;
  65. procedure Init; virtual; abstract;
  66. property Running: Boolean read FRunning write FRunning;
  67. property ElapsedTime: Double read FElapsedTime write FElapsedTime;
  68. property StartTime: Double read FStartTime write FStartTime;
  69. property ProceedTime: Double read FProceedTime write FProceedTime;
  70. end;
  71. TgxMoveToPosJob = class(TgxCameraJob)
  72. private
  73. FInitialPos : TVector4f;
  74. FFinalPos : TVector4f;
  75. public
  76. X : Double;
  77. Y : Double;
  78. Z : Double;
  79. Time : Double;
  80. procedure Step; override;
  81. procedure Init; override;
  82. // Properties.
  83. property InitialPos: TVector4f read FInitialPos;
  84. property FinalPos: TVector4f read FFinalPos;
  85. end;
  86. TgxZoomToDistanceJob = class(TgxCameraJob)
  87. private
  88. FInitialPos : TVector4f;
  89. FFinalPos : TVector4f;
  90. public
  91. Distance : Double;
  92. Time : Double;
  93. procedure Step; override;
  94. procedure Init; override;
  95. // Properties.
  96. property InitialPos: TVector4f read FInitialPos;
  97. property FinalPos: TVector4f read FFinalPos;
  98. end;
  99. TgxOrbitToPosJob = class(TgxCameraJob)
  100. private
  101. FFinalPos: TVector4f; // Yep, FFinalPos is stored in relative coordinates.
  102. FRotateSpeed: TVector2f;
  103. FCameraUpVector: TVector4f;
  104. // Absolute Coordinates, can even be not normalized by radius.
  105. // Procesed in Init, not used anywhere else.
  106. FTargetPosition: TVector4f;
  107. FTime : Double;
  108. public
  109. procedure Step; override;
  110. procedure Init; override;
  111. // Properties.
  112. property RotateSpeed: TVector2f read FRotateSpeed;
  113. property CameraUpVector: TVector4f read FCameraUpVector;
  114. property TargetPosition: TVector4f read FTargetPosition;
  115. property FinalPos: TVector4f read FFinalPos;
  116. property Time: Double read FTime;
  117. end;
  118. TgxSmoothOrbitToPos = class(TgxOrbitToPosJob)
  119. private
  120. FCutoffAngle: Single;
  121. FNeedToRecalculateZoom: Boolean;
  122. FShouldBeMatrix: TMatrix4f;
  123. FSmoothNavigator: TgxNavigatorSmoothChangeVector;
  124. public
  125. constructor Create(const AJoblist : TgxCameraJobList); override;
  126. procedure Step; override;
  127. property CutoffAngle: Single read FCutoffAngle write FCutoffAngle;
  128. property NeedToRecalculateZoom: Boolean read FNeedToRecalculateZoom write FNeedToRecalculateZoom;
  129. end;
  130. TgxOrbitToPosAdvJob = class(TgxCameraJob)
  131. private
  132. FInitialPos : TVector4f;
  133. FFinalPos : TVector4f;
  134. FInitialUp : TVector4f;
  135. FInitialDir : TVector4f;
  136. FRotAxis : TVector4f;
  137. FAngle : Double;
  138. public
  139. X : Double;
  140. Y : Double;
  141. Z : Double;
  142. Time : Double;
  143. PreferUpAxis : Boolean;
  144. procedure Step; override;
  145. procedure Init; override;
  146. // Properties.
  147. property InitialPos: TVector4f read FInitialPos;
  148. property InitialUp: TVector4f read FInitialUp;
  149. property InitialDir: TVector4f read FInitialDir;
  150. property FinalPos: TVector4f read FFinalPos;
  151. end;
  152. TgxSmoothOrbitToPosAdvJob = class(TgxOrbitToPosAdvJob)
  153. private
  154. FPreviousPosition: TVector4f;
  155. FSmoothNavigator: TgxNavigatorSmoothChangeVector;
  156. FRestoreUpVector: Boolean;
  157. public
  158. procedure Step; override;
  159. procedure Init; override;
  160. end;
  161. TgxCameraJobEvent = procedure(Sender : TgxCameraJob) of object;
  162. TgxCameraController = class(TComponent)
  163. private
  164. // Objects.
  165. FCameraJobList : TgxCameraJobList;
  166. FCamera: TgxBaseSceneObject;
  167. FCameraTarget: TgxBaseSceneObject;
  168. // Events.
  169. FOnJobAdded: TgxCameraJobEvent;
  170. FOnJobFinished: TgxCameraJobEvent;
  171. FOnJobStep: TgxCameraJobEvent;
  172. //fields used by SafeOrbitAndZoomToPos
  173. FsoSafeDist, FsoTimeToSafePlacement, FsoTimeToOrbit, FsoTimeToZoomBackIn:double;
  174. //private methods
  175. //used to test whether camera and cadencer are assigned
  176. //Extended = true -> will test also for Camera.TargetObject
  177. procedure CheckAssignments(Extended: boolean);
  178. //after AdjustScene the Camera.DepthofView will be modified
  179. //if you want to zoom back in from GUI
  180. //you should use something like
  181. // Camera.DepthOfView:=2*Camera.DistanceToTarget+2*camera.TargetObject.BoundingSphereRadius;
  182. procedure SetOnJobAdded(const Value: TgxCameraJobEvent);
  183. procedure SetOnJobFinished(const Value: TgxCameraJobEvent);
  184. procedure SetOnJobStep(const Value: TgxCameraJobEvent);
  185. procedure SetCamera(const Value: TgxBaseSceneObject);
  186. procedure SetCameraTarget(const Value: TgxBaseSceneObject);
  187. protected
  188. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  189. public
  190. // Constructor.
  191. constructor Create(AOwner:TComponent); override;
  192. destructor Destroy; override;
  193. //methods
  194. //linear movement from current pos
  195. function MoveToPos(x,y,z,time:double): TgxMoveToPosJob;
  196. //orbiting from current pos to the pos where
  197. //the camera points at the camera.targetObject TROUGH the given point
  198. //it will not move to the given point(!), use SafeOrbitAndZoomToPos instead
  199. //there has to be a camera.targetObject assigned!
  200. function OrbitToPos(x,y,z,time:double): TgxOrbitToPosJob;
  201. // Same as OrbitToPos(), but makes use of SmoothNavigator to make
  202. // sure all camera movements are smooth.
  203. function OrbitToPosSmooth(const ATargetPosition: TVector4f; const ATime: Double;
  204. const ASmoothNavigator: TgxNavigatorSmoothChangeVector; const AFNeedToRecalculateZoom: Boolean;
  205. const ACameraUpVector: PVector4f = nil): TgxSmoothOrbitToPos;
  206. //Same function as OrbitToPos but support all camera states
  207. //PreferUpAxis value is to setup if function use Camera Up based rotation axis
  208. //instead of Camera direction based rotation axis when destination and camera
  209. //position are opposite from Camera Target
  210. function OrbitToPosAdvanced(x,y,z,time:double; PreferUpAxis: Boolean = True): TgxOrbitToPosAdvJob;
  211. // Same as OrbitToPosAdvanced(), but makes use of SmoothNavigator to make
  212. // sure all camera movements are smooth.
  213. function OrbitToPosAdvancedSmooth(const x,y,z, time: double;
  214. const ASmoothNavigator: TgxNavigatorSmoothChangeVector;
  215. const PreferUpAxis: Boolean = True): TgxSmoothOrbitToPosAdvJob;
  216. //zooms in/out by moving to the given distance from camera.targetObject
  217. //there has to be a camera.targetObject assigned!
  218. function ZoomToDistance(Distance,Time:double): TgxZoomToDistanceJob;
  219. //google earth - like "fly-to"
  220. // = zoom out to safe distance, orbit, and then zoom in to the given point
  221. //there has to be a camera.targetObject assigned!
  222. procedure SafeOrbitAndZoomToPos(x,y,z:double);
  223. //Dan Bartlett said in the GLScene newsgroup that it might be a good idea
  224. //to introduce ability to stop movement and return control to user
  225. //here it is
  226. procedure StopMovement;
  227. // Called by the cadencer to animate the camera
  228. procedure Step(const deltaTime, newTime: Double);
  229. property CameraJobList: TgxCameraJobList read FCameraJobList;
  230. published
  231. // Assign a Moving object (usually a TgxCamera).
  232. property Camera: TgxBaseSceneObject read FCamera write SetCamera;
  233. // Assign a target, around which Moving object should rotate(usually TgxCamera.TargetObject).
  234. property CameraTarget: TgxBaseSceneObject read FCameraTarget write SetCameraTarget;
  235. //specifies whether user should be able interract with the GLSceneViewer
  236. //it is set to false while the camera is moving and
  237. //coders should check this value and block GUI access to GLSceneViewer
  238. //property AllowUserAction:boolean read FAllowUserAction;
  239. //safe distance to avoid moving the camera trough the camera.targetObject
  240. //while performing SafeOrbitAndZoomToPos
  241. property soSafeDistance:double read FsoSafeDist write FsoSafeDist;
  242. //time to zoom in/out to the safe position while performing SafeOrbitAndZoomToPos
  243. property soTimeToSafePlacement:double read FsoTimeToSafePlacement write FsoTimeToSafePlacement;
  244. //time to orbit while performing SafeOrbitAndZoomToPos
  245. property soTimeToOrbit:double read FsoTimeToOrbit write FsoTimeToOrbit;
  246. //time to zoom in/out to the given final position while performing SafeOrbitAndZoomToPos
  247. property soTimeToZoomBackIn:double read FsoTimeToZoomBackIn write FsoTimeToZoomBackIn;
  248. //this event is triggered when a job is init
  249. property OnJobAdded : TgxCameraJobEvent read FOnJobAdded write SetOnJobAdded;
  250. //this event is triggered when a job is step (like an OnMove)
  251. property OnJobStep : TgxCameraJobEvent read FOnJobStep write SetOnJobStep;
  252. //this event is triggered when a job is finished (not canceled)
  253. property OnJobFinished : TgxCameraJobEvent read FOnJobFinished write SetOnJobFinished;
  254. end;
  255. implementation
  256. const
  257. cGLCAMERACONTROLLER_CHECK_EXTENDED = TRUE;
  258. cEPSILON = 0.001;
  259. { TgxCameraController }
  260. constructor TgxCameraController.Create(AOwner:TComponent);
  261. begin
  262. inherited;
  263. //create the job list container
  264. FCameraJobList := TgxCameraJobList.Create(Self);
  265. FCameraJobList.OwnsObjects := true;
  266. //initialize values
  267. soSafeDistance:=10;
  268. soTimeToSafePlacement:=1;
  269. soTimeToOrbit:=2;
  270. soTimeToZoomBackIn:=1;
  271. end;
  272. destructor TgxCameraController.Destroy;
  273. begin
  274. //delete job list and all jobs inside
  275. FCameraJobList.Free;
  276. inherited;
  277. end;
  278. procedure TgxCameraController.CheckAssignments(Extended:boolean);
  279. begin
  280. /// Check camera assignment
  281. if not Assigned(FCamera) then
  282. begin
  283. Raise EGLCameraController.CreateFmt('%s (%s) needs to have a Camera assigned',[Self.Name, Self.ClassName]);
  284. end;
  285. if Extended then
  286. /// Check camera;TargetObject assignment
  287. if not Assigned(FCameraTarget) then
  288. begin
  289. Raise EGLCameraController.CreateFmt('%s (%s) needs Camera to have a TargetObject assigned',[Self.Name, Self.ClassName]);
  290. end;
  291. end;
  292. procedure TgxCameraController.Step(const deltaTime, newTime: Double);
  293. var
  294. CurrentJob : TgxCameraJob;
  295. begin
  296. if FCameraJobList.Count > 0 then
  297. begin
  298. CurrentJob := FCameraJobList.First;
  299. if CurrentJob.FInit then
  300. begin
  301. CurrentJob.Init;
  302. CurrentJob.FStartTime := newTime;
  303. CurrentJob.FRunning := True;
  304. CurrentJob.FInit := False;
  305. // Notify job
  306. if Assigned(FOnJobAdded) then
  307. FOnJobAdded(CurrentJob);
  308. end;
  309. if CurrentJob.FRunning then
  310. begin
  311. CurrentJob.FElapsedTime := newTime - CurrentJob.FStartTime;
  312. CurrentJob.FDeltaTime := deltaTime;// newTime - CurrentJob.FElapsedTime;
  313. CurrentJob.Step;
  314. // Notify job
  315. if Assigned(FOnJobStep) then
  316. FOnJobStep(CurrentJob);
  317. end;
  318. if not CurrentJob.FRunning then
  319. begin
  320. FCameraJobList.Remove(CurrentJob);
  321. // Notify job
  322. if Assigned(FOnJobFinished) then
  323. FOnJobFinished(CurrentJob);
  324. end;
  325. end;
  326. //AdjustScene;
  327. end;
  328. function TgxCameraController.MoveToPos(x,y,z, time:double): TgxMoveToPosJob;
  329. begin
  330. Result := TgxMoveToPosJob.Create(FCameraJobList);
  331. Result.X := x;
  332. Result.Y := y;
  333. Result.Z := z;
  334. Result.Time := time;
  335. end;
  336. function TgxCameraController.ZoomToDistance(Distance, Time:double): TgxZoomToDistanceJob;
  337. begin
  338. Result := TgxZoomToDistanceJob.Create(FCameraJobList);
  339. Result.Distance := Distance;
  340. Result.Time := Time;
  341. end;
  342. function TgxCameraController.OrbitToPos(x,y,z,time:double): TgxOrbitToPosJob;
  343. begin
  344. Result := TgxOrbitToPosJob.Create(FCameraJobList);
  345. Result.FTargetPosition := PointMake(x, y, z);
  346. Result.FCameraUpVector := FCameraJobList.FController.FCamera.AbsoluteUp;
  347. Result.FTime := time;
  348. end;
  349. function TgxCameraController.OrbitToPosSmooth(const ATargetPosition: TVector4f; const ATime: Double;
  350. const ASmoothNavigator: TgxNavigatorSmoothChangeVector; const AFNeedToRecalculateZoom: Boolean;
  351. const ACameraUpVector: PVector4f = nil): TgxSmoothOrbitToPos;
  352. begin
  353. Result := TgxSmoothOrbitToPos.Create(FCameraJobList);
  354. Result.FTargetPosition := ATargetPosition;
  355. Result.FTime := ATime;
  356. Result.FSmoothNavigator := ASmoothNavigator;
  357. Result.FShouldBeMatrix := FCameraJobList.FController.FCamera.Matrix^;
  358. Result.FNeedToRecalculateZoom := AFNeedToRecalculateZoom;
  359. if ACameraUpVector = nil then
  360. Result.FCameraUpVector := FCameraJobList.FController.FCamera.AbsoluteUp
  361. else
  362. Result.FCameraUpVector := ACameraUpVector^;
  363. end;
  364. function TgxCameraController.OrbitToPosAdvanced(x,y,z,time:double; PreferUpAxis: Boolean = True): TgxOrbitToPosAdvJob;
  365. begin
  366. Result := TgxOrbitToPosAdvJob.Create(FCameraJobList);
  367. Result.X := x;
  368. Result.Y := y;
  369. Result.Z := z;
  370. Result.PreferUpAxis := PreferUpAxis;
  371. Result.Time := time;
  372. end;
  373. function TgxCameraController.OrbitToPosAdvancedSmooth(const x,y,z, time: double;
  374. const ASmoothNavigator: TgxNavigatorSmoothChangeVector; const PreferUpAxis: Boolean = True): TgxSmoothOrbitToPosAdvJob;
  375. begin
  376. Result := TgxSmoothOrbitToPosAdvJob.Create(FCameraJobList);
  377. Result.X := x;
  378. Result.Y := y;
  379. Result.Z := z;
  380. Result.PreferUpAxis := PreferUpAxis;
  381. Result.Time := time;
  382. Result.FSmoothNavigator := ASmoothNavigator;
  383. Result.FPreviousPosition := ASmoothNavigator.OnGetCurrentValue(ASmoothNavigator);
  384. Result.FRestoreUpVector := True;
  385. end;
  386. procedure TgxCameraController.SafeOrbitAndZoomToPos(x,y,z:double);
  387. begin
  388. //this was the main purpose of this component
  389. //as you can see, it actually is a combination of the other 3 methods
  390. CheckAssignments(cGLCAMERACONTROLLER_CHECK_EXTENDED);
  391. ZoomToDistance(soSafeDistance,soTimeToSafePlacement);
  392. OrbitToPos(x,y,z,soTimeToOrbit);
  393. MoveToPos(x,y,z,soTimeToZoomBackIn);
  394. end;
  395. procedure TgxCameraController.StopMovement;
  396. begin
  397. FCameraJobList.Clear;
  398. end;
  399. procedure TgxCameraController.SetOnJobAdded(const Value: TgxCameraJobEvent);
  400. begin
  401. FOnJobAdded := Value;
  402. end;
  403. procedure TgxCameraController.SetOnJobStep(const Value: TgxCameraJobEvent);
  404. begin
  405. FOnJobStep := Value;
  406. end;
  407. procedure TgxCameraController.SetOnJobFinished(const Value: TgxCameraJobEvent);
  408. begin
  409. FOnJobFinished := Value;
  410. end;
  411. procedure TgxCameraController.SetCamera(const Value: TgxBaseSceneObject);
  412. begin
  413. if FCamera <> nil then FCamera.RemoveFreeNotification(Self);
  414. FCamera := Value;
  415. if FCamera <> nil then FCamera.FreeNotification(Self);
  416. if (FCamera is TgxCamera) and (FCameraTarget = nil) then
  417. SetCameraTarget(TgxCamera(FCamera).TargetObject);
  418. end;
  419. procedure TgxCameraController.SetCameraTarget(
  420. const Value: TgxBaseSceneObject);
  421. begin
  422. if FCameraTarget <> nil then FCameraTarget.RemoveFreeNotification(Self);
  423. FCameraTarget := Value;
  424. if FCameraTarget <> nil then FCameraTarget.FreeNotification(Self);
  425. end;
  426. procedure TgxCameraController.Notification(AComponent: TComponent;
  427. Operation: TOperation);
  428. begin
  429. inherited;
  430. if Operation = opRemove then
  431. begin
  432. if AComponent = FCamera then
  433. FCamera := nil
  434. else if AComponent = FCameraTarget then
  435. FCameraTarget := nil;
  436. end;
  437. end;
  438. { TgxCameraJobList }
  439. constructor TgxCameraJobList.Create(AController: TgxCameraController);
  440. begin
  441. inherited Create;
  442. FController := AController;
  443. end;
  444. function TgxCameraJobList.GetCameraJob(const AIndex: integer): TgxCameraJob;
  445. begin
  446. Result := inherited Get(AIndex);
  447. end;
  448. procedure TgxCameraJobList.SetCameraJob(const AIndex: integer;
  449. const Value: TgxCameraJob);
  450. begin
  451. inherited Put(AIndex, Value);
  452. end;
  453. function TgxCameraJobList.Add(ACameraJob: TgxCameraJob): integer;
  454. begin
  455. Result := inherited Add(ACameraJob);
  456. end;
  457. function TgxCameraJobList.First: TgxCameraJob;
  458. begin
  459. Result := TgxCameraJob(inherited First);
  460. end;
  461. function TgxCameraJobList.Last: TgxCameraJob;
  462. begin
  463. Result := TgxCameraJob(inherited Last);
  464. end;
  465. { TgxCameraJob }
  466. constructor TgxCameraJob.Create(const AJoblist : TgxCameraJobList);
  467. begin
  468. FJoblist := AJoblist;
  469. FJoblist.Add(Self);
  470. FInit := True;
  471. FStartTime := 0;
  472. FProceedTime := 0;
  473. end;
  474. destructor TgxCameraJob.Destroy;
  475. begin
  476. inherited;
  477. end;
  478. procedure TgxCameraJob.Abort;
  479. begin
  480. end;
  481. { TgxMoveToPosJob }
  482. procedure TgxMoveToPosJob.Init;
  483. begin
  484. FProceedTime := Time;
  485. FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  486. MakeVector(FFinalPos, X, Y, Z);
  487. end;
  488. procedure TgxMoveToPosJob.Step;
  489. var
  490. Vect : TVector4f;
  491. begin
  492. if FElapsedTime < FProceedTime then
  493. begin
  494. Vect := VectorLerp(FInitialPos, FFinalPos, FElapsedTime/FProceedTime);
  495. end
  496. else
  497. begin
  498. Vect := FFinalPos;
  499. FRunning := false;
  500. end;
  501. if Assigned(FJobList.FController.FCamera.Parent) then
  502. Vect:=FJobList.FController.FCamera.Parent.AbsoluteToLocal(Vect);
  503. FJobList.FController.FCamera.Position.AsVector := Vect;
  504. end;
  505. { TgxZoomToDistanceJob }
  506. procedure TgxZoomToDistanceJob.Init;
  507. begin
  508. FProceedTime := Time;
  509. FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  510. // To determine final position, we normalize original position and scale it with final distance
  511. SetVector(FFinalPos, FInitialPos);
  512. NormalizeVector(FFinalPos);
  513. ScaleVector(FFinalPos, Distance);
  514. end;
  515. procedure TgxZoomToDistanceJob.Step;
  516. var
  517. Vect : TVector4f;
  518. begin
  519. if FElapsedTime < FProceedTime then
  520. begin
  521. Vect := VectorLerp(FInitialPos, FFinalPos, FElapsedTime/FProceedTime);
  522. end
  523. else
  524. begin
  525. Vect := FFinalPos;
  526. FRunning := false;
  527. end;
  528. if Assigned(FJobList.FController.FCamera.Parent) then
  529. Vect:=FJobList.FController.FCamera.Parent.AbsoluteToLocal(Vect);
  530. FJobList.FController.FCamera.Position.AsVector := Vect;
  531. end;
  532. { TgxOrbitToPosJob }
  533. procedure TgxOrbitToPosJob.Init;
  534. begin
  535. FProceedTime := FTime;
  536. FFinalPos := ShiftObjectFromCenter(FTargetPosition, FJobList.FController.FCameraTarget.AbsolutePosition,
  537. VectorDistance(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition), True);
  538. // Yep, FFinalPos is stored in relative coordinates.
  539. if FJobList.FController.FCamera.Parent <> nil then
  540. FFinalPos := FJobList.FController.FCamera.Parent.AbsoluteToLocal(FFinalPos);
  541. FRotateSpeed := GetSafeTurnAngle(
  542. FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector, FTargetPosition,
  543. FJobList.FController.FCameraTarget.AbsolutePosition);
  544. ScaleVector(FRotateSpeed, 1 / FProceedTime);
  545. FInit := True;
  546. end;
  547. procedure TgxOrbitToPosJob.Step;
  548. begin
  549. if FElapsedTime < FProceedTime then
  550. begin
  551. FJobList.FController.FCamera.AbsolutePosition := MoveObjectAround(
  552. FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector,
  553. FJobList.FController.FCameraTarget.AbsolutePosition,
  554. FRotateSpeed.X * FDeltaTime, FRotateSpeed.Y * FDeltaTime);
  555. end
  556. else
  557. begin
  558. // Yep, FFinalPos is stored in ralative coordinates.
  559. FJobList.FController.FCamera.Position.AsVector := FFinalPos;
  560. FRunning := False;
  561. end;
  562. end;
  563. { TgxOrbitToPosAdvJob }
  564. procedure TgxOrbitToPosAdvJob.Init;
  565. var
  566. Right: TVector4f;
  567. lAbsVectorToTarget: TVector4f;
  568. begin
  569. FProceedTime := time;
  570. FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  571. if Assigned(FJobList.FController.FCamera.Parent) then
  572. FFinalPos := VectorSubtract(FJobList.FController.FCamera.Parent.LocalToAbsolute(VectorMake(x,y,z,1)), FJobList.FController.FCameraTarget.AbsolutePosition)
  573. else
  574. FFinalPos := VectorSubtract(VectorMake(x,y,z,1), FJobList.FController.FCameraTarget.AbsolutePosition);
  575. //if destination is Target Pos, we can't compute
  576. if VectorLength(FFinalPos)<cEPSILON then
  577. begin
  578. //FAllowUserAction := True;
  579. Exit;
  580. end;
  581. //Compute Angle of Rotation
  582. FAngle:= ArcCos(VectorAngleCosine(Vector3fMake(FFinalPos), Vector3fMake(FInitialPos)));
  583. lAbsVectorToTarget := VectorNormalize(VectorSubtract(
  584. FJobList.FController.FCameraTarget.AbsolutePosition,
  585. FJobList.FController.FCamera.AbsolutePosition));
  586. Right := VectorNormalize(VectorCrossProduct(lAbsVectorToTarget, FJobList.FController.FCamera.AbsoluteUp));
  587. FInitialDir := FJobList.FController.FCamera.AbsoluteDirection;
  588. FInitialUp := FJobList.FController.FCamera.AbsoluteUp;
  589. // Determine rotation Axis
  590. // if Angle equals 0 degrees.
  591. if FAngle < cEPSILON then
  592. if PreferUpAxis then
  593. FRotAxis := VectorNormalize(VectorCrossProduct(
  594. VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  595. else
  596. FRotAxis := Right
  597. else
  598. // if Angle equals 180 degrees.
  599. if FAngle >Pi - cEPSILON then
  600. if PreferUpAxis then
  601. FRotAxis := VectorNormalize(VectorCrossProduct(VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  602. else
  603. FRotAxis := Right
  604. else
  605. FRotAxis:= VectorNormalize(VectorCrossProduct(FFinalPos, FInitialPos));
  606. end;
  607. procedure TgxOrbitToPosAdvJob.Step;
  608. var
  609. tempUp, tempDir, tempPos : TVector4f;
  610. begin
  611. if FElapsedTime < FProceedTime then
  612. begin
  613. //Compute Position
  614. tempPos := FInitialPos;
  615. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  616. FJobList.FController.FCamera.AbsolutePosition := VectorAdd(FJobList.FController.FCameraTarget.AbsolutePosition, tempPos);
  617. //Compute Direction vector
  618. tempDir := FInitialDir;
  619. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  620. FJobList.FController.FCamera.AbsoluteDirection := tempDir;
  621. //Compute Up Vector
  622. tempUp := FInitialUp;
  623. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  624. FJobList.FController.FCamera.AbsoluteUp := tempUp;
  625. end
  626. else
  627. begin
  628. //Compute Position
  629. tempPos := FInitialPos;
  630. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle);
  631. FJoblist.FController.FCamera.AbsolutePosition := VectorAdd(
  632. FJoblist.FController.FCameraTarget.AbsolutePosition, tempPos);
  633. //Compute Direction vector
  634. tempDir := FInitialDir;
  635. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle);
  636. FJoblist.FController.FCamera.AbsoluteDirection := tempDir;
  637. //Compute Up Vector
  638. tempUp := FInitialUp;
  639. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle);
  640. FJoblist.FController.FCamera.AbsoluteUp := tempUp;
  641. FRunning := false;
  642. end;
  643. end;
  644. { TgxSmoothOrbitToPosAdvJob }
  645. procedure TgxSmoothOrbitToPosAdvJob.Init;
  646. var
  647. Right: TVector4f;
  648. begin
  649. FProceedTime := time;
  650. FInitialPos:= VectorSubtract(FPreviousPosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  651. if Assigned(FJobList.FController.FCamera.Parent) then
  652. FFinalPos := VectorSubtract(FJobList.FController.FCamera.Parent.LocalToAbsolute(VectorMake(x,y,z,1)), FJobList.FController.FCameraTarget.AbsolutePosition)
  653. else
  654. FFinalPos := VectorSubtract(VectorMake(x,y,z,1), FJobList.FController.FCameraTarget.AbsolutePosition);
  655. //if destination is Target Pos, we can't compute
  656. if VectorLength(FFinalPos)<cEPSILON then
  657. begin
  658. //FAllowUserAction := True;
  659. Exit;
  660. end;
  661. //Compute Angle of Rotation
  662. FAngle:= ArcCos(VectorAngleCosine(Vector3fMake(FFinalPos), Vector3fMake(FInitialPos)));
  663. Right := VectorNormalize(VectorCrossProduct(
  664. // FJobList.FController.FCamera.AbsoluteVectorToTarget,
  665. VectorNormalize(VectorSubtract(FJobList.FController.FCameraTarget.AbsolutePosition, FPreviousPosition)),
  666. FJobList.FController.FCamera.AbsoluteUp));
  667. FInitialDir := FJobList.FController.FCamera.AbsoluteDirection;
  668. FInitialUp := FJobList.FController.FCamera.AbsoluteUp;
  669. // Determine rotation Axis
  670. // if Angle equals 0 degrees.
  671. if FAngle < cEPSILON then
  672. if PreferUpAxis then
  673. FRotAxis := VectorNormalize(VectorCrossProduct(
  674. VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  675. else
  676. FRotAxis := Right
  677. else
  678. // if Angle equals 180 degrees.
  679. if FAngle >Pi - cEPSILON then
  680. if PreferUpAxis then
  681. FRotAxis := VectorNormalize(VectorCrossProduct(VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  682. else
  683. FRotAxis := Right
  684. else
  685. FRotAxis:= VectorNormalize(VectorCrossProduct(FFinalPos, FInitialPos));
  686. end;
  687. procedure TgxSmoothOrbitToPosAdvJob.Step;
  688. var
  689. tempUp, tempDir, tempPos : TVector4f;
  690. begin
  691. if FElapsedTime < FProceedTime then
  692. begin
  693. //Compute Position
  694. tempPos := FInitialPos;
  695. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  696. FSmoothNavigator.TargetValue.DirectVector := VectorAdd(FJobList.FController.FCameraTarget.AbsolutePosition, tempPos);
  697. FPreviousPosition := FSmoothNavigator.TargetValue.DirectVector;
  698. //Compute Direction vector
  699. tempDir := FInitialDir;
  700. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  701. FJobList.FController.FCamera.AbsoluteDirection := tempDir;
  702. //Compute Up Vector
  703. if FRestoreUpVector then
  704. FJobList.FController.FCamera.AbsoluteUp := FInitialUp
  705. else
  706. begin
  707. tempUp := FInitialUp;
  708. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  709. FJobList.FController.FCamera.AbsoluteUp := tempUp;
  710. end;
  711. end
  712. else
  713. begin
  714. //Compute Position
  715. tempPos := FInitialPos;
  716. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle);
  717. FJoblist.FController.FCamera.AbsolutePosition := VectorAdd(
  718. FJoblist.FController.CameraTarget.AbsolutePosition, tempPos);
  719. //Compute Direction vector
  720. tempDir := FInitialDir;
  721. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle);
  722. FJoblist.FController.FCamera.AbsoluteDirection := tempDir;
  723. //Compute Up Vector
  724. if FRestoreUpVector then
  725. FJoblist.FController.FCamera.AbsoluteUp := FInitialUp
  726. else
  727. begin
  728. tempUp := FInitialUp;
  729. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle);
  730. FJoblist.FController.FCamera.AbsoluteUp := tempUp;
  731. FRunning := false;
  732. end;
  733. FRunning := false;
  734. end;
  735. end;
  736. { TgxSmoothOrbitToPosAdv }
  737. constructor TgxSmoothOrbitToPos.Create(const AJoblist: TgxCameraJobList);
  738. begin
  739. inherited;
  740. FCutoffAngle := 0.1;
  741. end;
  742. procedure TgxSmoothOrbitToPos.Step;
  743. var
  744. lCurrentDistanceToTarget: Single;
  745. lTargetPosition: TVector4f;
  746. lCurrentMatrix: TMatrix4f;
  747. lAngle: Single;
  748. lAbsTargetPosition: TVector4f;
  749. procedure RestoreDistanceToTarget();
  750. var
  751. lDirection: TVector4f;
  752. begin
  753. lDirection := VectorNormalize(VectorSubtract(
  754. FJobList.FController.FCameraTarget.AbsolutePosition,
  755. FJobList.FController.FCamera.AbsolutePosition));
  756. FJobList.FController.FCamera.AbsolutePosition := VectorAdd(
  757. FJobList.FController.FCameraTarget.AbsolutePosition,
  758. VectorScale(lDirection, - lCurrentDistanceToTarget));
  759. end;
  760. procedure SetTargetValueRelative(const AAbsolutePosition: TVector4f);
  761. begin
  762. if FJobList.FController.FCamera.Parent = nil then
  763. FSmoothNavigator.TargetValue.DirectVector := AAbsolutePosition
  764. else
  765. FSmoothNavigator.TargetValue.DirectVector := FJobList.FController.FCamera.Parent.AbsoluteToLocal(AAbsolutePosition);
  766. end;
  767. procedure ApplyDistanceToResult();
  768. var
  769. lDirection, lNewTargetPosition: TVector4f;
  770. begin
  771. lDirection := VectorNormalize(VectorSubtract(
  772. FJobList.FController.FCameraTarget.AbsolutePosition,
  773. lAbsTargetPosition));
  774. lNewTargetPosition := VectorAdd(
  775. FJobList.FController.FCameraTarget.AbsolutePosition,
  776. VectorScale(lDirection, - lCurrentDistanceToTarget));
  777. SetTargetValueRelative(lNewTargetPosition);
  778. end;
  779. begin
  780. if FElapsedTime < FProceedTime then
  781. begin
  782. // Save current matrix.
  783. lCurrentMatrix := FJobList.FController.FCamera.Matrix^;
  784. if FNeedToRecalculateZoom then
  785. lCurrentDistanceToTarget := FJobList.FController.FCamera.DistanceTo(FJobList.FController.FCameraTarget)
  786. else
  787. lCurrentDistanceToTarget := 0; // To avoid warning message.
  788. // Calculate the position, in which camera should have been.
  789. FJobList.FController.FCamera.SetMatrix(FShouldBeMatrix);
  790. FJobList.FController.FCamera.AbsolutePosition := MoveObjectAround(
  791. FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector,
  792. FJobList.FController.FCameraTarget.AbsolutePosition,
  793. FRotateSpeed.X * FDeltaTime, FRotateSpeed.Y * FDeltaTime);
  794. if FNeedToRecalculateZoom then
  795. RestoreDistanceToTarget();
  796. lTargetPosition := FJobList.FController.FCamera.AbsolutePosition;
  797. FShouldBeMatrix := FJobList.FController.FCamera.Matrix^;
  798. // Restore Camera position and move it to the desired vector.
  799. FJobList.FController.FCamera.SetMatrix(lCurrentMatrix);
  800. SetTargetValueRelative(lTargetPosition);
  801. end
  802. else
  803. begin
  804. if FNeedToRecalculateZoom then
  805. begin
  806. if FJobList.FController.FCamera.Parent = nil then
  807. lAbsTargetPosition := FFinalPos
  808. else
  809. lAbsTargetPosition := FJobList.FController.FCamera.Parent.LocalToAbsolute(FFinalPos);
  810. lAngle := RadToDeg(AngleBetweenVectors(FJobList.FController.FCamera.AbsolutePosition,
  811. lAbsTargetPosition, FJobList.FController.FCameraTarget.AbsolutePosition));
  812. if lAngle < FCutoffAngle then
  813. begin
  814. FSmoothNavigator.Enabled := False;
  815. FRunning := False;
  816. end
  817. else
  818. begin
  819. lCurrentDistanceToTarget := FJobList.FController.FCamera.DistanceTo(FJobList.FController.FCameraTarget);
  820. ApplyDistanceToResult();
  821. end;
  822. end
  823. else
  824. begin
  825. FSmoothNavigator.TargetValue.DirectVector := FFinalPos;
  826. FRunning := False;
  827. end;
  828. end;
  829. end;
  830. end.