Physics.SPIManager.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit Physics.SPIManager;
  5. (* The Manager for Scene Physics Interactions (SPI) *)
  6. interface
  7. uses
  8. System.Classes,
  9. System.SysUtils,
  10. Vcl.Dialogs,
  11. GLS.XCollection,
  12. GLS.VectorGeometry,
  13. GLS.Scene,
  14. Physics.SPIForces,
  15. GLS.Behaviours;
  16. type
  17. // only ssEuler is usable at the moment
  18. TDESolverType = (ssEuler, ssRungeKutta4, ssVerlet);
  19. // TDESolver = procedure((*RigidBody:TGLRigidBody;*)DeltaTime:Real) of object;
  20. TStateArray = Array of Real;
  21. TGLSPIManager = class;
  22. (*
  23. ***Euler***, EulerImproved, EulerModified, MidPoint
  24. RungeKutta2, ***RungeKutta4***, RungKutta4Adaptive
  25. State Variables: Position, Velocity
  26. Verlet
  27. State Variables: Position, Old Position
  28. *)
  29. // need to have state array(s) seperate from inertias to allow for implicit & explicit methods
  30. TDESolver = class(TObject)
  31. public
  32. StateSize: Integer;
  33. StateArray: TStateArray;
  34. Owner: TGLSPIManager;
  35. function StateToArray(): TStateArray; virtual;
  36. procedure ArrayToState(StateArray: TStateArray); virtual;
  37. procedure Solve(DeltaTime: Real); virtual; abstract;
  38. constructor Create(aOwner: TGLSPIManager); // override; //abstract;
  39. destructor Destroy; override;
  40. // procedure Assign(Source: TPersistent); override;
  41. end;
  42. // explicit e.g. Euler, Mid-point, Runge-Kutta integration
  43. TDESolverExplicit = class(TDESolver)
  44. public
  45. StateArrayDot: TStateArray; // Velocity stored
  46. function CalcStateDot(): TStateArray; virtual;
  47. end;
  48. TDESolverEuler = class(TDESolverExplicit)
  49. public
  50. procedure Solve(DeltaTime: Real); override;
  51. end;
  52. TDESolverRungeKutta4 = class(TDESolverExplicit)
  53. public
  54. procedure Solve(DeltaTime: Real); override;
  55. end;
  56. // implicit e.g. Verlet Integration
  57. TDESolverImplicit = class(TDESolver)
  58. public
  59. LastStateArray: TStateArray; // Last state stored
  60. end;
  61. TDESolverVerlet = class(TDESolverImplicit)
  62. public
  63. end;
  64. TGLForces = class;
  65. TGLBaseForceFieldEmitter = class;
  66. // TGLSPIManager = class;
  67. (* purpose of TGLBaseInertia is to allow for inertias that may be constrained
  68. to 1 or 2 dimensions
  69. Shouldn't be used directly, instead use TGLParticleInertia (for a 3D particle)
  70. TGLRigidBodyInertia (for a 3D rigid-body) or define a new sub-class
  71. e.g. TGL1DParticleInertia, this will allow for faster speed *)
  72. TGLBaseInertia = class(TGLBehaviour)
  73. private
  74. FDampingEnabled: Boolean;
  75. FManager: TGLSPIManager;
  76. FManagerName: String; // NOT persistent, temporarily used for persistence
  77. protected
  78. procedure Loaded; override;
  79. procedure WriteToFiler(writer: TWriter); override;
  80. procedure ReadFromFiler(reader: TReader); override;
  81. public
  82. StateSize: Integer; // don't re-declare this in sub-classes
  83. // just initialise it in constructor
  84. procedure StateToArray(var StateArray: TStateArray;
  85. StatePos: Integer); virtual;
  86. procedure ArrayToState( { var } StateArray: TStateArray;
  87. StatePos: Integer); virtual;
  88. procedure CalcStateDot(var StateArray: TStateArray;
  89. StatePos: Integer); virtual;
  90. procedure RemoveForces(); virtual;
  91. procedure CalculateForceFieldForce(ForceFieldEmitter
  92. : TGLBaseForceFieldEmitter); virtual;
  93. procedure CalcAuxiliary(); virtual;
  94. procedure SetUpStartingState(); virtual;
  95. function CalculateKE(): Real; virtual;
  96. function CalculatePE(): Real; virtual;
  97. constructor Create(aOwner: TXCollection); override; // abstract;
  98. destructor Destroy; override;
  99. procedure Assign(Source: TPersistent); override;
  100. procedure SetManager(const val: TGLSPIManager);
  101. published
  102. property DampingEnabled: Boolean read FDampingEnabled write FDampingEnabled;
  103. property Manager: TGLSPIManager read FManager write SetManager;
  104. end;
  105. (* A base for different types of force-field behaviours *)
  106. TGLBaseForceFieldEmitter = class(TGLBehaviour)
  107. private
  108. FManager: TGLSPIManager;
  109. FManagerName: String; // NOT persistent, temporarily used for persistence
  110. protected
  111. procedure Loaded; override;
  112. procedure WriteToFiler(writer: TWriter); override;
  113. procedure ReadFromFiler(reader: TReader); override;
  114. public
  115. constructor Create(aOwner: TXCollection); override; // abstract;
  116. destructor Destroy; override;
  117. procedure Assign(Source: TPersistent); override;
  118. procedure SetManager(const val: TGLSPIManager);
  119. function CalculateForceField(Body: TGLBaseSceneObject): TAffineVector; virtual;
  120. published
  121. property Manager: TGLSPIManager read FManager write SetManager;
  122. end;
  123. (* The Simple Physics Interaction (SPI) manager can only deal with objects from one scene
  124. More than one physics manager can be assigned to a scene *)
  125. TGLSPIManager = class(TComponent)
  126. // StateSize:Integer;
  127. protected
  128. fInertias: TList; // list of all inertias with manager = self
  129. fForceFieldEmitters: TList; // list of all forcefield emitters
  130. fForces: TGLForces; // Collection of forces acting on/between objects
  131. fDESolverType: TDESolverType;
  132. DESolver: TDESolver;
  133. fScene: TGLScene;
  134. protected
  135. procedure Loaded; override;
  136. procedure DefineProperties(Filer: TFiler); override;
  137. procedure WriteForces(stream: TStream);
  138. procedure ReadForces(stream: TStream);
  139. procedure SetForces(const val: TGLForces);
  140. function GetForces: TGLForces;
  141. procedure SetInertias(const val: TList);
  142. procedure SetForceFieldEmitters(const val: TList);
  143. procedure SetScene(const val: TGLScene);
  144. public
  145. procedure RegisterInertia(aInertia: TGLBaseInertia);
  146. procedure DeRegisterInertia(aInertia: TGLBaseInertia);
  147. procedure DeRegisterAllInertias;
  148. procedure RegisterForceFieldEmitter(aForceField: TGLBaseForceFieldEmitter);
  149. procedure DeRegisterForceFieldEmitter(aForceField: TGLBaseForceFieldEmitter);
  150. procedure DeRegisterAllForceFieldEmitters;
  151. procedure Notification(AComponent: TComponent;
  152. Operation: TOperation); override;
  153. constructor Create(aOwner: TComponent); override;
  154. destructor Destroy; override;
  155. procedure Assign(Source: TPersistent); override;
  156. procedure CalculateNextState(DeltaTime: Real);
  157. function CalculateKE(): Real;
  158. function CalculatePE(): Real;
  159. procedure SetDESolver(SolverType: TDESolverType);
  160. function FindObjectByName(Name: String): TGLBaseSceneObject;
  161. function FindForceFieldEmitterByName(Name: String): TGLBaseSceneObject;
  162. property Inertias: TList read fInertias write SetInertias; // stored False;
  163. property ForceFieldEmitters: TList read fForceFieldEmitters
  164. write SetForceFieldEmitters; // stored False;
  165. published
  166. property Forces: TGLForces read GetForces write SetForces; // stored False;
  167. property Solver: TDESolverType read fDESolverType write SetDESolver;
  168. property Scene: TGLScene read fScene write SetScene;
  169. end;
  170. TGLForces = class(TXCollection)
  171. protected
  172. function GetForce(index: Integer): TGLForce;
  173. public
  174. constructor Create(aOwner: TPersistent); override;
  175. // destructor Destroy;override;
  176. class function ItemsClass: TXCollectionItemClass; override;
  177. property Force[index: Integer]: TGLForce read GetForce; default;
  178. function CanAdd(aClass: TXCollectionItemClass): Boolean; override;
  179. end;
  180. // ------------------------------------------------------------------
  181. implementation
  182. // ------------------------------------------------------------------
  183. procedure TGLSPIManager.Notification(AComponent: TComponent;
  184. Operation: TOperation);
  185. begin
  186. (* if Operation=opRemove then
  187. begin
  188. if AComponent=FScene then FScene:=nil;
  189. end;
  190. *)
  191. end;
  192. procedure TGLSPIManager.DefineProperties(Filer: TFiler);
  193. begin
  194. inherited DefineProperties(Filer);
  195. Filer.DefineBinaryProperty('ForcesData', ReadForces, WriteForces,
  196. (Assigned(fForces) and (fForces.Count > 0)));
  197. end;
  198. procedure TGLSPIManager.Loaded;
  199. begin
  200. inherited Loaded;
  201. if Assigned(fForces) then
  202. fForces.Loaded;
  203. end;
  204. function TGLSPIManager.FindObjectByName(Name: String): TGLBaseSceneObject;
  205. var
  206. i: Integer;
  207. begin
  208. Result := nil;
  209. for i := 0 to fInertias.Count - 1 do
  210. begin
  211. if (TGLBaseInertia(fInertias.Items[i]).OwnerBaseSceneObject.GetNamePath =
  212. Name) then
  213. begin
  214. Result := TGLBaseInertia(fInertias.Items[i]).OwnerBaseSceneObject;
  215. end
  216. else if Owner.FindComponent(Name) <> nil then
  217. begin
  218. Result := TGLBaseSceneObject(Owner.FindComponent(Name));
  219. end;
  220. end;
  221. end;
  222. function TGLSPIManager.FindForceFieldEmitterByName(Name: String)
  223. : TGLBaseSceneObject;
  224. var
  225. i: Integer;
  226. begin
  227. Result := nil;
  228. for i := 0 to fForceFieldEmitters.Count - 1 do
  229. begin
  230. if (TGLBaseForceFieldEmitter(fForceFieldEmitters.Items[i])
  231. .OwnerBaseSceneObject.GetNamePath = Name) then
  232. begin
  233. Result := TGLBaseForceFieldEmitter(fForceFieldEmitters.Items[i])
  234. .OwnerBaseSceneObject;
  235. end;
  236. end;
  237. end;
  238. procedure TGLSPIManager.WriteForces(stream: TStream);
  239. var
  240. writer: TWriter;
  241. begin
  242. // messagedlg('Writing forces',mtInformation,[mbOk],0);
  243. writer := TWriter.Create(stream, 16384);
  244. try
  245. Forces.WriteToFiler(writer);
  246. finally
  247. writer.Free;
  248. end;
  249. end;
  250. procedure TGLSPIManager.ReadForces(stream: TStream);
  251. var
  252. reader: TReader;
  253. begin
  254. reader := TReader.Create(stream, 16384);
  255. try
  256. Forces.ReadFromFiler(reader);
  257. finally
  258. reader.Free;
  259. end;
  260. end;
  261. procedure TGLSPIManager.SetForces(const val: TGLForces);
  262. begin
  263. Forces.Assign(val);
  264. end;
  265. procedure TGLSPIManager.SetInertias(const val: TList);
  266. begin
  267. fInertias.Assign(val);
  268. end;
  269. procedure TGLSPIManager.SetForceFieldEmitters(const val: TList);
  270. begin
  271. fForceFieldEmitters.Assign(val);
  272. end;
  273. procedure TGLSPIManager.SetScene(const val: TGLScene);
  274. begin
  275. // fScene:=val;
  276. if fScene <> val then
  277. begin
  278. if Assigned(fScene) then
  279. fScene.RemoveFreeNotification(Self);
  280. fScene := val;
  281. if Assigned(fScene) then
  282. fScene.FreeNotification(Self);
  283. end;
  284. end;
  285. function TGLSPIManager.GetForces: TGLForces;
  286. begin
  287. if not Assigned(fForces) then
  288. fForces := TGLForces.Create(Self);
  289. Result := fForces;
  290. end;
  291. // Not accurate yet, because Forces should be re-calculated for each KVector.
  292. // Since forces will depend on distances between objects, then this will require
  293. // a central physics manager, that calculates KVector for all objects, then calculate forces
  294. // between objects for this new estimated state.
  295. //
  296. function TDESolver.StateToArray(): TStateArray;
  297. var
  298. i { ,j } : Integer;
  299. currentpos: Integer;
  300. // state:TStateArray;
  301. begin
  302. currentpos := 0;
  303. for i := 0 to Owner.fInertias.Count - 1 do
  304. begin
  305. TGLBaseInertia(Owner.fInertias.Items[i]).StateToArray(StateArray,
  306. currentpos);
  307. currentpos := currentpos + TGLBaseInertia(Owner.fInertias.Items[i])
  308. .StateSize;
  309. end;
  310. Result := StateArray;
  311. end;
  312. procedure TDESolver.ArrayToState(StateArray: TStateArray);
  313. var
  314. i: Integer;
  315. currentpos: Integer;
  316. begin
  317. currentpos := 0;
  318. for i := 0 to Owner.fInertias.Count - 1 do
  319. begin
  320. TGLBaseInertia(Owner.fInertias.Items[i]).ArrayToState(StateArray,
  321. currentpos);
  322. currentpos := currentpos + TGLBaseInertia(Owner.fInertias.Items[i])
  323. .StateSize;
  324. end;
  325. end;
  326. constructor TDESolver.Create(aOwner: TGLSPIManager);
  327. begin
  328. Self.Owner := aOwner;
  329. end;
  330. destructor TDESolver.Destroy;
  331. begin
  332. //
  333. end;
  334. function TDESolverExplicit.CalcStateDot(): TStateArray;
  335. var
  336. i { ,j } : Integer;
  337. currentpos: Integer;
  338. state: TStateArray;
  339. begin
  340. //
  341. SetLength(state, StateSize);
  342. for i := 0 to StateSize - 1 do
  343. state[i] := StateArray[i];
  344. // state:=StateArray;
  345. currentpos := 0;
  346. for i := 0 to Owner.fInertias.Count - 1 do
  347. begin
  348. TGLBaseInertia(Owner.fInertias.Items[i]).CalcStateDot(state, currentpos);
  349. currentpos := currentpos + TGLBaseInertia(Owner.fInertias.Items[i])
  350. .StateSize;
  351. end;
  352. Result := state;
  353. end;
  354. procedure TDESolverRungeKutta4.Solve(DeltaTime: Real);
  355. var
  356. // X,X0:TStateArray;
  357. Kvectors: array [0 .. 3] of TStateArray;
  358. n: Integer;
  359. StateArray0: TStateArray;
  360. tempStateArray: TStateArray;
  361. // tempState:TGLBInertia;
  362. begin
  363. // tempState:=TGLBInertia.Create(nil);
  364. // tempState.Assign(Self);
  365. tempStateArray := StateToArray();
  366. StateArray0 := tempStateArray;
  367. for n := 0 to 3 do
  368. SetLength(Kvectors[n], Length(StateArray0));
  369. Kvectors[0] := CalcStateDot();
  370. for n := 0 to StateSize - 1 do
  371. tempStateArray[n] := tempStateArray[n] + DeltaTime / 2 * Kvectors[0][n];
  372. ArrayToState(tempStateArray);
  373. Kvectors[1] := CalcStateDot();
  374. for n := 0 to StateSize - 1 do
  375. tempStateArray[n] := tempStateArray[n] + DeltaTime / 2 * Kvectors[1][n];
  376. ArrayToState(tempStateArray);
  377. Kvectors[2] := CalcStateDot();
  378. for n := 0 to StateSize - 1 do
  379. tempStateArray[n] := tempStateArray[n] + DeltaTime / 2 * Kvectors[2][n];
  380. ArrayToState(tempStateArray);
  381. Kvectors[3] := CalcStateDot();
  382. for n := 0 to StateSize - 1 do
  383. begin
  384. tempStateArray[n] := StateArray0[n] + DeltaTime / 6 *
  385. (Kvectors[0][n] + 2 * Kvectors[1][n] + 2 * Kvectors[2][n] +
  386. Kvectors[3][n]);
  387. end;
  388. ArrayToState(tempStateArray);
  389. // NormalizeQuaternion(AngularOrientation);
  390. // tempState.Free();
  391. end;
  392. procedure TDESolverEuler.Solve(DeltaTime: Real);
  393. var
  394. i, j: Integer;
  395. tempState, tempStateDot: TStateArray;
  396. // force1:TAffineVector;
  397. Inertia1: TGLBaseInertia;
  398. tempForce: TAffineVector;
  399. // UnDampedMomentum,DampedMomentum:Real;
  400. begin
  401. {$IFDEF DEBUG}
  402. messagedlg('Euler integration', mtinformation, [mbok], 0);
  403. {$ENDIF}
  404. for i := 0 to Owner.fInertias.Count - 1 do
  405. begin
  406. Inertia1 := TGLBaseInertia(Owner.fInertias.Items[i]);
  407. // TGLRigidBodyInertia(FObjects.Items[i]).SetTorque(0,0,0);
  408. for j := 0 to Owner.fForceFieldEmitters.Count - 1 do
  409. begin
  410. Inertia1.CalculateForceFieldForce
  411. (TGLBaseForceFieldEmitter(Owner.fForceFieldEmitters.Items[j]));
  412. // Inertia1.ApplyForce(TGLForceFieldEmitter(FForceFieldEmitters.Items[j]).CalculateForceField(Inertia1.OwnerBaseSceneObject));
  413. end;
  414. end;
  415. for i := 0 to Owner.Forces.Count - 1 do
  416. begin
  417. { force1:= } Owner.Forces.Force[i].CalculateForce();
  418. end;
  419. tempState := StateToArray();
  420. tempStateDot := CalcStateDot();
  421. for i := 0 to StateSize - 1 do
  422. tempState[i] := tempState[i] + DeltaTime * tempStateDot[i];
  423. ArrayToState(tempState);
  424. for i := 0 to Owner.fInertias.Count - 1 do
  425. begin
  426. // TGLInertia(FObjects.Items[i]).SetForce(0,0,0);
  427. Inertia1 := TGLBaseInertia(Owner.fInertias.Items[i]);
  428. if Inertia1.DampingEnabled = true then
  429. begin
  430. // UnDampedMomentum:=VectorLength(Inertia1.TranslationSpeed.AsAffineVector);
  431. // DampedMomentum:= Inertia1.TranslationDamping.Calculate(UnDampedMomentum,deltaTime);
  432. // if UnDampedMomentum<>0 then
  433. begin
  434. // ScaleVector(Inertia1.TranslationSpeed.AsAffineVector,DampedMomentum/UnDampedMomentum);
  435. // ScaleVector(Inertia1.LinearMomentum,DampedMomentum/UnDampedMomentum);
  436. end;
  437. // Inertia1.TranslationDamping.Calculate(VectorLength(Inertia1.LinearMomentum),deltaTime);
  438. end;
  439. Inertia1.CalcAuxiliary();
  440. Inertia1.RemoveForces();
  441. end;
  442. // NormalizeQuaternion(AngularOrientation);
  443. end;
  444. constructor TGLSPIManager.Create(aOwner: TComponent);
  445. begin
  446. inherited Create(aOwner);
  447. fInertias := TList.Create();
  448. fForceFieldEmitters := TList.Create();
  449. fForces := TGLForces.Create(Self);
  450. SetDESolver(ssEuler);
  451. ///RegisterManager(Self);
  452. end;
  453. destructor TGLSPIManager.Destroy;
  454. begin
  455. // fScene:=nil;
  456. DeRegisterAllInertias();
  457. DeRegisterAllForceFieldEmitters();
  458. /// DeRegisterManager(Self);
  459. fInertias.Free();
  460. fForceFieldEmitters.Free();
  461. fForces.Free();
  462. inherited Destroy;
  463. end;
  464. procedure TGLSPIManager.Assign(Source: TPersistent);
  465. begin
  466. inherited Assign(Source);
  467. end;
  468. procedure TGLSPIManager.SetDESolver(SolverType: TDESolverType);
  469. var
  470. tempSolver: TDESolver;
  471. begin
  472. if Assigned(DESolver) then
  473. begin
  474. if (fDESolverType <> SolverType) then
  475. case SolverType of
  476. ssRungeKutta4:
  477. begin
  478. // DESolver:=RungeKutta4;
  479. end;
  480. ssEuler:
  481. begin
  482. // DESolver:=Euler;
  483. end;
  484. end;
  485. end
  486. else
  487. begin
  488. // if (fDESolverType<>SolverType) then
  489. case SolverType of
  490. ssRungeKutta4:
  491. begin
  492. DESolver := TDESolverRungeKutta4.Create(Self);
  493. end;
  494. ssEuler:
  495. begin
  496. DESolver := TDESolverEuler.Create(Self);
  497. end;
  498. end;
  499. fDESolverType := SolverType;
  500. end;
  501. end;
  502. procedure TGLSPIManager.RegisterInertia(aInertia: TGLBaseInertia);
  503. begin
  504. if Assigned(aInertia) then
  505. if fInertias.IndexOf(aInertia) < 0 then
  506. begin
  507. fInertias.Add(aInertia);
  508. aInertia.FManager := Self;
  509. DESolver.StateSize := DESolver.StateSize + aInertia.StateSize;
  510. SetLength(DESolver.StateArray, DESolver.StateSize);
  511. end;
  512. end;
  513. procedure TGLSPIManager.DeRegisterInertia(aInertia: TGLBaseInertia);
  514. begin
  515. if Assigned(aInertia) then
  516. begin
  517. aInertia.FManager := nil;
  518. fInertias.Remove(aInertia);
  519. DESolver.StateSize := DESolver.StateSize - aInertia.StateSize;
  520. SetLength(DESolver.StateArray, DESolver.StateSize);
  521. end;
  522. end;
  523. procedure TGLSPIManager.DeRegisterAllInertias;
  524. var
  525. i: Integer;
  526. begin
  527. // Fast deregistration
  528. for i := 0 to fInertias.Count - 1 do
  529. TGLBaseInertia(fInertias[i]).FManager := nil;
  530. fInertias.Clear;
  531. DESolver.StateSize := 0;
  532. // SetLEngth(StateArray,0);
  533. end;
  534. procedure TGLSPIManager.RegisterForceFieldEmitter
  535. (aForceField: TGLBaseForceFieldEmitter);
  536. begin
  537. if Assigned(aForceField) then
  538. if fForceFieldEmitters.IndexOf(aForceField) < 0 then
  539. begin
  540. fForceFieldEmitters.Add(aForceField);
  541. aForceField.FManager := Self;
  542. end;
  543. end;
  544. procedure TGLSPIManager.DeRegisterForceFieldEmitter
  545. (aForceField: TGLBaseForceFieldEmitter);
  546. begin
  547. if Assigned(aForceField) then
  548. begin
  549. aForceField.FManager := nil;
  550. fForceFieldEmitters.Remove(aForceField);
  551. end;
  552. end;
  553. procedure TGLSPIManager.DeRegisterAllForceFieldEmitters;
  554. var
  555. i: Integer;
  556. begin
  557. // Fast deregistration
  558. for i := 0 to fForceFieldEmitters.Count - 1 do
  559. TGLBaseForceFieldEmitter(fForceFieldEmitters[i]).FManager := nil;
  560. fForceFieldEmitters.Clear;
  561. end;
  562. function TGLSPIManager.CalculateKE(): Real;
  563. var
  564. Total: Real;
  565. i: Integer;
  566. begin
  567. Total := 0;
  568. for i := 0 to fInertias.Count - 1 do
  569. begin
  570. // calculate fInertias[i] KE
  571. Total := Total + TGLBaseInertia(fInertias.Items[i]).CalculateKE();
  572. end;
  573. Result := Total;
  574. end;
  575. function TGLSPIManager.CalculatePE(): Real;
  576. var
  577. Total: Real;
  578. i: Integer;
  579. begin
  580. Total := 0;
  581. for i := 0 to fInertias.Count - 1 do
  582. begin
  583. // calculate fobject[i] PE
  584. Total := Total + TGLBaseInertia(fInertias.Items[i]).CalculatePE();
  585. end;
  586. Result := Total;
  587. end;
  588. procedure TGLSPIManager.CalculateNextState(DeltaTime: Real);
  589. begin
  590. if Assigned(DESolver) then
  591. DESolver.Solve(DeltaTime);
  592. end;
  593. constructor TGLForces.Create(aOwner: TPersistent);
  594. begin
  595. // Assert(aOwner is TGLBaseSceneObject);
  596. inherited Create(aOwner);
  597. end;
  598. { destructor TGLForces.Destroy;
  599. begin
  600. inherited Destroy;
  601. end;
  602. }
  603. class function TGLForces.ItemsClass: TXCollectionItemClass;
  604. begin
  605. Result := TGLForce;
  606. end;
  607. function TGLForces.GetForce(index: Integer): TGLForce;
  608. begin
  609. Result := TGLForce(Items[index]);
  610. end;
  611. function TGLForces.CanAdd(aClass: TXCollectionItemClass): Boolean;
  612. begin
  613. Result := { (not aClass.InheritsFrom(TGLEffect)) and }
  614. (inherited CanAdd(aClass));
  615. end;
  616. // -----------------------------------------------------------------------------
  617. procedure TGLBaseInertia.SetManager(const val: TGLSPIManager);
  618. begin
  619. if val <> FManager then
  620. begin
  621. if Assigned(FManager) then
  622. FManager.DeRegisterInertia(Self);
  623. if Assigned(val) then
  624. val.RegisterInertia(Self);
  625. // messagedlg(val.GetNamePath,mtinformation,[mbok],0);
  626. end;
  627. end;
  628. procedure TGLBaseInertia.Loaded;
  629. var
  630. mng: TComponent;
  631. begin
  632. inherited;
  633. if FManagerName <> '' then
  634. begin
  635. ///? mng := FindManager(TGLSPIManager, FManagerName);
  636. if Assigned(mng) then
  637. Manager := TGLSPIManager(mng);
  638. FManagerName := '';
  639. end;
  640. end;
  641. procedure TGLBaseInertia.WriteToFiler(writer: TWriter);
  642. begin
  643. inherited; // Dan Bartlett
  644. with writer do
  645. begin
  646. WriteInteger(0); // Archive Version 0
  647. WriteBoolean(FDampingEnabled);
  648. if Assigned(FManager) then
  649. WriteString(FManager.GetNamePath)
  650. else
  651. WriteString('');
  652. end;
  653. end;
  654. procedure TGLBaseInertia.ReadFromFiler(reader: TReader);
  655. begin
  656. inherited;
  657. with reader do
  658. begin
  659. ReadInteger; // ignore archiveVersion
  660. FDampingEnabled := ReadBoolean;
  661. FManagerName := ReadString;
  662. Manager := nil;
  663. end;
  664. // Loaded; //DB100
  665. end;
  666. constructor TGLBaseInertia.Create(aOwner: TXCollection);
  667. begin
  668. inherited Create(aOwner);
  669. FDampingEnabled := true;
  670. end;
  671. destructor TGLBaseInertia.Destroy;
  672. begin
  673. SetManager(nil);
  674. inherited Destroy;
  675. end;
  676. procedure TGLBaseInertia.Assign(Source: TPersistent);
  677. begin
  678. if Source.ClassType = Self.ClassType then
  679. begin
  680. StateSize := TGLBaseInertia(Source).StateSize;
  681. FDampingEnabled := TGLBaseInertia(Source).DampingEnabled;
  682. Manager := TGLBaseInertia(Source).Manager;
  683. end;
  684. inherited Assign(Source);
  685. end;
  686. procedure TGLBaseInertia.StateToArray(var StateArray: TStateArray;
  687. StatePos: Integer);
  688. begin
  689. end;
  690. procedure TGLBaseInertia.ArrayToState( { var } StateArray: TStateArray;
  691. StatePos: Integer);
  692. begin
  693. end;
  694. procedure TGLBaseInertia.CalcStateDot(var StateArray: TStateArray;
  695. StatePos: Integer);
  696. begin
  697. end;
  698. procedure TGLBaseInertia.RemoveForces();
  699. begin
  700. end;
  701. procedure TGLBaseInertia.CalculateForceFieldForce(ForceFieldEmitter
  702. : TGLBaseForceFieldEmitter);
  703. begin
  704. end;
  705. function TGLBaseInertia.CalculateKE(): Real;
  706. begin
  707. Result := 0;
  708. end;
  709. function TGLBaseInertia.CalculatePE(): Real;
  710. begin
  711. Result := 0;
  712. end;
  713. procedure TGLBaseInertia.CalcAuxiliary();
  714. begin
  715. end;
  716. procedure TGLBaseInertia.SetUpStartingState();
  717. begin
  718. end;
  719. // -----------------------------------------------------------------------------
  720. procedure TGLBaseForceFieldEmitter.SetManager(const val: TGLSPIManager);
  721. begin
  722. if val <> FManager then
  723. begin
  724. if Assigned(FManager) then
  725. FManager.DeRegisterForceFieldEmitter(Self);
  726. if Assigned(val) then
  727. val.RegisterForceFieldEmitter(Self);
  728. end;
  729. end;
  730. procedure TGLBaseForceFieldEmitter.Loaded;
  731. var
  732. mng: TComponent;
  733. begin
  734. inherited;
  735. if FManagerName <> '' then
  736. begin
  737. ///? mng := FindManager(TGLSPIManager, FManagerName);
  738. if Assigned(mng) then
  739. Manager := TGLSPIManager(mng);
  740. FManagerName := '';
  741. end;
  742. end;
  743. procedure TGLBaseForceFieldEmitter.WriteToFiler(writer: TWriter);
  744. begin
  745. inherited; // Dan Bartlett
  746. with writer do
  747. begin
  748. WriteInteger(0); // Archive Version 0
  749. if Assigned(FManager) then
  750. WriteString(FManager.GetNamePath)
  751. else
  752. WriteString('');
  753. end;
  754. end;
  755. procedure TGLBaseForceFieldEmitter.ReadFromFiler(reader: TReader);
  756. begin
  757. inherited;
  758. with reader do
  759. begin
  760. ReadInteger; // ignore archiveVersion
  761. FManagerName := ReadString;
  762. Manager := nil;
  763. end;
  764. // Loaded; //DB100
  765. end;
  766. constructor TGLBaseForceFieldEmitter.Create(aOwner: TXCollection);
  767. begin
  768. inherited Create(aOwner);
  769. end;
  770. destructor TGLBaseForceFieldEmitter.Destroy;
  771. begin
  772. SetManager(nil);
  773. inherited Destroy;
  774. end;
  775. procedure TGLBaseForceFieldEmitter.Assign(Source: TPersistent);
  776. begin
  777. if Source.ClassType = Self.ClassType then
  778. begin
  779. Manager := TGLBaseForceFieldEmitter(Source).Manager;
  780. end;
  781. inherited Assign(Source);
  782. end;
  783. // CalculateForceField
  784. function TGLBaseForceFieldEmitter.CalculateForceField(Body: TGLBaseSceneObject)
  785. : TAffineVector;
  786. begin
  787. Result := nullVector;
  788. end;
  789. // ------------------------------------------------------------------
  790. initialization
  791. // ------------------------------------------------------------------
  792. // RegisterClasses([TGLForces]);
  793. // RegisterClasses([TGLSPIManager, TGLBaseInertia, TGLBaseForceFieldEmitter]);
  794. // RegisterXCollectionItemClass(TGLBaseInertia);
  795. // RegisterXCollectionItemClass(TGLBaseForceFieldEmitter);
  796. // RegisterXCollectionItemClass(TGLPhysicsForce);
  797. end.