GXS.Movement.pas 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Movement;
  5. (*
  6. Movement path behaviour by Roger Cao
  7. Note: It is recommended to set TgxMovementPath.RotationMode = rmUpDirection,
  8. but the default value is rmTurnPitchRoll for backwards compatibility.
  9. *)
  10. interface
  11. {$I Stage.Defines.inc}
  12. uses
  13. Winapi.OpenGL,
  14. System.Classes,
  15. System.SysUtils,
  16. GXS.XCollection,
  17. GXS.PersistentClasses,
  18. GXS.BaseClasses,
  19. Stage.VectorTypes,
  20. Stage.VectorGeometry,
  21. Stage.Spline,
  22. Stage.Strings,
  23. GXS.Scene,
  24. GXS.Objects,
  25. Stage.Utils;
  26. type
  27. TgxPathNode = class (TCollectionItem)
  28. private
  29. FPosition: TVector4f;
  30. FScale: TVector4f;
  31. FRotation: TVector4f;
  32. FDirection: TVector4f;
  33. FUp: TVector4f;
  34. FSpeed: single;
  35. procedure SetPositionAsVector(const Value: TVector4f);
  36. procedure SetRotationAsVector(const Value: TVector4f);
  37. procedure SetScaleAsVector(const Value: TVector4f);
  38. function GetPositionCoordinate(const Index: Integer): Single;
  39. procedure SetPositionCoordinate(const Index: integer; const AValue: Single);
  40. function GetRotationCoordinate(const Index: Integer): Single;
  41. procedure SetRotationCoordinate(const Index: integer; const AValue: Single);
  42. function GetScaleCoordinate(const Index: Integer): Single;
  43. procedure SetScaleCoordinate(const Index: integer; const AValue: Single);
  44. procedure SetSpeed(const Value: single);
  45. function GetDirectionCoordinate(const Index: Integer): Single;
  46. procedure SetDirectionCoordinate(const Index: integer; const AValue: Single);
  47. function GetUpCoordinate(const Index: Integer): Single;
  48. procedure SetUpCoordinate(const Index: integer; const AValue: Single);
  49. protected
  50. function GetDisplayName: string; override;
  51. procedure WriteToFiler(writer : TWriter);
  52. procedure ReadFromFiler(reader : TReader);
  53. public
  54. constructor Create(Collection: TCollection); override;
  55. destructor Destroy; override;
  56. function PositionAsAddress: PGLFloat;
  57. function RotationAsAddress: PGLFloat;
  58. function ScaleAsAddress: PGLFloat;
  59. procedure Assign(Source: TPersistent); override;
  60. procedure InitializeByObject(const Obj: TgxBaseSceneObject);
  61. // Warning: does not take speed into account.
  62. function EqualNode(const aNode: TgxPathNode): boolean;
  63. // Rotation.X means PitchAngle, Rotation.Y means TurnAngle, Rotation.Z means RollAngle.
  64. property RotationAsVector: TVector4f Read FRotation Write SetRotationAsVector;
  65. property PositionAsVector: TVector4f Read FPosition Write SetPositionAsVector;
  66. property ScaleAsVector: TVector4f Read FScale Write SetScaleAsVector;
  67. property UpAsVector: TVector4f read FUp write FUp;
  68. property DirectionAsVector: TVector4f read FDirection write FDirection;
  69. published
  70. property X: Single index 0 Read GetPositionCoordinate Write SetPositionCoordinate;
  71. property Y: Single index 1 Read GetPositionCoordinate Write SetPositionCoordinate;
  72. property Z: Single index 2 Read GetPositionCoordinate Write SetPositionCoordinate;
  73. (* Rotation.X means PitchAngle;
  74. Rotation.Y means TurnAngle;
  75. Rotation.Z means RollAngle; *)
  76. property PitchAngle: Single index 0 Read GetRotationCoordinate Write SetRotationCoordinate;
  77. property TurnAngle: Single index 1 Read GetRotationCoordinate Write SetRotationCoordinate;
  78. property RollAngle: Single index 2 Read GetRotationCoordinate Write SetRotationCoordinate;
  79. property ScaleX: Single index 0 Read GetScaleCoordinate Write SetScaleCoordinate;
  80. property ScaleY: Single index 1 Read GetScaleCoordinate Write SetScaleCoordinate;
  81. property ScaleZ: Single index 2 Read GetScaleCoordinate Write SetScaleCoordinate;
  82. property DirectionX: Single index 0 Read GetDirectionCoordinate Write SetDirectionCoordinate;
  83. property DirectionY: Single index 1 Read GetDirectionCoordinate Write SetDirectionCoordinate;
  84. property DirectionZ: Single index 2 Read GetDirectionCoordinate Write SetDirectionCoordinate;
  85. property UpX: Single index 0 Read GetUpCoordinate Write SetUpCoordinate;
  86. property UpY: Single index 1 Read GetUpCoordinate Write SetUpCoordinate;
  87. property UpZ: Single index 2 Read GetUpCoordinate Write SetUpCoordinate;
  88. property Speed: single Read FSpeed Write SetSpeed;
  89. end;
  90. TgxMovementRotationMode = (rmTurnPitchRoll, rmUpDirection);
  91. TgxMovementPath = class;
  92. TgxPathNodes = class (TOwnedCollection)
  93. protected
  94. procedure SetItems(const index: integer; const val: TgxPathNode);
  95. function GetItems(const index: integer): TgxPathNode;
  96. public
  97. constructor Create(aOwner: TgxMovementPath);
  98. function GetOwnerMovementPath: TgxMovementPath;
  99. function Add: TgxPathNode;
  100. function FindItemID(const ID: integer): TgxPathNode;
  101. property Items[const index: integer]: TgxPathNode Read GetItems Write SetItems; default;
  102. procedure NotifyChange; virtual;
  103. end;
  104. TgxMovement = class;
  105. TgxMovementPaths = class;
  106. TgxMovementPath = class(TCollectionItem)
  107. private
  108. FPathLine: TgxLines;
  109. FShowPath: Boolean;
  110. FPathSplineMode: TgxLineSplineMode;
  111. FNodes: TgxPathNodes;
  112. //All the time saved in ms
  113. FStartTimeApplied: Boolean;
  114. FStartTime: double;
  115. FInitialTime: Double;
  116. FEstimateTime: double;
  117. FCurrentNode: TgxPathNode;
  118. FInTravel: boolean;
  119. FLooped: boolean;
  120. FName: string;
  121. FRotationMode: TgxMovementRotationMode;
  122. MotionSplineControl: TCubicSpline;
  123. RotationSplineControl: TCubicSpline;
  124. ScaleSplineControl: TCubicSpline;
  125. DirectionSplineControl: TCubicSpline;
  126. UpSplineControl: TCubicSpline;
  127. FOnTravelStart: TNotifyEvent;
  128. FOnTravelStop: TNotifyEvent;
  129. FCurrentNodeIndex: integer;
  130. function GetNodeCount: integer;
  131. procedure SetStartTime(const Value: double);
  132. procedure SetCurrentNodeIndex(const Value: integer);
  133. procedure SetShowPath(const Value: Boolean);
  134. procedure SetPathSplineMode(const Value: TgxLineSplineMode);
  135. protected
  136. procedure WriteToFiler(writer : TWriter);
  137. procedure ReadFromFiler(reader : TReader);
  138. function CanTravel: boolean;
  139. function GetCollection: TgxMovementPaths;
  140. public
  141. constructor Create(Collection: TCollection); override;
  142. destructor Destroy; override;
  143. procedure Assign(Source: TPersistent); override;
  144. function GetMovement: TgxMovement;
  145. function AddNode: TgxPathNode; overload;
  146. function AddNode(const Node: TgxPathNode): TgxPathNode; overload;
  147. function AddNodeFromObject(const Obj: TgxBaseSceneObject): TgxPathNode;
  148. function InsertNodeFromObject(const Obj: TgxBaseSceneObject; const Index: integer): TgxPathNode;
  149. function InsertNode(const Node: TgxPathNode; const Index: integer): TgxPathNode; overload;
  150. function InsertNode(const Index: integer): TgxPathNode; overload;
  151. function DeleteNode(const Index: integer): TgxPathNode; overload;
  152. function DeleteNode(const Node: TgxPathNode): TgxPathNode; overload;
  153. procedure ClearNodes;
  154. procedure UpdatePathLine;
  155. function NodeDistance(const Node1, Node2: TgxPathNode): double;
  156. procedure CalculateState(const CurrentTime: double);
  157. procedure TravelPath(const Start: boolean); overload;
  158. procedure TravelPath(const Start: boolean; const aStartTime: double); overload;
  159. property NodeCount: integer Read GetNodeCount;
  160. property CurrentNode: TgxPathNode Read FCurrentNode;
  161. property InTravel: boolean Read FInTravel;
  162. function PrevNode: integer;
  163. function NextNode: integer;
  164. property CurrentNodeIndex: integer Read FCurrentNodeIndex Write SetCurrentNodeIndex;
  165. property OnTravelStart: TNotifyEvent Read FOnTravelStart Write FOnTravelStart;
  166. property OnTravelStop: TNotifyEvent Read FOnTravelStop Write FOnTravelStop;
  167. published
  168. property Name: string Read FName Write FName;
  169. { This property is currently ignored. }
  170. property PathSplineMode: TgxLineSplineMode read FPathSplineMode write SetPathSplineMode default lsmLines;
  171. property RotationMode: TgxMovementRotationMode read FRotationMode write FRotationMode default rmTurnPitchRoll;
  172. property StartTime: double Read FStartTime Write SetStartTime;
  173. property EstimateTime: double Read FEstimateTime;
  174. property Looped: boolean Read FLooped Write FLooped;
  175. property Nodes: TgxPathNodes Read FNodes;
  176. property ShowPath: Boolean read FShowPath write SetShowPath;
  177. end;
  178. TgxMovementPaths = class(TOwnedCollection)
  179. protected
  180. procedure SetItems(const index: integer; const val: TgxMovementPath);
  181. function GetItems(const index: integer): TgxMovementPath;
  182. function GetMovement: TgxMovement;
  183. public
  184. constructor Create(aOwner: TgxMovement);
  185. function Add: TgxMovementPath;
  186. function FindItemID(const ID: integer): TgxMovementPath;
  187. property Items[const index: integer]: TgxMovementPath Read GetItems Write SetItems; default;
  188. procedure NotifyChange; virtual;
  189. end;
  190. //Event for path related event
  191. TPathTravelStartEvent = procedure (Sender: TObject;
  192. Path: TgxMovementPath) of object;
  193. TPathTravelStopEvent = procedure (Sender: TObject;
  194. Path: TgxMovementPath; var Looped: boolean) of object;
  195. TgxMovement = class(TgxBehaviour)
  196. private
  197. FPaths: TgxMovementPaths;
  198. FAutoStartNextPath: boolean;
  199. FActivePathIndex: integer;
  200. FOnAllPathTravelledOver: TNotifyEvent;
  201. FOnPathTravelStart: TPathTravelStartEvent;
  202. FOnPathTravelStop: TPathTravelStopEvent;
  203. ///function GetMovementPath(Index: integer): TgxMovementPath;
  204. ///procedure SetMovementPath(Index: integer; AValue: TgxMovementPath);
  205. function GetPathCount: integer;
  206. procedure SetActivePathIndex(Value: integer);
  207. function GetActivePath: TgxMovementPath;
  208. procedure SetActivePath(Value: TgxMovementPath);
  209. protected
  210. procedure WriteToFiler(writer : TWriter); override;
  211. procedure ReadFromFiler(reader : TReader); override;
  212. procedure PathTravelStart(Sender: TObject);
  213. procedure PathTravelStop(Sender: TObject);
  214. function GetSceneObject: TgxBaseSceneObject;
  215. public
  216. constructor Create(aOwner: TXCollection); override;
  217. destructor Destroy; override;
  218. //add an empty path;
  219. function AddPath: TgxMovementPath; overload;
  220. //add an path with one node, and the node is based on aObject
  221. function AddPath(aObject: TgxBaseSceneObject): TgxMovementPath; overload;
  222. //add one path to the new one
  223. function AddPath(Path: TgxMovementPath): TgxMovementPath; overload;
  224. procedure ClearPaths;
  225. //Result is current path
  226. function DeletePath(Path: TgxMovementPath): TgxMovementPath; overload;
  227. function DeletePath(Index: integer): TgxMovementPath; overload;
  228. function DeletePath: TgxMovementPath; overload;
  229. procedure Assign(Source: TPersistent); override;
  230. class function FriendlyName: string; override;
  231. class function FriendlyDescription: string; override;
  232. class function UniqueItem: boolean; override;
  233. procedure StartPathTravel;
  234. procedure StopPathTravel;
  235. procedure DoProgress(const progressTime : TgxProgressTimes); override;
  236. function NextPath: integer;
  237. function PrevPath: integer;
  238. function FirstPath: integer;
  239. function LastPath: integer;
  240. //property Paths[index: Integer]: TgxMovementPath read GetMovementPath write SetMovementPath;
  241. property PathCount: integer Read GetPathCount;
  242. //why do these property can't be saved in IDE ?
  243. property OnAllPathTravelledOver: TNotifyEvent Read FOnAllPathTravelledOver Write FOnAllPathTravelledOver;
  244. property OnPathTravelStart: TPathTravelStartEvent Read FOnPathTravelStart Write FOnPathTravelStart;
  245. property OnPathTravelStop: TPathTravelStopEvent Read FOnPathTravelStop Write FOnPathTravelStop;
  246. published
  247. property Paths: TgxMovementPaths Read FPaths;
  248. property AutoStartNextPath: boolean Read FAutoStartNextPath Write FAutoStartNextPath;
  249. property ActivePathIndex: integer Read FActivePathIndex Write SetActivePathIndex;
  250. property ActivePath: TgxMovementPath Read GetActivePath Write SetActivePath;
  251. end;
  252. function GetMovement(const behaviours: TgxBehaviours): TgxMovement; overload;
  253. function GetMovement(const obj: TgxBaseSceneObject): TgxMovement; overload;
  254. function GetOrCreateMovement(const behaviours: TgxBehaviours): TgxMovement; overload;
  255. function GetOrCreateMovement(const obj: TgxBaseSceneObject): TgxMovement; overload;
  256. procedure StartAllMovements(const Scene: TgxScene; const StartCamerasMove, StartObjectsMove: Boolean);
  257. procedure StopAllMovements(const Scene: TgxScene; const StopCamerasMove, StopObjectsMove: Boolean);
  258. // ------------------------------------------------------------------
  259. implementation
  260. // ------------------------------------------------------------------
  261. //----------------------------- TgxPathNode ------------------------------------
  262. constructor TgxPathNode.Create(Collection: TCollection);
  263. begin
  264. inherited Create(Collection);
  265. FPosition := VectorMake(0, 0, 0, 1);
  266. FRotation := VectorMake(0, 0, 0, 1);
  267. FScale := VectorMake(1, 1, 1, 1);
  268. FDirection := ZHmgVector;
  269. FUp := YHmgVector;
  270. FSpeed := 0;
  271. end;
  272. destructor TgxPathNode.Destroy;
  273. begin
  274. inherited Destroy;
  275. end;
  276. procedure TgxPathNode.SetPositionAsVector(const Value: TVector4f);
  277. begin
  278. FPosition := Value;
  279. (Collection as TgxPathNodes).NotifyChange;
  280. end;
  281. procedure TgxPathNode.SetRotationAsVector(const Value: TVector4f);
  282. begin
  283. FRotation := Value;
  284. (Collection as TgxPathNodes).NotifyChange;
  285. end;
  286. procedure TgxPathNode.SetScaleAsVector(const Value: TVector4f);
  287. begin
  288. FScale := Value;
  289. (Collection as TgxPathNodes).NotifyChange;
  290. end;
  291. function TgxPathNode.PositionAsAddress: PGLFloat;
  292. begin
  293. Result := @FPosition;
  294. end;
  295. function TgxPathNode.RotationAsAddress: PGLFloat;
  296. begin
  297. Result := @FRotation;
  298. end;
  299. function TgxPathNode.ScaleAsAddress: PGLFloat;
  300. begin
  301. Result := @FScale;
  302. end;
  303. procedure TgxPathNode.WriteToFiler(writer : TWriter);
  304. var
  305. WriteStuff: boolean;
  306. begin
  307. with Writer do
  308. begin
  309. WriteInteger(1); // Archive Version 1.
  310. WriteStuff := not (VectorEquals(FPosition, NullHmgPoint) and
  311. VectorEquals(FRotation, NullHmgPoint) and
  312. VectorEquals(FScale, XYZHmgVector) and
  313. (Speed = 0) and
  314. VectorEquals(FDirection, ZHmgVector) and
  315. VectorEquals(FUp, YHmgVector));
  316. WriteBoolean(writeStuff);
  317. if WriteStuff then
  318. begin
  319. // Archive Version 0.
  320. Write(FPosition, SizeOf(FPosition));
  321. Write(FRotation, SizeOf(FRotation));
  322. Write(FScale, SizeOf(FScale));
  323. WriteFloat(FSpeed);
  324. // Archive Version 1.
  325. Write(FDirection, SizeOf(FDirection));
  326. Write(FUp, SizeOf(FUp));
  327. end;
  328. end;
  329. end;
  330. procedure TgxPathNode.ReadFromFiler(reader : TReader);
  331. var
  332. lVersion: Integer;
  333. begin
  334. with Reader do
  335. begin
  336. lVersion := ReadInteger;
  337. if ReadBoolean then
  338. begin
  339. // Archive Version 0.
  340. Read(FPosition, SizeOf(FPosition));
  341. Read(FRotation, SizeOf(FRotation));
  342. Read(FScale, SizeOf(FScale));
  343. FSpeed := ReadFloat;
  344. // Archive Version 1.
  345. if lVersion >= 1 then
  346. begin
  347. Read(FDirection, SizeOf(FDirection));
  348. Read(FUp, SizeOf(FUp));
  349. end;
  350. end
  351. else
  352. begin
  353. // Default parameters.
  354. FPosition := NullHmgPoint;
  355. FRotation := NullHmgPoint;
  356. FScale := VectorMake(1, 1, 1, 1);
  357. FSpeed := 0;
  358. FDirection := ZHmgVector;
  359. FUp := YHmgVector;
  360. end;
  361. end;
  362. end;
  363. procedure TgxPathNode.InitializeByObject(const Obj: TgxBaseSceneObject);
  364. begin
  365. if Assigned(Obj) then
  366. begin
  367. FPosition := Obj.Position.AsVector;
  368. FScale := Obj.Scale.AsVector;
  369. FRotation := Obj.Rotation.AsVector;
  370. FDirection := Obj.Direction.AsVector;
  371. FUp := Obj.Up.AsVector;
  372. end;
  373. end;
  374. procedure TgxPathNode.Assign(Source: TPersistent);
  375. begin
  376. if Source is TgxPathNode then
  377. begin
  378. FPosition := TgxPathNode(Source).FPosition;
  379. FRotation := TgxPathNode(Source).FRotation;
  380. FScale := TgxPathNode(Source).FScale;
  381. FSpeed := TgxPathNode(Source).FSpeed;
  382. FDirection := TgxPathNode(Source).FDirection;
  383. FUp := TgxPathNode(Source).FUp;
  384. end else
  385. inherited Assign(Source);
  386. end;
  387. function TgxPathNode.EqualNode(const aNode: TgxPathNode): boolean;
  388. begin
  389. Result := VectorEquals(FPosition, aNode.FPosition) and
  390. VectorEquals(FRotation, aNode.FRotation) and
  391. VectorEquals(FScale, aNode.FScale) and
  392. VectorEquals(FDirection, aNode.FDirection) and
  393. VectorEquals(FUp, aNode.FUp);
  394. end;
  395. procedure TgxPathNode.SetSpeed(const Value: single);
  396. begin
  397. FSpeed := Value;
  398. end;
  399. function TgxPathNode.GetDisplayName: string;
  400. begin
  401. Result := 'PathNode';
  402. end;
  403. function TgxPathNode.GetPositionCoordinate(const Index: Integer): Single;
  404. begin
  405. result := FPosition.V[Index];
  406. end;
  407. procedure TgxPathNode.SetPositionCoordinate(const Index: integer; const AValue: Single);
  408. begin
  409. FPosition.V[Index] := AValue;
  410. if Collection <> nil then
  411. (Collection as TgxPathNodes).NotifyChange;
  412. end;
  413. function TgxPathNode.GetRotationCoordinate(const Index: Integer): Single;
  414. begin
  415. result := FRotation.V[Index];
  416. end;
  417. procedure TgxPathNode.SetRotationCoordinate(const Index: integer; const AValue: Single);
  418. begin
  419. FRotation.V[Index] := AValue;
  420. if Collection <> nil then
  421. (Collection as TgxPathNodes).NotifyChange;
  422. end;
  423. function TgxPathNode.GetScaleCoordinate(const Index: Integer): Single;
  424. begin
  425. result := FScale.V[Index];
  426. end;
  427. procedure TgxPathNode.SetScaleCoordinate(const Index: integer; const AValue: Single);
  428. begin
  429. FScale.V[Index] := AValue;
  430. if Collection <> nil then
  431. (Collection as TgxPathNodes).NotifyChange;
  432. end;
  433. function TgxPathNode.GetDirectionCoordinate(const Index: Integer): Single;
  434. begin
  435. result := FDirection.V[Index];
  436. end;
  437. procedure TgxPathNode.SetDirectionCoordinate(const Index: integer;
  438. const AValue: Single);
  439. begin
  440. FDirection.V[Index] := AValue;
  441. if Collection <> nil then
  442. (Collection as TgxPathNodes).NotifyChange;
  443. end;
  444. function TgxPathNode.GetUpCoordinate(const Index: Integer): Single;
  445. begin
  446. result := FUp.V[Index];
  447. end;
  448. procedure TgxPathNode.SetUpCoordinate(const Index: integer; const AValue: Single);
  449. begin
  450. FUp.V[Index] := AValue;
  451. if Collection <> nil then
  452. (Collection as TgxPathNodes).NotifyChange;
  453. end;
  454. //--------------------------- TgxPathNodes -------------------------------------
  455. constructor TgxPathNodes.Create(aOwner: TgxMovementPath);
  456. begin
  457. inherited Create(aOwner, TgxPathNode);
  458. end;
  459. procedure TgxPathNodes.SetItems(const index: integer; const val: TgxPathNode);
  460. begin
  461. inherited Items[index] := val;
  462. end;
  463. function TgxPathNodes.GetItems(const index: integer): TgxPathNode;
  464. begin
  465. Result := TgxPathNode(inherited Items[index]);
  466. end;
  467. function TgxPathNodes.Add: TgxPathNode;
  468. begin
  469. Result := (inherited Add) as TgxPathNode;
  470. end;
  471. function TgxPathNodes.GetOwnerMovementPath: TgxMovementPath;
  472. begin
  473. Result := TgxMovementPath(GetOwner);
  474. end;
  475. function TgxPathNodes.FindItemID(const ID: integer): TgxPathNode;
  476. begin
  477. Result := (inherited FindItemID(ID)) as TgxPathNode;
  478. end;
  479. procedure TgxPathNodes.NotifyChange;
  480. begin
  481. // Update the path-line if avalible in TgxMovementPath.
  482. GetOwnerMovementPath.UpdatePathLine;
  483. end;
  484. //--------------------------- TgxMovementPath ----------------------------------
  485. constructor TgxMovementPath.Create(Collection: TCollection);
  486. begin
  487. // This object can only be added to a TgxMovement class.
  488. inherited Create(Collection);
  489. FNodes := TgxPathNodes.Create(Self);
  490. FCurrentNodeIndex := -1;
  491. FRotationMode := rmTurnPitchRoll;
  492. FPathSplineMode := lsmCubicSpline;
  493. FStartTimeApplied := False;
  494. end;
  495. destructor TgxMovementPath.Destroy;
  496. begin
  497. // Make sure the splines are freed.
  498. FLooped:= false;
  499. ClearNodes;
  500. FNodes.Free;
  501. inherited Destroy;
  502. end;
  503. procedure TgxMovementPath.WriteToFiler(writer : TWriter);
  504. var
  505. WriteStuff: boolean;
  506. I: Integer;
  507. begin
  508. with Writer do
  509. begin
  510. WriteInteger(1); // Archive Version 1.
  511. WriteStuff := (FNodes.Count>0) or (FLooped) or (FCurrentNodeIndex<>-1) or (FShowPath) or
  512. (FPathSplineMode <> lsmCubicSpline) or (FRotationMode <> rmTurnPitchRoll);
  513. WriteBoolean(writeStuff);
  514. if WriteStuff then
  515. begin
  516. // Archive Version 0.
  517. WriteBoolean(FLooped);
  518. WriteInteger(FCurrentNodeIndex);
  519. WriteBoolean(FShowPath);
  520. Write(FPathSplineMode, SizeOf(FPathSplineMode));
  521. WriteInteger(FNodes.Count);
  522. for I:=0 to FNodes.Count-1 do
  523. FNodes.Items[I].WriteToFiler(Writer);
  524. // Archive Version 1.
  525. WriteInteger(Ord(FRotationMode));
  526. end;
  527. end;
  528. end;
  529. procedure TgxMovementPath.ReadFromFiler(reader : TReader);
  530. var
  531. I: Integer;
  532. Count: Integer;
  533. Node: TgxPathNode;
  534. lVersion: Integer;
  535. begin
  536. ClearNodes;
  537. with Reader do
  538. begin
  539. lVersion := ReadInteger; // Archive Version.
  540. if ReadBoolean then
  541. begin
  542. // Archive Version 0.
  543. FLooped := ReadBoolean;
  544. FCurrentNodeIndex := ReadInteger;
  545. ShowPath := ReadBoolean;
  546. Read(FPathSplineMode, SizeOf(FPathSplineMode));
  547. Count := ReadInteger;
  548. for I:=0 to Count-1 do
  549. begin
  550. Node := AddNode;
  551. Node.ReadFromFiler(Reader);
  552. end;
  553. // Archive Version 1.
  554. if lVersion >= 1 then
  555. begin
  556. FRotationMode := TgxMovementRotationMode(ReadInteger);
  557. end;
  558. end
  559. else
  560. begin
  561. FLooped := False;
  562. FCurrentNodeIndex := -1;
  563. FShowPath := False;
  564. FPathSplineMode := lsmCubicSpline;
  565. FRotationMode := rmTurnPitchRoll;
  566. end;
  567. end;
  568. UpdatePathLine;
  569. end;
  570. procedure TgxMovementPath.SetPathSplineMode(const Value: TgxLineSplineMode);
  571. begin
  572. if Value<>FPathSplineMode then
  573. begin
  574. FPathSplineMode := Value;
  575. if FShowPath then
  576. FPathLine.SplineMode := FPathSplineMode;
  577. end;
  578. end;
  579. procedure TgxMovementPath.UpdatePathLine;
  580. var
  581. I: Integer;
  582. Node: TgxPathNode;
  583. begin
  584. if FShowPath then
  585. begin
  586. FPathLine.Nodes.Clear;
  587. for I:=0 to Nodes.Count-1 do
  588. begin
  589. Node := Nodes.Items[I];
  590. FPathLine.AddNode(Node.PositionAsVector);
  591. end;
  592. end;
  593. end;
  594. procedure TgxMovementPath.SetShowPath(const Value: Boolean);
  595. var
  596. OwnerObj: TgxBaseSceneObject;
  597. begin
  598. if FShowPath<>Value then
  599. begin
  600. FShowPath := Value;
  601. OwnerObj := GetMovement.GetSceneObject;
  602. if FShowPath then
  603. begin
  604. FPathLine := TgxLines.Create(OwnerObj);
  605. MakeSubComponent(FPathLine, True);
  606. OwnerObj.Scene.Objects.AddChild(FPathLine);
  607. FPathLine.SplineMode := FPathSplineMode;
  608. UpdatePathLine;
  609. end
  610. else
  611. FreeAndNil(FPathLine);
  612. end;
  613. end;
  614. procedure TgxMovementPath.ClearNodes;
  615. begin
  616. TravelPath(False);
  617. FNodes.Clear;
  618. if Assigned(FCurrentNode) then
  619. begin
  620. FCurrentNode.Free;
  621. FCurrentNode := nil;
  622. end;
  623. FCurrentNodeIndex := -1;
  624. UpdatePathLine;
  625. end;
  626. procedure TgxMovementPath.SetCurrentNodeIndex(const Value: integer);
  627. begin
  628. if FNodes.Count = 0 then
  629. begin
  630. FCurrentNodeIndex := -1;
  631. exit;
  632. end;
  633. if (FInTravel) or (Value > FNodes.Count - 1) or (Value < 0) then
  634. exit
  635. else
  636. begin
  637. FCurrentNodeIndex := Value;
  638. if not Assigned(FCurrentNode) then
  639. FCurrentNode := TgxPathNode.Create(nil);
  640. FCurrentNode.Assign(Nodes[FCurrentNodeIndex]);
  641. end;
  642. end;
  643. function TgxMovementPath.InsertNode(const Node: TgxPathNode; const Index: integer): TgxPathNode;
  644. var
  645. N: TgxPathNode;
  646. begin
  647. Result := nil;
  648. //Intravel, can't insert
  649. if FInTravel then
  650. exit;
  651. //Insert into the position
  652. if (Assigned(Node)) and (Assigned(Nodes[Index])) then
  653. begin
  654. N := TgxPathNode(FNodes.Insert(Index));
  655. if Index >0 then
  656. N.Assign(Nodes[Index -1]);
  657. end
  658. else
  659. //add to the tail of list
  660. N := FNodes.Add;
  661. Result := N;
  662. UpdatePathLine;
  663. end;
  664. function TgxMovementPath.InsertNode(const Index: integer): TgxPathNode;
  665. var
  666. N: TgxPathNode;
  667. begin
  668. Result := nil;
  669. //Intravel, can't insert
  670. if FInTravel then
  671. exit;
  672. //Insert into the position
  673. if (Assigned(Nodes[Index])) then
  674. begin
  675. N := TgxPathNode(FNodes.Insert(Index));
  676. if Index >0 then
  677. N.Assign(Nodes[Index -1]);
  678. Result := N;
  679. end
  680. else
  681. //add to the tail of list
  682. Result := AddNode;
  683. UpdatePathLine;
  684. end;
  685. function TgxMovementPath.AddNodeFromObject(const Obj: TgxBaseSceneObject): TgxPathNode;
  686. begin
  687. Result := nil;
  688. if (FInTravel) or (not Assigned(Obj)) then
  689. exit;
  690. Result := AddNode;
  691. Result.FPosition := Obj.Position.AsVector;
  692. Result.FScale := Obj.Scale.AsVector;
  693. Result.FRotation := Obj.Rotation.AsVector;
  694. Result.FDirection:= Obj.Direction.AsVector;
  695. Result.FUp:= Obj.Up.AsVector;
  696. UpdatePathLine;
  697. end;
  698. function TgxMovementPath.InsertNodeFromObject(const Obj: TgxBaseSceneObject; const Index: integer): TgxPathNode;
  699. begin
  700. Result := nil;
  701. if (FInTravel) or (not Assigned(Obj)) then
  702. exit;
  703. Result := InsertNode(Index);
  704. Result.FPosition := Obj.Position.AsVector;
  705. Result.FScale := Obj.Scale.AsVector;
  706. Result.FRotation := Obj.Rotation.AsVector;
  707. Result.FDirection:= Obj.Direction.AsVector;
  708. Result.FUp:= Obj.Up.AsVector;
  709. UpdatePathLine;
  710. end;
  711. function TgxMovementPath.DeleteNode(const Index: integer): TgxPathNode;
  712. var
  713. Node: TgxPathNode;
  714. begin
  715. Result := nil;
  716. //Ontravel, can't delete
  717. if FInTravel then
  718. exit;
  719. Node := Nodes[Index];
  720. if Assigned(Node) then
  721. begin
  722. FNodes.Delete(Index);
  723. if FCurrentNodeIndex < 0 then
  724. exit;
  725. if (Index =0) then
  726. begin
  727. if FNodes.Count > 0 then
  728. FCurrentNodeIndex := 0
  729. else
  730. FCurrentNodeIndex := -1;
  731. end
  732. else
  733. begin
  734. //one has been deleted, so the index should be equal to FNodeList.Count
  735. if Index =FNodes.Count then
  736. FCurrentNodeIndex := Index -1
  737. else
  738. FCurrentNodeIndex := Index;
  739. end;
  740. Result := Nodes[FCurrentNodeIndex];
  741. end;
  742. UpdatePathLine;
  743. end;
  744. function TgxMovementPath.DeleteNode(const Node: TgxPathNode): TgxPathNode;
  745. var
  746. I: integer;
  747. begin
  748. Result := nil;
  749. for I := 0 to FNodes.Count - 1 do
  750. begin
  751. if Node = Nodes[I] then
  752. begin
  753. Result := DeleteNode(I);
  754. break;
  755. end;
  756. end;
  757. UpdatePathLine;
  758. end;
  759. function TgxMovementPath.PrevNode: integer;
  760. begin
  761. Result := FCurrentNodeIndex;
  762. if FNodes.Count = 0 then
  763. exit;
  764. Dec(FCurrentNodeIndex);
  765. if (FCurrentNodeIndex < 0) then
  766. FCurrentNodeIndex := 0
  767. else
  768. //this line can cause the CurrentNode generated
  769. CurrentNodeIndex := FCurrentNodeIndex;
  770. Result := FCurrentNodeIndex;
  771. end;
  772. function TgxMovementPath.NextNode: integer;
  773. begin
  774. Result := FCurrentNodeIndex;
  775. if FNodes.Count = 0 then
  776. exit;
  777. Inc(FCurrentNodeIndex);
  778. if (FCurrentNodeIndex = FNodes.Count) then
  779. Dec(FCurrentNodeIndex)
  780. else
  781. //this line can cause the CurrentNode generated
  782. CurrentNodeIndex := FCurrentNodeIndex;
  783. Result := FCurrentNodeIndex;
  784. end;
  785. function TgxMovementPath.NodeDistance(const Node1, Node2: TgxPathNode): double;
  786. begin
  787. Result := VectorDistance(Node1.FPosition, Node2.FPosition);
  788. end;
  789. //need to do
  790. //1 No acceleration implemented
  791. //2 The travel-time of a segment is based a simple linear movement, at the start and the end
  792. // of the segment, the speed will be more high than in the middle
  793. //3 Rotation Interpolation has not been tested
  794. procedure TgxMovementPath.CalculateState(const CurrentTime: double);
  795. var
  796. I: integer;
  797. SumTime: double;
  798. L, L2: single;
  799. Interpolated: boolean;
  800. T: double;
  801. a:double;
  802. procedure Interpolation(ReturnNode: TgxPathNode; Time1, Time2: double; Index: integer);
  803. var
  804. Ratio: double;
  805. x, y, z, p, t, r, sx, sy, sz: single;
  806. dx, dy, dz,ux, uy, uz: single;
  807. begin
  808. Ratio:=(Nodes[I - 1].Speed*Time2+0.5*a*time2*time2)/L + Index;
  809. MotionSplineControl.SplineXYZ(Ratio, x, y, z);
  810. RotationSplineControl.SplineXYZ(Ratio, p, t, r);
  811. ScaleSplineControl.SplineXYZ(Ratio, sx, sy, sz);
  812. DirectionSplineControl.SplineXYZ(Ratio,dx,dy,dz);
  813. UpSplineControl.SplineXYZ(Ratio,ux,uy,uz);
  814. ReturnNode.FPosition := VectorMake(x, y, z, 1);
  815. ReturnNode.FRotation := VectorMake(p, t, r, 1);
  816. ReturnNode.FScale := VectorMake(sx, sy, sz, 1);
  817. ReturnNode.FDirection := VectorMake(dx,dy,dz, 1);
  818. ReturnNode.FUp := VectorMake(ux,uy,uz, 1);
  819. end;
  820. begin
  821. I := 1;
  822. if (FInitialTime = 0) or (FInitialTime > CurrentTime) then
  823. FInitialTime := CurrentTime;
  824. if (FStartTime <> 0) and not FStartTimeApplied then
  825. begin
  826. if FInitialTime + FStartTime < CurrentTime then
  827. begin
  828. FInitialTime := CurrentTime;
  829. FStartTimeApplied := True;
  830. end
  831. else
  832. Exit;
  833. end;
  834. SumTime := FInitialTime;
  835. Interpolated := False;
  836. while I < FNodes.Count do
  837. begin
  838. L := NodeDistance(Nodes[I], Nodes[I - 1]);
  839. if L = 0 then
  840. L := VectorDistance(Nodes[i].FScale, Nodes[i-1].FScale);
  841. if L = 0 then
  842. begin
  843. L := VectorDistance(Nodes[i].FDirection, Nodes[i-1].FDirection);
  844. L2 := VectorDistance(Nodes[i].FUp, Nodes[i-1].Fup);
  845. if (L2 > L) then L:= L2;
  846. end;
  847. if L = 0 then
  848. L := Nodes[I - 0].Speed;
  849. T := L / (Nodes[I - 1].Speed + Nodes[I - 0].Speed) * 2;
  850. if (SumTime + T) >= CurrentTime then
  851. begin
  852. a:=(Nodes[I - 0].Speed-Nodes[I - 1].Speed)/T;
  853. Interpolation(FCurrentNode, T, CurrentTime - SumTime, I - 1);
  854. Interpolated := True;
  855. break;
  856. end
  857. else
  858. begin
  859. Inc(I);
  860. SumTime := SumTime + T;
  861. end;
  862. end;
  863. if (not Interpolated) then
  864. begin
  865. Interpolation(FCurrentNode, 1.0, 0.0, FNodes.Count - 1);
  866. TravelPath(False);
  867. end;
  868. end;
  869. function TgxMovementPath.CanTravel: boolean;
  870. var
  871. I: integer;
  872. begin
  873. Result := True;
  874. if FNodes.Count < 2 then
  875. begin
  876. Result := False;
  877. exit;
  878. end;
  879. for I := 0 to FNodes.Count - 1 do
  880. if Abs(Nodes[I].Speed) < 0.01 then
  881. begin
  882. Result := False;
  883. break;
  884. end;
  885. end;
  886. function TgxMovementPath.GetCollection: TgxMovementPaths;
  887. begin
  888. Result := TgxMovementPaths(GetOwner);
  889. end;
  890. function TgxMovementPath.GetMovement: TgxMovement;
  891. begin
  892. Result := GetCollection.GetMovement;
  893. end;
  894. procedure TgxMovementPath.TravelPath(const Start: boolean);
  895. var
  896. x, y, z: PFloatArray;
  897. p, t, r: PFloatArray;
  898. sx, sy, sz: PFloatArray;
  899. dx, dy, dz: PFloatArray;
  900. ux, uy, uz: PFloatArray;
  901. I: integer;
  902. begin
  903. if (FInTravel = Start) or (FNodes.Count = 0) then
  904. exit;
  905. //One of the node speed < 0.01;
  906. if (Start) and (not CanTravel) then
  907. exit;
  908. FInTravel := Start;
  909. if FInTravel then
  910. begin
  911. GetMem(x, sizeof(single) * FNodes.Count);
  912. GetMem(y, sizeof(single) * FNodes.Count);
  913. GetMem(z, sizeof(single) * FNodes.Count);
  914. GetMem(p, sizeof(single) * FNodes.Count);
  915. GetMem(t, sizeof(single) * FNodes.Count);
  916. GetMem(r, sizeof(single) * FNodes.Count);
  917. GetMem(sx, sizeof(single) * FNodes.Count);
  918. GetMem(sy, sizeof(single) * FNodes.Count);
  919. GetMem(sz, sizeof(single) * FNodes.Count);
  920. GetMem(dx, sizeof(single) * FNodes.Count);
  921. GetMem(dy, sizeof(single) * FNodes.Count);
  922. GetMem(dz, sizeof(single) * FNodes.Count);
  923. GetMem(ux, sizeof(single) * FNodes.Count);
  924. GetMem(uy, sizeof(single) * FNodes.Count);
  925. GetMem(uz, sizeof(single) * FNodes.Count);
  926. for I := 0 to FNodes.Count - 1 do
  927. begin
  928. PFloatArray(x)[I] := Nodes[I].FPosition.X;
  929. PFloatArray(y)[I] := Nodes[I].FPosition.Y;
  930. PFloatArray(z)[I] := Nodes[I].FPosition.Z;
  931. PFloatArray(p)[I] := Nodes[I].FRotation.X;
  932. PFloatArray(t)[I] := Nodes[I].FRotation.Y;
  933. PFloatArray(r)[I] := Nodes[I].FRotation.Z;
  934. PFloatArray(sx)[I] := Nodes[I].FScale.X;
  935. PFloatArray(sy)[I] := Nodes[I].FScale.Y;
  936. PFloatArray(sz)[I] := Nodes[I].FScale.Z;
  937. PFloatArray(dx)[I] := Nodes[I].FDirection.X;
  938. PFloatArray(dy)[I] := Nodes[I].FDirection.Y;
  939. PFloatArray(dz)[I] := Nodes[I].FDirection.Z;
  940. PFloatArray(ux)[I] := Nodes[I].FUp.X;
  941. PFloatArray(uy)[I] := Nodes[I].FUp.Y;
  942. PFloatArray(uz)[I] := Nodes[I].FUp.Z;
  943. end;
  944. MotionSplineControl := TCubicSpline.Create(x, y, z, nil, FNodes.Count);
  945. RotationSplineControl := TCubicSpline.Create(p, t, r, nil, FNodes.Count);
  946. ScaleSplineControl := TCubicSpline.Create(sx, sy, sz, nil, FNodes.Count);
  947. DirectionSplineControl:= TCubicSpline.Create(dx, dy, dz, nil, FNodes.Count);
  948. UpSplineControl:= TCubicSpline.Create(ux, uy, uz, nil, FNodes.Count);
  949. FreeMem(x);
  950. FreeMem(y);
  951. FreeMem(z);
  952. FreeMem(p);
  953. FreeMem(t);
  954. FreeMem(r);
  955. FreeMem(sx);
  956. FreeMem(sy);
  957. FreeMem(sz);
  958. FreeMem(dx);
  959. FreeMem(dy);
  960. FreeMem(dz);
  961. FreeMem(ux);
  962. FreeMem(uy);
  963. FreeMem(uz);
  964. FreeAndNil(FCurrentNode);
  965. FCurrentNode := TgxPathNode.Create(nil);
  966. FCurrentNode.Assign(Nodes[0]);
  967. FCurrentNodeIndex := -1;
  968. FEstimateTime := 0;
  969. for I := 1 to FNodes.Count - 1 do
  970. FEstimateTime := FEstimateTime + NodeDistance(Nodes[I], Nodes[I - 1]) / Nodes[I - 1].Speed;
  971. if Assigned(FOnTravelStart) then
  972. FOnTravelStart(self);
  973. end
  974. else
  975. begin
  976. FreeAndNil(MotionSplineControl);
  977. FreeAndNil(RotationSplineControl);
  978. FreeAndNil(ScaleSplineControl);
  979. FreeAndNil(DirectionSplineControl);
  980. FreeAndNil(UpSplineControl);
  981. if Assigned(FOnTravelStop) then
  982. FOnTravelStop(self);
  983. end;
  984. end;
  985. procedure TgxMovementPath.TravelPath(const Start: boolean; const aStartTime: double);
  986. begin
  987. if FInTravel = Start then
  988. exit;
  989. FInitialTime := aStartTime;
  990. FStartTimeApplied := False;
  991. TravelPath(Start);
  992. end;
  993. function TgxMovementPath.GetNodeCount: integer;
  994. begin
  995. Result := FNodes.Count;
  996. end;
  997. //-------------------------- This function need modified -----------------------
  998. procedure TgxMovementPath.SetStartTime(const Value: double);
  999. begin
  1000. FStartTime := Value;
  1001. end;
  1002. procedure TgxMovementPath.Assign(Source: TPersistent);
  1003. var
  1004. I: integer;
  1005. begin
  1006. if Source is TgxMovementPath then
  1007. begin
  1008. ClearNodes;
  1009. for I := 0 to TgxMovementPath(Source).NodeCount - 1 do
  1010. begin
  1011. AddNode;
  1012. Nodes[I].Assign(TgxMovementPath(Source).Nodes[I]);
  1013. FStartTime := TgxMovementPath(Source).FStartTime;
  1014. //FEstimateTime := TgxMovementPath(Source).FEstimateTime;
  1015. FLooped := TgxMovementPath(Source).FLooped;
  1016. FRotationMode := TgxMovementPath(Source).FRotationMode;
  1017. end;
  1018. end;
  1019. end;
  1020. function TgxMovementPath.AddNode: TgxPathNode;
  1021. var
  1022. Node: TgxPathNode;
  1023. I: integer;
  1024. begin
  1025. //Add a empty node, if it's not the first one, try locate the node to the previous one
  1026. Node := FNodes.Add;
  1027. I := FNodes.Count;
  1028. if I > 1 then
  1029. Node.Assign(Nodes[I - 2]);
  1030. Result := Node;
  1031. end;
  1032. function TgxMovementPath.AddNode(const Node: TgxPathNode): TgxPathNode;
  1033. begin
  1034. Result := AddNode;
  1035. if Assigned(Node) then
  1036. Result.Assign(Node);
  1037. end;
  1038. //------------------------- TgxMovementPaths ----------------------------------
  1039. constructor TgxMovementPaths.Create(aOwner: TgxMovement);
  1040. begin
  1041. inherited Create(aOwner, TgxMovementPath);
  1042. end;
  1043. procedure TgxMovementPaths.SetItems(const index: integer; const val: TgxMovementPath);
  1044. begin
  1045. inherited Items[index] := val;
  1046. end;
  1047. function TgxMovementPaths.GetItems(const index: integer): TgxMovementPath;
  1048. begin
  1049. Result := TgxMovementPath(inherited Items[index]);
  1050. end;
  1051. function TgxMovementPaths.Add: TgxMovementPath;
  1052. begin
  1053. Result := (inherited Add) as TgxMovementPath;
  1054. end;
  1055. function TgxMovementPaths.FindItemID(const ID: integer): TgxMovementPath;
  1056. begin
  1057. Result := (inherited FindItemID(ID)) as TgxMovementPath;
  1058. end;
  1059. procedure TgxMovementPaths.NotifyChange;
  1060. begin
  1061. // Do nothing here.
  1062. end;
  1063. function TgxMovementPaths.GetMovement: TgxMovement;
  1064. begin
  1065. Result := TgxMovement(GetOwner);
  1066. end;
  1067. //--------------------------- TgxMovement --------------------------------------
  1068. constructor TgxMovement.Create(aOwner: TXCollection);
  1069. begin
  1070. inherited Create(aOwner);
  1071. FPaths := TgxMovementPaths.Create(Self);
  1072. FAutoStartNextPath := True;
  1073. FActivePathIndex := -1;
  1074. FOnAllPathTravelledOver := nil;
  1075. FOnPathTravelStart := nil;
  1076. FOnPathTravelStop := nil;
  1077. end;
  1078. destructor TgxMovement.Destroy;
  1079. begin
  1080. ClearPaths;
  1081. FPaths.Free;
  1082. inherited Destroy;
  1083. end;
  1084. procedure TgxMovement.WriteToFiler(writer : TWriter);
  1085. var
  1086. WriteStuff: boolean;
  1087. I: Integer;
  1088. begin
  1089. with Writer do
  1090. begin
  1091. // Archive Version 1, added inherited call
  1092. WriteInteger(1);
  1093. inherited;
  1094. WriteStuff := (FPaths.Count>0) or (not FAutoStartNextPath) or (FActivePathIndex<>-1);
  1095. WriteBoolean(WriteStuff);
  1096. if WriteStuff then
  1097. begin
  1098. WriteBoolean(FAutoStartNextPath);
  1099. WriteInteger(FActivePathIndex);
  1100. WriteInteger(FPaths.Count);
  1101. for I:=0 to FPaths.Count-1 do
  1102. FPaths.Items[I].WriteToFiler(Writer);
  1103. end;
  1104. end;
  1105. end;
  1106. procedure TgxMovement.ReadFromFiler(reader : TReader);
  1107. var
  1108. I: Integer;
  1109. Count: Integer;
  1110. Path: TgxMovementPath;
  1111. archiveVersion: Integer;
  1112. begin
  1113. ClearPaths;
  1114. with Reader do
  1115. begin
  1116. archiveVersion := ReadInteger;
  1117. if archiveVersion >= 1 then
  1118. inherited;
  1119. if ReadBoolean then
  1120. begin
  1121. FAutoStartNextPath := ReadBoolean;
  1122. FActivePathIndex := ReadInteger;
  1123. Count := ReadInteger;
  1124. for I:=0 to Count-1 do
  1125. begin
  1126. Path := AddPath;
  1127. Path.ReadFromFiler(Reader);
  1128. end;
  1129. end else
  1130. begin
  1131. FAutoStartNextPath := True;
  1132. FActivePathIndex := -1;
  1133. end;
  1134. end;
  1135. end;
  1136. procedure TgxMovement.ClearPaths;
  1137. begin
  1138. StopPathTravel;
  1139. FPaths.Clear;
  1140. FActivePathIndex := -1;
  1141. end;
  1142. procedure TgxMovement.PathTravelStart(Sender: TObject);
  1143. begin
  1144. if Assigned(FOnPathTravelStart) then
  1145. FOnPathTravelStart(Self, TgxMovementPath(Sender));
  1146. end;
  1147. procedure TgxMovement.PathTravelStop(Sender: TObject);
  1148. begin
  1149. if Assigned(FOnPathTravelStop) then
  1150. FOnPathTravelStop(Self, TgxMovementPath(Sender), TgxMovementPath(Sender).FLooped);
  1151. if TgxMovementPath(Sender).FLooped then
  1152. begin
  1153. //if looped, then re-start the path
  1154. StartPathTravel;
  1155. end
  1156. else if (FActivePathIndex = FPaths.Count - 1) then
  1157. begin
  1158. if (Assigned(FOnAllPathTravelledOver)) then
  1159. FOnAllPathTravelledOver(Self);
  1160. end
  1161. else //auto-start next path
  1162. if FAutoStartNextPath then
  1163. begin
  1164. Inc(FActivePathIndex);
  1165. StartPathTravel;
  1166. end;
  1167. end;
  1168. function TgxMovement.GetSceneObject: TgxBaseSceneObject;
  1169. begin
  1170. Result := TgxBaseSceneObject(Owner{TgxBehavours}.Owner);
  1171. end;
  1172. function TgxMovement.AddPath: TgxMovementPath;
  1173. var
  1174. Path: TgxMovementPath;
  1175. begin
  1176. Path := FPaths.Add;
  1177. Path.OnTravelStart := PathTravelStart;
  1178. Path.OnTravelStop := PathTravelStop;
  1179. Result := Path;
  1180. end;
  1181. function TgxMovement.AddPath(aObject: TgxBaseSceneObject): TgxMovementPath;
  1182. begin
  1183. Result := AddPath;
  1184. Result.AddNodeFromObject(aObject);
  1185. end;
  1186. function TgxMovement.AddPath(Path: TgxMovementPath): TgxMovementPath;
  1187. begin
  1188. Result := AddPath;
  1189. if Assigned(Path) then
  1190. Result.Assign(Path);
  1191. end;
  1192. function TgxMovement.DeletePath: TgxMovementPath;
  1193. begin
  1194. Result := DeletePath(FActivePathIndex);
  1195. end;
  1196. function TgxMovement.DeletePath(Path: TgxMovementPath): TgxMovementPath;
  1197. var
  1198. I: integer;
  1199. begin
  1200. Result := nil;
  1201. for I := 0 to FPaths.Count - 1 do
  1202. begin
  1203. if Path = Paths[I] then
  1204. begin
  1205. Result := DeletePath(I);
  1206. break;
  1207. end;
  1208. end;
  1209. end;
  1210. function TgxMovement.DeletePath(Index: integer): TgxMovementPath;
  1211. begin
  1212. Result := nil;
  1213. if (Index <0) or (Index >=FPaths.Count) then
  1214. exit;
  1215. if Index >=0 then
  1216. begin
  1217. TgxMovementPath(FPaths[Index]).Free;
  1218. FPaths.Delete(Index);
  1219. if FActivePathIndex < 0 then
  1220. exit;
  1221. if (Index =0) then
  1222. begin
  1223. if FPaths.Count > 0 then
  1224. FActivePathIndex := 0
  1225. else
  1226. FActivePathIndex := -1;
  1227. end
  1228. else
  1229. begin
  1230. //one has been deleted, so the index should be equal to FPathList.Count
  1231. if Index =FPaths.Count then
  1232. FActivePathIndex := Index -1
  1233. else
  1234. FActivePathIndex := Index;
  1235. end;
  1236. Result := ActivePath;
  1237. end;
  1238. end;
  1239. procedure TgxMovement.SetActivePathIndex(Value: integer);
  1240. begin
  1241. if FActivePathIndex = Value then
  1242. exit;
  1243. //if current has a Active path in travelling, then exit the method
  1244. if (Assigned(ActivePath)) and (ActivePath.InTravel) then
  1245. exit;
  1246. if (Value >= 0) and (Value < FPaths.Count) then
  1247. begin
  1248. FActivePathIndex := Value;
  1249. //Start the new path or wait for the start-command
  1250. end
  1251. else if Value < 0 then
  1252. begin
  1253. FActivePathIndex := -1;
  1254. //Stop all the running path
  1255. end;
  1256. end;
  1257. function TgxMovement.NextPath: integer;
  1258. begin
  1259. ActivePathIndex := FActivePathIndex + 1;
  1260. Result := FActivePathIndex;
  1261. end;
  1262. function TgxMovement.PrevPath: integer;
  1263. begin
  1264. ActivePathIndex := FActivePathIndex - 1;
  1265. if (FActivePathIndex < 0) and (FPaths.Count > 0) then
  1266. Result := 0
  1267. else
  1268. Result := FActivePathIndex;
  1269. end;
  1270. function TgxMovement.FirstPath: integer;
  1271. begin
  1272. if FPaths.Count > 0 then
  1273. FActivePathIndex := 0;
  1274. Result := FActivePathIndex;
  1275. end;
  1276. function TgxMovement.LastPath: integer;
  1277. begin
  1278. if FPaths.Count > 0 then
  1279. FActivePathIndex := FPaths.Count - 1;
  1280. Result := FActivePathIndex;
  1281. end;
  1282. function TgxMovement.GetActivePath: TgxMovementPath;
  1283. begin
  1284. if FActivePathIndex >= 0 then
  1285. Result := Paths[FActivePathIndex]
  1286. else
  1287. Result := nil;
  1288. end;
  1289. procedure TgxMovement.SetActivePath(Value: TgxMovementPath);
  1290. var
  1291. I: integer;
  1292. begin
  1293. ActivePathIndex := -1;
  1294. for I := 0 to FPaths.Count - 1 do
  1295. begin
  1296. if Value = Paths[I] then
  1297. begin
  1298. ActivePathIndex := I;
  1299. break;
  1300. end;
  1301. end;
  1302. end;
  1303. function TgxMovement.GetPathCount: integer;
  1304. begin
  1305. Result := FPaths.Count;
  1306. end;
  1307. procedure TgxMovement.Assign(Source: TPersistent);
  1308. var
  1309. I: integer;
  1310. begin
  1311. if Source is TgxMovement then
  1312. begin
  1313. ClearPaths;
  1314. for I := 0 to TgxMovement(Source).PathCount - 1 do
  1315. begin
  1316. AddPath;
  1317. Paths[I].Assign(TgxMovement(Source).Paths[I]);
  1318. end;
  1319. FAutoStartNextPath := TgxMovement(Source).FAutoStartNextPath;
  1320. end;
  1321. end;
  1322. class function TgxMovement.FriendlyName: string;
  1323. begin
  1324. Result := 'Movement controls'
  1325. end;
  1326. class function TgxMovement.FriendlyDescription: string;
  1327. begin
  1328. Result := 'Object movement path controls'
  1329. end;
  1330. class function TgxMovement.UniqueItem: boolean;
  1331. begin
  1332. Result := True;
  1333. end;
  1334. procedure TgxMovement.StartPathTravel;
  1335. begin
  1336. if FActivePathIndex < 0 then
  1337. exit;
  1338. //convert the time to second
  1339. Paths[FActivePathIndex].TravelPath(True, 0);
  1340. end;
  1341. procedure TgxMovement.StopPathTravel;
  1342. var
  1343. I: Integer;
  1344. begin
  1345. if FPaths.Count <> 0 then
  1346. for I := 0 to FPaths.Count - 1 do
  1347. Paths[I].TravelPath(False);
  1348. end;
  1349. //Calculate functions add into this method
  1350. procedure TgxMovement.DoProgress(const progressTime : TgxProgressTimes);
  1351. var
  1352. Path: TgxMovementPath;
  1353. begin
  1354. if (FActivePathIndex >= 0) and (Paths[FActivePathIndex].InTravel) then
  1355. begin
  1356. Path := Paths[FActivePathIndex];
  1357. Path.CalculateState(progressTime.newTime);
  1358. if Assigned(Path.CurrentNode) then
  1359. begin
  1360. if Owner.Owner is TgxBaseSceneObject then
  1361. with TgxBaseSceneObject(Owner.Owner) do
  1362. begin
  1363. Position.AsVector := Path.CurrentNode.FPosition;
  1364. Scale.AsVector := Path.CurrentNode.FScale;
  1365. case Path.FRotationMode of
  1366. rmTurnPitchRoll:
  1367. begin
  1368. PitchAngle := Path.CurrentNode.PitchAngle;
  1369. TurnAngle := Path.CurrentNode.TurnAngle;
  1370. RollAngle := Path.CurrentNode.RollAngle;
  1371. end;
  1372. rmUpDirection:
  1373. begin
  1374. Direction.AsVector := Path.CurrentNode.FDirection;
  1375. Up.AsVector := Path.CurrentNode.FUp;
  1376. end;
  1377. else
  1378. Assert(False, strErrorEx + strUnknownType);
  1379. end
  1380. end;
  1381. end;
  1382. end;
  1383. end;
  1384. function GetMovement(const behaviours: TgxBehaviours): TgxMovement; overload;
  1385. var
  1386. i: integer;
  1387. begin
  1388. i := behaviours.IndexOfClass(TgxMovement);
  1389. if i >= 0 then
  1390. Result := TgxMovement(behaviours[i])
  1391. else
  1392. Result := nil;
  1393. end;
  1394. function GetMovement(const obj: TgxBaseSceneObject): TgxMovement; overload;
  1395. begin
  1396. Result := GetMovement(obj.behaviours);
  1397. end;
  1398. function GetOrCreateMovement(const behaviours: TgxBehaviours): TgxMovement; overload;
  1399. var
  1400. i: integer;
  1401. begin
  1402. i := behaviours.IndexOfClass(TgxMovement);
  1403. if i >= 0 then
  1404. Result := TgxMovement(behaviours[i])
  1405. else
  1406. Result := TgxMovement.Create(behaviours);
  1407. end;
  1408. function GetOrCreateMovement(const obj: TgxBaseSceneObject): TgxMovement; overload;
  1409. begin
  1410. Result := GetOrCreateMovement(obj.behaviours);
  1411. end;
  1412. procedure StartStopTravel(const Obj: TgxBaseSceneObject; Start: Boolean; ChangeCameras, ChangeObjects: Boolean);
  1413. var
  1414. NewObj: TgxBaseSceneObject;
  1415. I: Integer;
  1416. Movement: TgxMovement;
  1417. begin
  1418. if ((Obj is TgxCamera)and(ChangeCameras))or
  1419. ((not(Obj is TgxCamera))and(ChangeObjects)) then
  1420. begin
  1421. Movement := GetMovement(Obj);
  1422. if Assigned(Movement) then
  1423. if Start then
  1424. begin
  1425. if (Movement.PathCount>0) and (Movement.ActivePathIndex=-1) then
  1426. Movement.ActivePathIndex := 0;
  1427. Movement.StartPathTravel;
  1428. end else
  1429. Movement.StopPathTravel;
  1430. end;
  1431. for I:=0 to Obj.Count-1 do
  1432. begin
  1433. NewObj := Obj.Children[I];
  1434. StartStopTravel(NewObj, Start, ChangeCameras, ChangeObjects);
  1435. end;
  1436. end;
  1437. procedure StartAllMovements(const Scene: TgxScene; const StartCamerasMove, StartObjectsMove: Boolean);
  1438. begin
  1439. if Assigned(Scene) then
  1440. begin
  1441. if StartCamerasMove or StartObjectsMove then
  1442. StartStopTravel(Scene.Objects, True, StartCamerasMove, StartObjectsMove);
  1443. end;
  1444. end;
  1445. procedure StopAllMovements(const Scene: TgxScene; const StopCamerasMove, StopObjectsMove: Boolean);
  1446. begin
  1447. if Assigned(Scene) then
  1448. begin
  1449. if StopCamerasMove or StopObjectsMove then
  1450. StartStopTravel(Scene.Objects, False, StopCamerasMove, StopObjectsMove);
  1451. end;
  1452. end;
  1453. // ------------------------------------------------------------------
  1454. initialization
  1455. // ------------------------------------------------------------------
  1456. RegisterXCollectionItemClass(TgxMovement);
  1457. finalization
  1458. UnregisterXCollectionItemClass(TgxMovement);
  1459. end.