2
0
glscene 1 жил өмнө
parent
commit
85ab64f21c

+ 1 - 1
Packages/GXScene_Cg_DT.dproj

@@ -105,7 +105,7 @@
         <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
         <VerInfo_Locale>1033</VerInfo_Locale>
         <DCC_Description>GLXcene CG Shaders</DCC_Description>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2)'!=''">
         <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>

+ 1 - 1
Packages/GXScene_Cg_RT.dproj

@@ -126,7 +126,7 @@
         <DCC_ObjOutput>..\lib\$(Platform)</DCC_ObjOutput>
         <DCC_HppOutput>..\include\$(Platform)</DCC_HppOutput>
         <DCC_Description>GXScene CG Shaders</DCC_Description>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2)'!=''">
         <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>

+ 1 - 1
Packages/GXScene_DT.dpk

@@ -28,7 +28,7 @@ package GXScene_DT;
 {$DEFINE DEBUG}
 {$ENDIF IMPLICITBUILDING}
 {$DESCRIPTION 'GXScene Graphics'}
-{$DESIGNONLY}
+{$RUNONLY}
 {$IMPLICITBUILD ON}
 
 requires

+ 2 - 2
Packages/GXScene_DT.dproj

@@ -88,7 +88,7 @@
         <DCC_S>false</DCC_S>
         <DCC_N>false</DCC_N>
         <GenDll>true</GenDll>
-        <DesignOnlyPackage>true</DesignOnlyPackage>
+        <RuntimeOnlyPackage>true</RuntimeOnlyPackage>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_Android)'!=''">
         <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
@@ -174,7 +174,7 @@
         <SanitizedProjectName>GLScene_RunTime_FMX</SanitizedProjectName>
         <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=VKSTeam;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>
         <DCC_N>false</DCC_N>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
         <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>

+ 1 - 1
Packages/GXScene_GPU_DT.dproj

@@ -146,7 +146,7 @@
         <DCC_HppOutput>..\include\$(Platform)</DCC_HppOutput>
         <DCC_ObjOutput>..\lib\$(Platform)</DCC_ObjOutput>
         <DCC_Description>GLXcene GPU Computing</DCC_Description>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <Import Project="CBoutput_FMX.optset" Condition="'$(Base)'!='' And Exists('CBoutput_FMX.optset')"/>
     <ItemGroup>

+ 1 - 1
Packages/GXScene_GPU_RT.dproj

@@ -172,7 +172,7 @@
         <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
         <VerInfo_Locale>1033</VerInfo_Locale>
         <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <ItemGroup>
         <DelphiCompile Include="$(MainSource)">

+ 1 - 1
Packages/GXScene_Physics_DT.dproj

@@ -92,7 +92,7 @@
         <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
         <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>
         <DCC_CBuilderOutput>All</DCC_CBuilderOutput>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <ItemGroup>
         <DelphiCompile Include="$(MainSource)">

+ 9 - 4
Packages/GXScene_Physics_RT.dpk

@@ -44,10 +44,15 @@ contains
   GXS.ODERagdoll in '..\Sourcex\GXS.ODERagdoll.pas',
   GXS.ODESkeletonColliders in '..\Sourcex\GXS.ODESkeletonColliders.pas',
   GXS.ODEUtils in '..\Sourcex\GXS.ODEUtils.pas',
-  Newton.Import in '..\Unipas\Newton.Import.pas',
-  NGD.Import in '..\Unipas\NGD.Import.pas',
-  ODE.Import in '..\Unipas\ODE.Import.pas',
-  PhysX.Import in '..\Unipas\PhysX.Import.pas';
+  GXS.PhysFields in '..\Sourcex\GXS.PhysFields.pas',
+  GXS.PhysForces in '..\Sourcex\GXS.PhysForces.pas',
+  GXS.PhysInertias in '..\Sourcex\GXS.PhysInertias.pas',
+  GXS.PhysJoints in '..\Sourcex\GXS.PhysJoints.pas',
+  GXS.PhysManager in '..\Sourcex\GXS.PhysManager.pas',
+  NGD.Import in '..\Source\NGD.Import.pas',
+  Newton.Import in '..\Source\Newton.Import.pas',
+  ODE.Import in '..\Source\ODE.Import.pas',
+  PhysX.Import in '..\Source\PhysX.Import.pas';
 
 end.
 

+ 10 - 5
Packages/GXScene_Physics_RT.dproj

@@ -164,7 +164,7 @@
         <DCC_CBuilderOutput>All</DCC_CBuilderOutput>
         <DCC_ImageBase>00400000</DCC_ImageBase>
         <SanitizedProjectName>GLScene_RunTime_FMX</SanitizedProjectName>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <ItemGroup>
         <DelphiCompile Include="$(MainSource)">
@@ -179,10 +179,15 @@
         <DCCReference Include="..\Sourcex\GXS.ODERagdoll.pas"/>
         <DCCReference Include="..\Sourcex\GXS.ODESkeletonColliders.pas"/>
         <DCCReference Include="..\Sourcex\GXS.ODEUtils.pas"/>
-        <DCCReference Include="..\Unipas\Newton.Import.pas"/>
-        <DCCReference Include="..\Unipas\NGD.Import.pas"/>
-        <DCCReference Include="..\Unipas\ODE.Import.pas"/>
-        <DCCReference Include="..\Unipas\PhysX.Import.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.PhysFields.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.PhysForces.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.PhysInertias.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.PhysJoints.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.PhysManager.pas"/>
+        <DCCReference Include="..\Source\NGD.Import.pas"/>
+        <DCCReference Include="..\Source\Newton.Import.pas"/>
+        <DCCReference Include="..\Source\ODE.Import.pas"/>
+        <DCCReference Include="..\Source\PhysX.Import.pas"/>
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
         </BuildConfiguration>

+ 1 - 1
Packages/GXScene_RT.dproj

@@ -178,7 +178,7 @@
         <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
         <VerInfo_Locale>1033</VerInfo_Locale>
         <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <ItemGroup>
         <DelphiCompile Include="$(MainSource)">

+ 1 - 1
Packages/GXScene_Sounds_DT.dproj

@@ -133,7 +133,7 @@
         <DCC_CBuilderOutput>All</DCC_CBuilderOutput>
         <DCC_ImageBase>00400000</DCC_ImageBase>
         <SanitizedProjectName>GLScene_RunTime_FMX</SanitizedProjectName>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <ItemGroup>
         <DelphiCompile Include="$(MainSource)">

+ 1 - 1
Packages/GXScene_Sounds_RT.dproj

@@ -155,7 +155,7 @@
         <DCC_CBuilderOutput>All</DCC_CBuilderOutput>
         <DCC_ImageBase>00400000</DCC_ImageBase>
         <SanitizedProjectName>GLScene_RunTime_FMX</SanitizedProjectName>
-        <DCC_UnitSearchPath>..\Unipas;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+        <DCC_UnitSearchPath>..\sourcex;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2)'!=''">
         <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>

+ 5 - 10
Source/GLScene.VectorGeometry.pas

@@ -207,7 +207,6 @@ type
       1: (X, Y, Z, W: Single);
   end;
 
-
   PQuaternionArray = ^TQuaternionArray;
   TQuaternionArray = array [0 .. MaxInt shr 5] of TQuaternion;
 
@@ -220,21 +219,18 @@ type
     pLeft, pTop, pRight, pBottom, pNear, pFar: THmgPlane;
   end;
 
-   TTransType = (ttScaleX, ttScaleY, ttScaleZ,
-                 ttShearXY, ttShearXZ, ttShearYZ,
-                 ttRotateX, ttRotateY, ttRotateZ,
-                 ttTranslateX, ttTranslateY, ttTranslateZ,
-                 ttPerspectiveX, ttPerspectiveY, ttPerspectiveZ, ttPerspectiveW);
-
+  TTransType = (ttScaleX, ttScaleY, ttScaleZ,
+                ttShearXY, ttShearXZ, ttShearYZ,
+                ttRotateX, ttRotateY, ttRotateZ,
+                ttTranslateX, ttTranslateY, ttTranslateZ,
+                ttPerspectiveX, ttPerspectiveY, ttPerspectiveZ, ttPerspectiveW);
   (*
     Used to describe a sequence of transformations in following order:
     [Sx][Sy][Sz][ShearXY][ShearXZ][ShearZY][Rx][Ry][Rz][Tx][Ty][Tz][P(x,y,z,w)]
     constants are declared for easier access (see MatrixDecompose below)
   *)
   TTransformations = array [TTransType] of Single;
-
   TPackedRotationMatrix = array [0 .. 2] of SmallInt;
-
   TGLInterpolationType = (itLinear, itPower, itSin, itSinAlt, itTan, itLn, itExp);
 
 const
@@ -289,7 +285,6 @@ const
   EmptyHmgMatrix: TGLMatrix = (V: ((X: 0; Y: 0; Z: 0; W: 0), (X: 0; Y: 0; Z: 0;
     W: 0), (X: 0; Y: 0; Z: 0; W: 0), (X: 0; Y: 0; Z: 0; W: 0)));
 
-
   // Quaternions
   IdentityQuaternion: TQuaternion = (ImagPart: (X: 0; Y: 0; Z: 0); RealPart: 1);
 

+ 1 - 1
Source/NGD.Import.pas

@@ -1666,6 +1666,6 @@ procedure NewtonMeshGetFacePointIndices(const Mesh: PNewtonMesh; const face: Poi
   Indices: PInteger); cdecl;
   external{$IFDEF __GPC__}name 'NewtonMeshGetFacePointIndices'{$ELSE}NewtonDLL{$ENDIF __GPC__};
 
-implementation
+implementation //-------------------------------------------------------------
 
 end.

+ 2 - 3
Source/ODE.Import.pas

@@ -54,9 +54,8 @@ interface
 {$ENDIF}
 
 uses
-  System.Classes
-  ,ModuleLoader
-  ;
+  System.Classes,
+  ModuleLoader;
 
 const
 

+ 341 - 0
Sourcex/GXS.PhysFields.pas

@@ -0,0 +1,341 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit GXS.PhysFields;
+
+interface
+
+uses
+  System.Classes,
+  GLScene.VectorGeometry,
+  GLScene.XCollection,
+  GLScene.Coordinates,
+
+  GXS.Scene,
+  GXS.Behaviours,
+  (* GXS.RigidBodyInertia *)
+  GXS.PhysInertias,
+  GXS.PhysManager;
+
+type
+  TGLUniformGravityEmitter = class(TgxBaseForceFieldEmitter)
+  private
+    fGravity: TgCoordinates;
+  protected
+    procedure SetGravity(const val: TgCoordinates);
+  public
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    function CalculateForceField(Body: TgxBaseSceneObject)
+      : TAffineVector; override;
+  published
+    property Gravity: TgCoordinates read fGravity write SetGravity;
+  end;
+
+  TGLRadialGravityEmitter = class(TgxBaseForceFieldEmitter)
+  private
+    fMass: Real;
+    fMassOverG: Real;
+  public
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    function CalculateForceField(Body: TgxBaseSceneObject)
+      : TAffineVector; override;
+  published
+    property Mass: Real read fMass write fMass;
+  end;
+
+  TgxDampingFieldEmitter = class(TgxBaseForceFieldEmitter)
+  private
+    fDamping: TgxDamping;
+  protected
+    procedure SetDamping(const val: TgxDamping);
+  public
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    function CalculateForceField(Body: TgxBaseSceneObject)
+      : TAffineVector; override;
+  published
+    property Damping: TgxDamping read fDamping write SetDamping;
+  end;
+
+const
+  GravitationalConstant = 6.6726E-11;
+
+// ==================================================================
+implementation
+// ==================================================================
+
+// -------------------------------------
+// ---- TGLUniformGravityEmitter
+// -------------------------------------
+constructor TGLUniformGravityEmitter.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+  fGravity := TgCoordinates.CreateInitialized(Self, nullHmgVector, csVector);
+end;
+
+destructor TGLUniformGravityEmitter.Destroy;
+begin
+  fGravity.Free;
+  inherited Destroy;
+end;
+
+procedure TGLUniformGravityEmitter.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    fGravity := TGLUniformGravityEmitter(Source).fGravity;
+  end;
+end;
+
+class function TGLUniformGravityEmitter.FriendlyName: String;
+begin
+  Result := 'Uniform Gravity';
+end;
+
+class function TGLUniformGravityEmitter.FriendlyDescription: String;
+begin
+  Result := 'Uniform Gravity, appropriate near surface of planet';
+end;
+
+class function TGLUniformGravityEmitter.UniqueItem: Boolean;
+begin
+  Result := false;
+end;
+
+procedure TGLUniformGravityEmitter.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    fGravity.WriteToFiler(writer);
+  end;
+end;
+
+procedure TGLUniformGravityEmitter.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    fGravity.ReadFromFiler(reader);
+  end;
+end;
+
+procedure TGLUniformGravityEmitter.SetGravity(const val: TgCoordinates);
+begin
+  fGravity.Assign(val);
+end;
+
+// CalculateForceField  (TODO: ParticleInertia -> BaseInertia, add BaseInertia.ApplyAcceleration)
+function TGLUniformGravityEmitter.CalculateForceField(Body: TgxBaseSceneObject)
+  : TAffineVector;
+var
+  inertia1: TgxParticleInertia;
+begin
+  inertia1 := TgxParticleInertia
+    (Body.Behaviours.GetByClass(TgxParticleInertia));
+  if Assigned(inertia1) then
+  begin
+    Result := VectorScale(fGravity.AsAffineVector, inertia1.Mass);
+    inertia1.ApplyForce(Result);
+  end
+  else
+    Result := nullVector;
+end;
+
+// ------------------------------------------------------------------------------
+// ------------------------------Radial Gravity Emitter -------------------------
+// ------------------------------------------------------------------------------
+
+constructor TGLRadialGravityEmitter.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+end;
+
+destructor TGLRadialGravityEmitter.Destroy;
+begin
+  inherited Destroy;
+end;
+
+procedure TGLRadialGravityEmitter.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    fMass := TGLRadialGravityEmitter(Source).fMass;
+  end;
+end;
+
+class function TGLRadialGravityEmitter.FriendlyName: String;
+begin
+  Result := 'Radial Gravity';
+end;
+
+class function TGLRadialGravityEmitter.FriendlyDescription: String;
+begin
+  Result := 'Radial Gravity, can be applied anywhere (use for planets)';
+end;
+
+class function TGLRadialGravityEmitter.UniqueItem: Boolean;
+begin
+  Result := false;
+end;
+
+procedure TGLRadialGravityEmitter.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    WriteFloat(fMass);
+  end;
+end;
+
+procedure TGLRadialGravityEmitter.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    fMass := ReadFloat();;
+  end;
+end;
+
+// CalculateForceField (TODO: ParticleInertia -> BaseInertia if possible)
+function TGLRadialGravityEmitter.CalculateForceField(Body: TgxBaseSceneObject)
+  : TAffineVector;
+var
+  inertia1: TgxParticleInertia;
+  R: TAffineVector;
+  L: Real;
+begin
+  inertia1 := TgxParticleInertia
+    (Body.Behaviours.GetByClass(TgxParticleInertia));
+  if Assigned(inertia1) then
+  begin
+    R := VectorSubtract(Body.Position.AsAffineVector,
+      Self.OwnerBaseSceneObject.Position.AsAffineVector);
+    L := VectorLength(R);
+    Result := VectorScale(R, -GravitationalConstant * (fMass / L));
+    inertia1.ApplyForce(Result);
+  end
+  else
+    Result := nullVector;
+end;
+
+// -----------------------------------------------------------------------------
+// ------------------------------Damping Field Emitter -------------------------
+// -----------------------------------------------------------------------------
+
+constructor TgxDampingFieldEmitter.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+  fDamping := TgxDamping.Create(Self);
+end;
+
+destructor TgxDampingFieldEmitter.Destroy;
+begin
+  fDamping.Free;
+  inherited Destroy;
+end;
+
+procedure TgxDampingFieldEmitter.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    fDamping := TgxDampingFieldEmitter(Source).fDamping;
+  end;
+end;
+
+class function TgxDampingFieldEmitter.FriendlyName: String;
+begin
+  Result := 'Damping Field';
+end;
+
+class function TgxDampingFieldEmitter.FriendlyDescription: String;
+begin
+  Result := 'Damping Field, to approximate air/fluid resistance';
+end;
+
+class function TgxDampingFieldEmitter.UniqueItem: Boolean;
+begin
+  Result := false;
+end;
+
+procedure TgxDampingFieldEmitter.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    fDamping.WriteToFiler(writer);
+  end;
+end;
+
+procedure TgxDampingFieldEmitter.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    fDamping.ReadFromFiler(reader);
+  end;
+end;
+
+procedure TgxDampingFieldEmitter.SetDamping(const val: TgxDamping);
+begin
+  fDamping.Assign(val);
+end;
+
+// CalculateForceField (TODO: ParticleInertia -> BaseInertia, BaseInertia.ApplyDamping?)
+function TgxDampingFieldEmitter.CalculateForceField(Body: TgxBaseSceneObject)
+  : TAffineVector;
+var
+  inertia1: TgxParticleInertia;
+  // velocity:TAffineVector;
+  // v:Real;
+begin
+  inertia1 := TgxParticleInertia
+    (Body.Behaviours.GetByClass(TgxParticleInertia));
+  if Assigned(inertia1) then
+    inertia1.ApplyDamping(Damping);
+
+  { Inertia1:=TgxParticleInertia(Body.Behaviours.GetByClass(TgxParticleInertia));
+    if Assigned(inertia1) then
+    begin
+    velocity:=VectorScale(inertia1.LinearMomentum, 1/Inertia1.Mass); // v = p/m
+    //apply force in opposite direction to velocity
+    v:=VectorLength(velocity);
+    //  F = -Normalised(V)*( Constant + (Linear)*(V) + (Quadtratic)*(V)*(V) )
+    Result:=VectorScale(VectorNormalize(velocity),-(fDamping.Constant+fDamping.Linear*v+fDamping.Quadratic*v*v));
+    inertia1.ApplyForce(Result);
+    end
+    else
+    Result:=nullvector;
+  }
+end;
+
+// -------------------------------------------------------------------------
+initialization
+
+// -------------------------------------------------------------------------
+
+RegisterXCollectionItemClass(TGLUniformGravityEmitter);
+RegisterXCollectionItemClass(TGLRadialGravityEmitter);
+RegisterXCollectionItemClass(TgxDampingFieldEmitter);
+
+end.

+ 413 - 0
Sourcex/GXS.PhysForces.pas

@@ -0,0 +1,413 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit GXS.PhysForces;
+
+interface
+
+uses
+  System.Classes,
+
+  GLScene.VectorTypes,
+  GLScene.XCollection,
+  GLScene.VectorGeometry,
+  GLScene.Coordinates,
+  GLScene.Strings,
+  
+  GXS.Scene,
+  GXS.Behaviours;
+
+type
+  TgxForce = class;
+  TgxForceType = (ftHookes, ftGravitation, ftCustom);
+
+  TOnCustomForce = procedure() of object;
+
+  TgxForce = class(TXCollectionItem)
+  private
+    fObject1: TgxBaseSceneObject;
+    fObject2: TgxBaseSceneObject;
+    fposition1: TgCoordinates;
+    fposition2: TgCoordinates;
+    object1Name: String;
+    object2Name: String;
+    // fOnCustomForce: TOnCustomForce;
+  protected
+    procedure Loaded; override;
+    procedure SetName(const val: String); override;
+    (* Returns the TgxBaseSceneObject on which the behaviour should be applied.
+      Does NOT check for nil owners *)
+    // function OwnerBaseSceneObject : TgxBaseSceneObject;
+  public
+    (* constructor Create(Collection: TCollection);override; *)
+    // Override this function to write subclass data.
+    procedure WriteToFiler(writer: TWriter); override;
+    // Override this function to read subclass data.
+    procedure ReadFromFiler(reader: TReader); override;
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    procedure SetObject1(const val: TgxBaseSceneObject);
+    procedure SetObject2(const val: TgxBaseSceneObject);
+    procedure SetPosition1(const val: TgCoordinates);
+    procedure SetPosition2(const val: TgCoordinates);
+    function CalculateForce(): TAffineVector; virtual;
+  published
+    property Object1: TgxBaseSceneObject read fObject1 write SetObject1;
+    property Object2: TgxBaseSceneObject read fObject2 write SetObject2;
+    property Position1: TgCoordinates read fposition1 write SetPosition1;
+    property Position2: TgCoordinates read fposition2 write SetPosition2;
+    // property OnCustomForce:TOnCustomForce read fOnCustomForce write fOnCustomForce;
+  end;
+
+  TgxHookesSpring = class(TgxForce)
+  private
+    fNaturalLength: Real;
+    fElasticity: Real;
+    fLength: Real;
+    fExtension: Real;
+    fDamping: TgxDamping;
+  public
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    procedure SetDamping(const val: TgxDamping);
+    function CalculateForce(): TAffineVector; override;
+  published
+    property NaturalLength: Real read fNaturalLength write fNaturalLength;
+    property Elasticity: Real read fElasticity write fElasticity;
+    property Damping: TgxDamping read fDamping write SetDamping;
+    // property Name;
+  end;
+
+  TgxHookesString = class(TgxHookesSpring)
+  protected
+    // procedure WriteToFiler(writer : TWriter); override;
+    // procedure ReadFromFiler(reader : TReader); override;
+  public
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    function CalculateForce(): TAffineVector; override;
+  end;
+
+implementation // -------------------------------------------------------------
+
+uses
+  GXS.PhysInertias,
+  GXS.PhysManager;
+
+constructor TgxForce.Create(aOwner: TXCollection);
+begin
+  inherited; // Create(aOwner)
+  fposition1 := TgCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
+  fposition2 := TgCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
+  // fObject1:=TgxBaseSceneObject.Create(Self);
+  // fObject2:=TgxBaseSceneObject.Create(Self);
+end;
+
+destructor TgxForce.Destroy;
+begin
+  fposition1.Free();
+  fposition2.Free();
+  // SetObject1(nil);
+  // SetObject2(nil);
+  // fObject1.Free();
+  // fObject2.Free();
+
+  inherited Destroy;
+end;
+
+procedure TgxForce.Assign(Source: TPersistent);
+begin
+  // inherited Assign(Source);
+  fposition1.Assign(TgxForce(Source).fposition1);
+  fposition2.Assign(TgxForce(Source).fposition2);
+  Object1 := TgxForce(Source).Object1;
+  Object2 := TgxForce(Source).Object2;
+  inherited Assign(Source);
+end;
+
+procedure TgxForce.SetObject1(const val: TgxBaseSceneObject);
+begin
+  if val.Behaviours.IndexOfClass(TgxBaseInertia) >=0 then
+    fObject1 := val
+  else
+    Write('Object1 does not have an inertia behaviour');
+end;
+
+procedure TgxForce.SetObject2(const val: TgxBaseSceneObject);
+begin
+  if val.Behaviours.IndexOfClass(TgxBaseInertia) >=0 then
+    fObject2 := val
+  else
+   Write('Object2 does not have an inertia behaviour');
+end;
+
+procedure TgxForce.SetPosition1(const val: TgCoordinates);
+begin
+  fposition1.Assign(val); // DB101
+end;
+
+procedure TgxForce.SetPosition2(const val: TgCoordinates);
+begin
+  fposition2.Assign(val);
+end;
+
+procedure TgxForce.Loaded;
+var
+  PhysMan: TgxPhysManager;
+begin
+  inherited Loaded;
+  // not nice at all!!!
+  // assumes owner is TgxForces belonging to TGLPhysicsManager
+  PhysMan := TgxPhysManager(Self.Owner.Owner);
+  if (object1Name <> '') then
+  begin
+    // PhysMan:=TGLPhysicsManager(Self.Owner.Owner);
+    fObject1 := PhysMan.FindObjectByName(object1Name);
+    // fObject1:=TgxBaseSceneObject(FindComponent(Object1Name));
+    // Object1Name:='';
+  end;
+
+  if object2Name <> '' then
+  begin
+    fObject2 := PhysMan.FindObjectByName(object2Name);
+    // Object2Name:='';
+  end;
+end;
+
+class function TgxForce.FriendlyName: String;
+begin
+  Result := 'Force';
+end;
+
+class function TgxForce.FriendlyDescription: String;
+begin
+  Result := 'Physics Force';
+end;
+
+class function TgxForce.UniqueItem: Boolean;
+begin
+  Result := false;
+end;
+
+procedure TgxForce.WriteToFiler(writer: TWriter);
+begin
+  inherited WriteToFiler(writer);
+  // Write('Writing to filer'+GetNamePath);
+  with writer do
+  begin
+    fposition1.WriteToFiler(writer);
+    fposition2.WriteToFiler(writer);
+    if Assigned(fObject1) then
+      WriteString(fObject1.GetNamePath)
+    else
+      WriteString('');
+    if Assigned(fObject2) then
+      WriteString(fObject2.GetNamePath)
+    else
+      WriteString('');
+    // WriteString(Object2Name);
+  end;
+end;
+
+procedure TgxForce.ReadFromFiler(reader: TReader);
+begin
+  // Read('Reading from filer'+GetNamePath);
+  inherited ReadFromFiler(reader);
+  with reader do
+  begin
+    fposition1.ReadFromFiler(reader);
+    fposition2.ReadFromFiler(reader);
+    object1Name := ReadString;
+    fObject1 := nil;
+    object2Name := ReadString;
+    fObject2 := nil;
+  end;
+  // Loaded;
+end;
+
+procedure TgxForce.SetName(const val: String);
+begin
+  inherited SetName(val);
+  (*
+  if Assigned(vGLBehaviourNameChangeEvent)
+  then
+   vGLBehaviourNameChangeEvent(Self);
+  *)
+end;
+
+function TgxForce.CalculateForce(): TAffineVector;
+begin
+  //
+end;
+
+constructor TgxHookesSpring.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+  fNaturalLength := 1;
+  fElasticity := 1;
+  fDamping := TgxDamping.Create(Self);
+end;
+
+destructor TgxHookesSpring.Destroy;
+begin
+  fDamping.Free;
+  inherited Destroy;
+end;
+
+procedure TgxHookesSpring.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    WriteFloat(fNaturalLength); // :Real;
+    WriteFloat(fElasticity); // :Real;
+    WriteFloat(fLength); // :Real;
+    WriteFloat(fExtension); // :Real;
+    fDamping.WriteToFiler(writer);
+  end;
+end;
+
+procedure TgxHookesSpring.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    fNaturalLength := ReadFloat(); // :Real;
+    fElasticity := ReadFloat(); // :Real;
+    fLength := ReadFloat(); // :Real;
+    fExtension := ReadFloat(); // :Real;
+    fDamping.ReadFromFiler(reader);
+  end;
+end;
+
+procedure TgxHookesSpring.SetDamping(const val: TgxDamping);
+begin
+  fDamping.Assign(val);
+end;
+
+function TgxHookesSpring.CalculateForce(): TAffineVector;
+var
+  rvector, vvector: TAffineVector;
+  Inertia1, Inertia2: TgxParticleInertia;
+begin
+  if (fObject1 = nil) or (fObject2 = nil) then
+    Exit;
+  Inertia2 := TgxParticleInertia
+    (Object2.Behaviours.GetByClass(TgxParticleInertia));
+  Inertia1 := TgxParticleInertia
+    (Object1.Behaviours.GetByClass(TgxParticleInertia));
+
+  // rvector:=VectorSubtract({VectorAdd(Object2.Position.asAffineVector,}VectorTransform(Position2.AsAffineVector,Object2.Matrix{)}),
+  // {VectorAdd(Object1.Position.asAffineVector,}VectorTransform(Position1.AsAffineVector,Object1.Matrix){)});
+  rvector := VectorSubtract(Object2.LocalToAbsolute(Position2.AsAffineVector),
+    Object1.LocalToAbsolute(Position1.AsAffineVector));
+  (*
+    rvector:=VectorSubtract(VectorAdd(Object2.Position.asAffineVector,VectorTransform(Position2.AsAffineVector,Object2.Matrix)),
+    VectorAdd(Object1.Position.asAffineVector,VectorTransform(Position1.AsAffineVector,Object1.Matrix)));
+  *)
+  fLength := VectorLength(rvector);
+  NormalizeVector(rvector);
+  fExtension := fLength - fNaturalLength;
+
+  // fDamping.Calculate();
+
+  Result := VectorScale(rvector, fElasticity * fExtension / fNaturalLength);
+  if Assigned(Inertia2) then
+    Inertia2.ApplyForce(Position2.AsAffineVector, VectorNegate(Result));
+  if Assigned(Inertia1) then
+    Inertia1.ApplyForce(Position1.AsAffineVector, Result);
+  // TGLInertia(Object1.Behaviours.GetByClass(TGLInertia)).ApplyForce(Position1.AsAffineVector,Result);
+end;
+
+class function TgxHookesSpring.FriendlyName: String;
+begin
+  Result := 'Hookes Spring';
+end;
+
+class function TgxHookesSpring.FriendlyDescription: String;
+begin
+  Result := 'A spring obeying Hookes Law';
+end;
+
+class function TgxHookesSpring.UniqueItem: Boolean;
+begin
+  Result := false;
+end;
+
+constructor TgxHookesString.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+end;
+
+destructor TgxHookesString.Destroy;
+begin
+  inherited Destroy;
+end;
+
+class function TgxHookesString.FriendlyName: String;
+begin
+  Result := 'Hookes String';
+end;
+
+class function TgxHookesString.FriendlyDescription: String;
+begin
+  Result := 'A string (that can go slack) obeying Hookes Law';
+end;
+
+class function TgxHookesString.UniqueItem: Boolean;
+begin
+  Result := false;
+end;
+
+function TgxHookesString.CalculateForce(): TAffineVector;
+var
+  rvector: TAffineVector;
+  Inertia1, Inertia2: TgxParticleInertia;
+begin
+  if (Object1 = nil) or (Object2 = nil) then
+    Exit;
+  rvector := VectorSubtract(Object2.LocalToAbsolute(Position2.AsAffineVector),
+    Object1.LocalToAbsolute(Position1.AsAffineVector));
+  // VectorAdd(Object2.Position.asAffineVector,VectorTransform(Object2.Position2.AsAffineVector,Object2.Matrix)),
+  // VectorAdd(Object1.Position.asAffineVector,VectorTransform(Position1.AsAffineVector,Object1.Matrix)));
+  fLength := VectorLength(rvector);
+  if (fLength < fNaturalLength) then
+    Result := NullVector
+  else
+  begin
+    NormalizeVector(rvector);
+    fExtension := fLength - fNaturalLength;
+    Result := VectorScale(rvector, fElasticity * fExtension / fNaturalLength);
+    // TGLInertia(Object2.Behaviours.GetByClass(TGLInertia)).ApplyForce(Position2.AsAffineVector,VectorNegate(Result));
+    // TGLInertia(Object1.Behaviours.GetByClass(TGLInertia)).ApplyForce(Position1.AsAffineVector,Result);
+    Inertia2 := TgxParticleInertia
+      (Object2.Behaviours.GetByClass(TgxParticleInertia));
+    Inertia1 := TgxParticleInertia
+      (Object1.Behaviours.GetByClass(TgxParticleInertia));
+    if Assigned(Inertia2) then
+      Inertia2.ApplyForce(Position2.AsAffineVector, VectorNegate(Result));
+    if Assigned(Inertia1) then
+      Inertia1.ApplyForce(Position1.AsAffineVector, Result);
+  end;
+  // Result:= inherited CalculateForce();
+  // if (fLength < fNaturalLength) then Result:=NullVector;
+end;
+
+initialization // -------------------------------------------------------------
+
+RegisterXCollectionItemClass(TgxHookesSpring);
+RegisterXCollectionItemClass(TgxHookesString);
+
+end.

+ 1137 - 0
Sourcex/GXS.PhysInertias.pas

@@ -0,0 +1,1137 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit GXS.PhysInertias;
+
+interface
+
+uses
+  System.SysUtils,
+  System.Classes,
+
+  GLScene.PersistentClasses,
+  GLScene.XCollection,
+  GLScene.BaseClasses,
+  GLScene.VectorGeometry,
+  GLScene.VectorTypes,
+  GLScene.Coordinates,
+  GLScene.Strings,
+  
+  GXS.PhysManager,
+  GXS.Scene,
+  GXS.Behaviours;
+
+type
+  TgxParticleInertia = class(TgxBaseInertia)
+  // modified from TgxBInertia
+  private
+    FMass: Single;
+    FTranslationSpeed: TgCoordinates;
+    FTranslationDamping: TgxDamping;
+  protected
+    function CalcLinearPositionDot(): TAffineVector;
+    function CalcLinearMomentumDot(): TAffineVector;
+    procedure SetTranslationSpeed(const val: TgCoordinates);
+    procedure SetTranslationDamping(const val: TgxDamping);
+  public
+    fForce: TAffineVector;
+    LinearPosition: TAffineVector;
+    LinearMomentum: TAffineVector;
+    procedure StateToArray(var StateArray: TStateArray; StatePos: Integer); override;
+    procedure ArrayToState( { var } StateArray: TStateArray; StatePos: Integer); override;
+    procedure CalcStateDot(var StateArray: TStateArray; StatePos: Integer); override;
+    procedure RemoveForces(); override;
+    procedure CalculateForceFieldForce(ForceFieldEmitter
+      : TgxBaseForceFieldEmitter); override;
+    procedure CalcAuxiliary(); override;
+    procedure SetUpStartingState(); override;
+    function CalculateKE(): Real; override;
+    function CalculatePE(): Real; override;
+    procedure SetForce(x, y, z: Real); virtual;
+    procedure ApplyForce(x, y, z: Real); overload; virtual;
+    procedure ApplyForce(Force: TAffineVector); overload; virtual;
+    procedure ApplyForce(pos, Force: TAffineVector); overload; virtual;
+    procedure ApplyLocalForce(pos, Force: TAffineVector); virtual;
+    procedure ApplyImpulse(j, x, y, z: Real); overload; virtual;
+    procedure ApplyImpulse(j: Single; normal: TAffineVector); overload; virtual;
+    procedure ApplyDamping(damping: TgxDamping); virtual;
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    // Inverts the translation vector
+    procedure MirrorTranslation;
+    (* Bounce speed as if hitting a surface.
+      restitution is the coefficient of restituted energy (1=no energy loss,
+      0=no bounce). The normal is NOT assumed to be normalized. *)
+    procedure SurfaceBounce(const surfaceNormal: TGLVector; restitution: Single);
+  published
+    property Mass: Single read FMass write FMass;
+    property TranslationSpeed: TgCoordinates read FTranslationSpeed
+      write SetTranslationSpeed;
+
+    (* Enable/Disable damping (damping has a high cpu-cycle cost).
+      Damping is enabled by default. *)
+    // property DampingEnabled : Boolean read FDampingEnabled write FDampingEnabled;
+    (* Damping applied to translation speed.<br>
+      Note that it is not "exactly" applied, ie. if damping would stop
+      your object after 0.5 time unit, and your progression steps are
+      of 1 time unit, there will be an integration error of 0.5 time unit. *)
+    property TranslationDamping: TgxDamping read FTranslationDamping
+      write SetTranslationDamping;
+  end;
+
+  TGLRigidBodyInertia = class;
+
+  (* Stores Inertia Tensor for TGLRigidBodyInertia model *)
+  TGLInertiaTensor = class(TGUpdateAbleObject)
+  private
+    fm11, fm12, fm13, fm21, fm22, fm23, fm31, fm32, fm33: Single;
+  public
+    constructor Create(aOwner: TPersistent); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure WriteToFiler(writer: TWriter);
+    procedure ReadFromFiler(reader: TReader);
+  published
+    property m11: Single read fm11 write fm11;
+    property m12: Single read fm12 write fm12;
+    property m13: Single read fm13 write fm13;
+    property m21: Single read fm21 write fm21;
+    property m22: Single read fm22 write fm22;
+    property m23: Single read fm23 write fm23;
+    property m31: Single read fm31 write fm31;
+    property m32: Single read fm32 write fm32;
+    property m33: Single read fm33 write fm33;
+  end;
+
+  (* A more complex model than TgxBInertia for Inertia *)
+  TGLRigidBodyInertia = class(TgxParticleInertia)
+  private
+    fDensity: Real;
+    fBodyInertiaTensor: TAffineMAtrix;
+    fBodyInverseInertiaTensor: TAffineMAtrix;
+    fInertiaTensor: TGLInertiaTensor;
+    InverseInertiaTensor: TAffineMAtrix;
+    // LinearVelocity:TAffineVector;
+    fRotationSpeed: TgCoordinates;
+    /// AngularVelocity:TAffineVector;      //rotation about axis, magnitude=speed
+    // damping properties
+    FRotationDamping: TgxDamping;
+  protected
+    // torques
+    fTorque: TAffineVector;
+    procedure SetLinearDamping(const val: TgxDamping);
+    procedure SetAngularDamping(const val: TgxDamping);
+  public
+    AngularOrientation: TQuaternion; // As Quat will help improve accuracy
+    R: TMatrix3f; // corresponds to AngularOrientation
+    AngularMomentum: TAffineVector;
+    procedure StateToArray(var StateArray: TStateArray;
+      StatePos: Integer); override;
+    procedure ArrayToState( (* var *) StateArray: TStateArray;
+      StatePos: Integer); override;
+    procedure CalcStateDot(var StateArray: TStateArray;
+      StatePos: Integer); override;
+    procedure ApplyImpulse(j, xpos, ypos, zpos, x, y, z: Real); overload;
+    procedure ApplyImpulse(j: Single; position, normal: TAffineVector);
+      overload;
+    procedure ApplyDamping(damping: TgxDamping); override;
+    // function CalcLinearPositionDot():TAffineVector;
+    // function CalcLinearMomentumDot():TAffineVector;
+    function CalcAngularOrientationDot(): TQuaternion;
+    function CalcAngularVelocityDot(): TAffineVector;
+    function CalculateKE(): Real; override;
+    function CalculatePE(): Real; override;
+    procedure CalcAuxiliary(); override;
+    procedure SetUpStartingState(); override;
+    constructor Create(aOwner: TXCollection); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+    class function FriendlyName: String; override;
+    class function FriendlyDescription: String; override;
+    class function UniqueItem: Boolean; override;
+    // function Star(Vector:TAffineVector):TGLMatrix;
+    function QuaternionToString(Quat: TQuaternion): String;
+    procedure RemoveForces(); override;
+    procedure SetTorque(x, y, z: Real);
+    procedure ApplyTorque(x, y, z: Real);
+    procedure ApplyForce(pos, Force: TAffineVector); override;
+    procedure ApplyLocalForce(pos, Force: TVector3f); override;
+    procedure ApplyLocalImpulse(xpos, ypos, zpos, x, y, z: Real);
+    procedure SetInertiaTensor(newVal: TGLInertiaTensor);
+    procedure SetRotationSpeed(const val: TgCoordinates);
+    procedure SetRotationDamping(const val: TgxDamping);
+  published
+    property Density: Real read fDensity write fDensity;
+    property InertiaTensor: TGLInertiaTensor read fInertiaTensor
+      write SetInertiaTensor;
+    property RotationSpeed: TgCoordinates read fRotationSpeed
+      write SetRotationSpeed;
+    property RotationDamping: TgxDamping read FRotationDamping
+      write SetRotationDamping;
+  end;
+
+(* Returns or creates the TgxParticleInertia within the given behaviours.
+   This helper function is convenient way to access a TgxParticleInertia. *)
+function GetOrCreateParticleInertia(behaviours: TgxBehaviours): TgxParticleInertia; overload;
+(* Returns or creates the TgxParticleInertia within the given object's behaviours.
+  This helper function is convenient way to access a TgxParticleInertia. *)
+function GetOrCreateParticleInertia(obj: TgxBaseSceneObject): TgxParticleInertia; overload;
+(* Returns or creates the TGLRigidBodyInertia within the given behaviours.
+  This helper function is convenient way to access a TGLRigidBodyInertia. *)
+function GetOrCreateRigidBodyInertia(behaviours: TgxBehaviours): TGLRigidBodyInertia; overload;
+(* Returns or creates the TGLRigidBodyInertia within the given object's behaviours.
+  This helper function is convenient way to access a TGLRigidBodyInertia. *)
+function GetOrCreateRigidBodyInertia(obj: TgxBaseSceneObject): TGLRigidBodyInertia; overload;
+
+const
+  DebugMode = false;
+
+implementation //-----------------------------------------------------------
+
+// ------------------
+// ------------------ TgxParticleInertia ------------------
+// ------------------
+
+constructor TgxParticleInertia.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+  FMass := 1;
+  StateSize := 6;
+  FTranslationSpeed := TgCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
+  LinearPosition := OwnerBaseSceneObject.position.AsAffineVector;
+  LinearMomentum := FTranslationSpeed.AsAffineVector;
+  FTranslationDamping := TgxDamping.Create(Self);
+end;
+
+destructor TgxParticleInertia.Destroy;
+begin
+  FTranslationDamping.Free;
+  FTranslationSpeed.Free;
+  inherited Destroy;
+end;
+
+procedure TgxParticleInertia.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    FMass := TgxParticleInertia(Source).FMass;
+    FTranslationSpeed.Assign(TgxParticleInertia(Source).FTranslationSpeed);
+    LinearPosition := TgxParticleInertia(Source).LinearPosition;
+    LinearMomentum := TgxParticleInertia(Source).LinearMomentum;
+    // FDampingEnabled:=TGLInertia(Source).DampingEnabled;
+    FTranslationDamping.Assign(TgxParticleInertia(Source).TranslationDamping);
+    // FRotationDamping.Assign(TgxBInertia(Source).RotationDamping);
+  end;
+  inherited Assign(Source);
+end;
+
+procedure TgxParticleInertia.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    WriteInteger(0); // Archive Version 0
+    WriteFloat(FMass);
+    Write(LinearPosition, SizeOf(LinearPosition));
+    Write(LinearMomentum, SizeOf(LinearMomentum));
+    Write(fForce, SizeOf(fForce));
+    FTranslationSpeed.WriteToFiler(writer);
+    FTranslationDamping.WriteToFiler(writer);
+  end;
+end;
+
+procedure TgxParticleInertia.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    ReadInteger; // ignore archiveVersion
+    FMass := ReadFloat;
+    Read(LinearPosition, SizeOf(LinearPosition));
+    Read(LinearMomentum, SizeOf(LinearMomentum));
+    Read(fForce, SizeOf(fForce));
+    FTranslationSpeed.ReadFromFiler(reader);
+    FTranslationDamping.ReadFromFiler(reader);
+  end;
+  // Loaded;
+  SetUpStartingState();
+end;
+
+procedure TgxParticleInertia.SetTranslationSpeed(const val: TgCoordinates);
+begin
+  FTranslationSpeed.Assign(val);
+  LinearMomentum := VectorScale(FTranslationSpeed.AsAffineVector, FMass);
+end;
+
+procedure TgxParticleInertia.SetUpStartingState();
+begin
+  LinearPosition := OwnerBaseSceneObject.position.AsAffineVector;
+  LinearMomentum := VectorScale(TranslationSpeed.AsAffineVector, Mass);
+end;
+
+procedure TgxParticleInertia.CalcAuxiliary( { RBody:TGLRigidBody } );
+begin
+  TranslationSpeed.AsAffineVector := VectorScale(LinearMomentum, 1 / Mass);
+  // OwnerBaseSceneObject.Matrix:=QuaternionToMatrix(AngularOrientation);
+  OwnerBaseSceneObject.position.AsAffineVector := LinearPosition; // position
+  // OwnerBaseSceneObject.position.x:=LinearPosition[0];//position
+  // OwnerBaseSceneObject.position.y:=LinearPosition[1];
+  // OwnerBaseSceneObject.position.z:=LinearPosition[2];
+end;
+
+procedure TgxParticleInertia.RemoveForces();
+begin
+  fForce := nullVector;
+end;
+
+procedure TgxParticleInertia.CalculateForceFieldForce(ForceFieldEmitter
+  : TgxBaseForceFieldEmitter);
+begin
+  ForceFieldEmitter.CalculateForceField(Self.OwnerBaseSceneObject);
+end;
+
+function TgxParticleInertia.CalculateKE(): Real;
+begin
+  Result := 1 / (2 * Mass) * VectorNorm(LinearMomentum);
+end;
+
+function TgxParticleInertia.CalculatePE(): Real;
+begin
+  // need to find potentials due to fields acting on body
+  // may be easier to do via ForceFieldEmitters?
+  Result := 0;
+end;
+
+procedure TgxParticleInertia.SetForce(x, y, z: Real);
+begin
+  fForce.x := x;
+  fForce.y := y;
+  fForce.z := z;
+end;
+
+procedure TgxParticleInertia.ApplyForce(x, y, z: Real);
+begin
+  fForce.X := fForce.X + x;
+  fForce.Y := fForce.Y + y;
+  fForce.Z := fForce.Z + z;
+end;
+
+procedure TgxParticleInertia.ApplyForce(Force: TAffineVector);
+begin
+  fForce := VectorAdd(fForce, Force);
+end;
+
+procedure TgxParticleInertia.ApplyForce(pos, Force: TAffineVector);
+// var
+// abspos:TAffineVector;
+begin
+  fForce := VectorAdd(fForce, Force);
+  // abspos:=VectorTransform(pos,R);
+  // fTorque:=VectorAdd(fTorque,VectorCrossProduct(abspos,force));
+  // fForce:=VectorAdd(fForce,force);
+end;
+
+procedure TgxParticleInertia.ApplyLocalForce(pos, Force: TAffineVector);
+// var
+// abspos:TAffineVector;
+// absForce:TAffineVector;
+begin
+  // abspos:=VectorTransform(pos,R);
+  // absForce:=VectorTransform(Force,R);
+  // fTorque:=VectorAdd(fTorque,VectorCrossProduct(abspos,absforce));
+  fForce := VectorAdd(fForce, Force);
+end;
+
+procedure TgxParticleInertia.ApplyImpulse(j, x, y, z: Real);
+begin
+  // V2 = V1 + (j/M)n
+  // V2.M = V1.M +j.n
+  LinearMomentum.X := LinearMomentum.X + j * x;
+  LinearMomentum.Y := LinearMomentum.Y + j * y;
+  LinearMomentum.Z := LinearMomentum.Z + j * z;
+end;
+
+procedure TgxParticleInertia.ApplyImpulse(j: Single; normal: TAffineVector);
+begin
+  CombineVector(LinearMomentum, normal, j);
+end;
+
+procedure TgxParticleInertia.ApplyDamping(damping: TgxDamping);
+var
+  velocity: TAffineVector;
+  v: Real;
+  dampingForce: TAffineVector;
+begin
+  velocity := VectorScale(LinearMomentum, 1 / Mass); // v = p/m
+  // apply force in opposite direction to velocity
+  v := VectorLength(velocity);
+  // F = -Normalised(V)*( Constant + (Linear)*(V) + (Quadtratic)*(V)*(V) )
+  dampingForce := VectorScale(VectorNormalize(velocity),
+    -(damping.Constant + damping.Linear * v + damping.Quadratic * v * v));
+  (*
+    dampingForce:=VectorScale(VectorNormalize(velocity),
+    -(Damping.Constant+Damping.Linear*v+Damping.Quadratic*v*v));
+  *)
+  ApplyForce(dampingForce);
+end;
+
+procedure TgxParticleInertia.SetTranslationDamping(const val: TgxDamping);
+begin
+  FTranslationDamping.Assign(val);
+end;
+
+class function TgxParticleInertia.FriendlyName: String;
+begin
+  Result := 'Particle Inertia';
+end;
+
+class function TgxParticleInertia.FriendlyDescription: String;
+begin
+  Result := 'A simple translation inertia';
+end;
+
+class function TgxParticleInertia.UniqueItem: Boolean;
+begin
+  Result := True;
+end;
+
+function TgxParticleInertia.CalcLinearPositionDot(): TAffineVector;
+begin
+  Result := VectorScale(LinearMomentum, 1 / FMass);
+  // Result:=FTranslationSpeed.AsAffineVector;
+end;
+
+function TgxParticleInertia.CalcLinearMomentumDot(): TAffineVector;
+begin
+  Result := fForce;
+end;
+
+procedure TgxParticleInertia.StateToArray(var StateArray: TStateArray;
+  StatePos: Integer);
+begin
+  // SetLength(Result,StateSize);
+  StateArray[StatePos] := LinearPosition.X; // position
+  StateArray[StatePos + 1] := LinearPosition.Y;
+  StateArray[StatePos + 2] := LinearPosition.Z;
+  StateArray[StatePos + 3] := LinearMomentum.X; // momentum
+  StateArray[StatePos + 4] := LinearMomentum.Y;
+  StateArray[StatePos + 5] := LinearMomentum.Z;
+end;
+
+procedure TgxParticleInertia.ArrayToState(StateArray: TStateArray;
+  StatePos: Integer);
+begin
+  LinearPosition.X := StateArray[StatePos];
+  LinearPosition.Y := StateArray[StatePos + 1];
+  LinearPosition.Z := StateArray[StatePos + 2];
+  LinearMomentum.X := StateArray[StatePos + 3];
+  LinearMomentum.Y := StateArray[StatePos + 4];
+  LinearMomentum.Z := StateArray[StatePos + 5];
+  // TODO change?
+  (* OwnerBaseSceneObject.position.x:=StateArray[StatePos];//position
+    OwnerBaseSceneObject.position.y:=StateArray[StatePos+1];
+    OwnerBaseSceneObject.position.z:=StateArray[StatePos+2];
+    FTranslationSpeed.X:=StateArray[StatePos+3]/fMass;//velocity
+    FTranslationSpeed.Y:=StateArray[StatePos+4]/fMass;
+    FTranslationSpeed.Z:=StateArray[StatePos+5]/fMass;
+  *)
+end;
+
+procedure TgxParticleInertia.CalcStateDot(var StateArray: TStateArray;
+  StatePos: Integer);
+var
+  LinPos, LinMom: TAffineVector;
+begin
+  LinPos := CalcLinearPositionDot();
+  LinMom := CalcLinearMomentumDot();
+  StateArray[StatePos] := LinPos.X;
+  StateArray[StatePos + 1] := LinPos.Y;
+  StateArray[StatePos + 2] := LinPos.Z;
+  StateArray[StatePos + 3] := LinMom.X;
+  StateArray[StatePos + 4] := LinMom.Y;
+  StateArray[StatePos + 5] := LinMom.Z;
+end;
+
+procedure TgxParticleInertia.MirrorTranslation;
+begin
+  FTranslationSpeed.Invert;
+end;
+
+procedure TgxParticleInertia.SurfaceBounce(const surfaceNormal: TGLVector;
+  restitution: Single);
+var
+  f: Single;
+begin
+  // does the current speed vector comply?
+  f := VectorDotProduct(FTranslationSpeed.AsVector, surfaceNormal);
+  if f < 0 then
+  begin
+    // remove the non-complying part of the speed vector
+    FTranslationSpeed.AddScaledVector(-f / VectorNorm(surfaceNormal) *
+      (1 + restitution), surfaceNormal);
+  end;
+end;
+
+function GetOrCreateParticleInertia(behaviours: TgxBehaviours)
+  : TgxParticleInertia;
+var
+  i: Integer;
+begin
+  i := behaviours.IndexOfClass(TgxParticleInertia);
+  if i >= 0 then
+    Result := TgxParticleInertia(behaviours[i])
+  else
+    Result := TgxParticleInertia.Create(behaviours);
+end;
+
+function GetOrCreateParticleInertia(obj: TgxBaseSceneObject)
+  : TgxParticleInertia;
+begin
+  Result := GetOrCreateParticleInertia(obj.behaviours);
+end;
+
+
+// -----------------------------------------------------------------------
+// ------------ TGLInertiaTensor
+// -----------------------------------------------------------------------
+
+constructor TGLInertiaTensor.Create(aOwner: TPersistent);
+begin
+  inherited Create(aOwner);
+  fm11 := 1;
+  fm22 := 1;
+  fm33 := 1;
+end;
+
+destructor TGLInertiaTensor.Destroy;
+begin
+  inherited Destroy;
+end;
+
+procedure TGLInertiaTensor.Assign(Source: TPersistent);
+begin
+  inherited;
+  fm11 := TGLInertiaTensor(Source).fm11;
+  fm12 := TGLInertiaTensor(Source).fm12;
+  fm13 := TGLInertiaTensor(Source).fm13;
+  fm21 := TGLInertiaTensor(Source).fm21;
+  fm22 := TGLInertiaTensor(Source).fm22;
+  fm23 := TGLInertiaTensor(Source).fm23;
+  fm31 := TGLInertiaTensor(Source).fm31;
+  fm32 := TGLInertiaTensor(Source).fm32;
+  fm33 := TGLInertiaTensor(Source).fm33;
+end;
+
+procedure TGLInertiaTensor.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    WriteInteger(0); // Archive Version 0
+    WriteFloat(fm11);
+    WriteFloat(fm12);
+    WriteFloat(fm13);
+    WriteFloat(fm21);
+    WriteFloat(fm22);
+    WriteFloat(fm23);
+    WriteFloat(fm31);
+    WriteFloat(fm32);
+    WriteFloat(fm33);
+  end;
+end;
+
+procedure TGLInertiaTensor.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    ReadInteger(); // Archive Version 0
+    fm11 := ReadFloat();
+    fm12 := ReadFloat();
+    fm13 := ReadFloat();
+    fm21 := ReadFloat();
+    fm22 := ReadFloat();
+    fm23 := ReadFloat();
+    fm31 := ReadFloat();
+    fm32 := ReadFloat();
+    fm33 := ReadFloat();
+  end;
+end;
+
+//--------------------------
+// TGLRigidBodyInertia
+//--------------------------
+procedure TGLRigidBodyInertia.SetInertiaTensor(newVal: TGLInertiaTensor);
+begin
+  fInertiaTensor := newVal;
+end;
+
+procedure TGLRigidBodyInertia.SetRotationSpeed(const val: TgCoordinates);
+begin
+  AngularMomentum := VectorTransform(val.AsAffineVector, fBodyInertiaTensor);
+  fRotationSpeed.Assign(val);
+end;
+
+procedure TGLRigidBodyInertia.SetRotationDamping(const val: TgxDamping);
+begin
+  FRotationDamping.Assign(val);
+end;
+
+procedure TGLRigidBodyInertia.ApplyImpulse(j, xpos, ypos, zpos, x, y, z: Real);
+begin
+  // V2 = V1 + (j/M)n
+  // V2.M = V1.M +j.n
+  LinearMomentum.X := LinearMomentum.X + j * x;
+  LinearMomentum.Y := LinearMomentum.Y + j * y;
+  LinearMomentum.Z := LinearMomentum.Z + j * z;
+
+  AngularMomentum.X := AngularMomentum.X + j * x * xpos;
+  AngularMomentum.Y := AngularMomentum.Y + j * y * ypos;
+  AngularMomentum.Z := AngularMomentum.Z + j * z * zpos;
+end;
+
+procedure TGLRigidBodyInertia.ApplyImpulse(j: Single;
+  position, normal: TAffineVector);
+begin
+  CombineVector(LinearMomentum, normal, j);
+  CombineVector(AngularMomentum, VectorCrossProduct(position, normal), j); // ?
+end;
+
+procedure TGLRigidBodyInertia.ApplyDamping(damping: TgxDamping);
+var
+  velocity, angularvelocity: TAffineVector;
+  v, angularv: Real;
+  dampingForce: TAffineVector;
+  angulardampingForce: TAffineVector;
+begin
+  velocity := VectorScale(LinearMomentum, 1 / Mass); // v = p/m
+  // apply force in opposite direction to velocity
+  v := VectorLength(velocity);
+  // F = -Normalised(V)*( Constant + (Linear)*(V) + (Quadtratic)*(V)*(V) )
+  dampingForce := VectorScale(VectorNormalize(velocity),
+    -(damping.Constant + damping.Linear * v + damping.Quadratic * v * v));
+  // ScaleVector(AngularMomentum,0.999);
+  // ScaleVector(AngularVelocity,Damping.Constant);
+  // dampingForce:=VectorScale(VectorNormalize(velocity),-(Damping.Constant+Damping.Linear*v+Damping.Quadratic*v*v));
+  ApplyForce(dampingForce);
+
+  angularvelocity := RotationSpeed.AsAffineVector; // v = p/m
+  // apply force in opposite direction to velocity
+  angularv := VectorLength(angularvelocity);
+  // F = -Normalised(V)*( Constant + (Linear)*(V) + (Quadtratic)*(V)*(V) )
+  angulardampingForce := VectorScale(VectorNormalize(angularvelocity),
+    -(RotationDamping.Constant + RotationDamping.Linear * v +
+    RotationDamping.Quadratic * v * v));
+  // ScaleVector(AngularMomentum,0.999);
+  // ScaleVector(AngularVelocity,Damping.Constant);
+  // dampingForce:=VectorScale(VectorNormalize(velocity),-(Damping.Constant+Damping.Linear*v+Damping.Quadratic*v*v));
+  ApplyTorque(angulardampingForce.X, angulardampingForce.Y, angulardampingForce.Z);
+
+end;
+
+procedure TGLRigidBodyInertia.CalcStateDot(var StateArray: TStateArray;
+  StatePos: Integer);
+var
+  LinPos, LinMom, AngMom: TAffineVector;
+  AngPos: TQuaternion;
+begin
+  LinPos := CalcLinearPositionDot();
+  LinMom := CalcLinearMomentumDot();
+  AngPos := CalcAngularOrientationDot();
+  AngMom := CalcAngularVelocityDot();
+  // SetLength(Result,StateSize);
+  StateArray[StatePos] := LinPos.X;
+  StateArray[StatePos + 1] := LinPos.Y;
+  StateArray[StatePos + 2] := LinPos.Z;
+  StateArray[StatePos + 3] := LinMom.X;
+  StateArray[StatePos + 4] := LinMom.Y;
+  StateArray[StatePos + 5] := LinMom.Z;
+  StateArray[StatePos + 6] := AngPos.imagPart.X;
+  StateArray[StatePos + 7] := AngPos.imagPart.Y;
+  StateArray[StatePos + 8] := AngPos.imagPart.Z;
+  StateArray[StatePos + 9] := AngPos.RealPart;
+  StateArray[StatePos + 10] := AngMom.X;
+  StateArray[StatePos + 11] := AngMom.Y;
+  StateArray[StatePos + 12] := AngMom.Z;
+end;
+
+function TGLRigidBodyInertia.CalculateKE(): Real;
+begin
+  // Result:= "Linear KE" + "Angular KE"
+  // only linear part so far
+  Result := 1 / (2 * Mass) * VectorNorm(LinearMomentum);
+end;
+
+function TGLRigidBodyInertia.CalculatePE(): Real;
+begin
+  // need to find potentials due to fields acting on body
+  // may be easier to do via forcefieldemitters?
+  Result := 0;
+end;
+
+function TGLRigidBodyInertia.CalcAngularOrientationDot(): TQuaternion;
+var
+  q1: TQuaternion;
+begin
+  q1.imagPart := VectorScale(RotationSpeed.AsAffineVector, 1 / 2); // v1;
+  q1.RealPart := 0;
+  Result := QuaternionMultiply(q1, AngularOrientation);
+end;
+
+function TGLRigidBodyInertia.CalcAngularVelocityDot(): TAffineVector;
+begin
+  Result := fTorque;
+end;
+
+function TGLRigidBodyInertia.QuaternionToString(Quat: TQuaternion): String;
+begin
+  Result := '<Quaternion><imagPart>' + FloatToSTr(Quat.imagPart.X) + ',' +
+    FloatToSTr(Quat.imagPart.Y) + ',' + FloatToSTr(Quat.imagPart.Z) +
+    '</imagPart><realPart>' + FloatToSTr(Quat.RealPart) +
+    '</realPart><Quaternion>';
+end;
+
+(*
+ function TGLRigidBodyInertia.Star(Vector:TAffineVector):TGLMatrix;
+  begin
+  Result.X.X:=0;             Result[0][1]:=-Vector[2];  Result[0][2]:=Vector[1];  Result[0][3]:=0;
+  Result[1][0]:=Vector[2];   Result[1][1]:=0;           Result[1][2]:=-Vector[0]; Result[1][3]:=0;
+  Result[2][0]:=Vector[1];   Result[2][1]:=Vector[0];   Result[2][2]:=0;          Result[2][3]:=0;
+  Result[3][0]:=0;           Result[3][1]:=0;            Result[3][2]:=0;          Result[3][3]:=1;
+  end;
+*)
+
+procedure TGLRigidBodyInertia.SetTorque(x, y, z: Real);
+begin
+  fTorque.X := x;
+  fTorque.Y := y;
+  fTorque.Z := z;
+end;
+
+procedure TGLRigidBodyInertia.ApplyTorque(x, y, z: Real);
+begin
+  fTorque.X := fTorque.X + x;
+  fTorque.Y := fTorque.Y + y;
+  fTorque.Z := fTorque.Z + z;
+end;
+
+(*
+procedure TGLRigidBodyInertia.ApplyImpulse(x,y,z:Real);
+  begin
+  //
+  end;
+*)
+
+procedure TGLRigidBodyInertia.RemoveForces();
+begin
+  fForce := nullVector;
+  fTorque := nullVector;
+end;
+
+procedure TGLRigidBodyInertia.ApplyForce(pos, Force: TVector3f);
+var
+  abspos: TAffineVector;
+begin
+  abspos := VectorTransform(pos, R);
+  fTorque := VectorAdd(fTorque, VectorCrossProduct(abspos, Force));
+  fForce := VectorAdd(fForce, Force);
+end;
+
+procedure TGLRigidBodyInertia.ApplyLocalForce(pos, Force: TVector3f);
+var
+  abspos: TAffineVector;
+  absForce: TAffineVector;
+begin
+  abspos := VectorTransform(pos, R);
+  absForce := VectorTransform(Force, R);
+  fTorque := VectorAdd(fTorque, VectorCrossProduct(abspos, absForce));
+  fForce := VectorAdd(fForce, absForce);
+end;
+
+procedure TGLRigidBodyInertia.ApplyLocalImpulse(xpos, ypos, zpos, x, y,
+  z: Real);
+begin
+  //
+end;
+
+procedure TGLRigidBodyInertia.SetUpStartingState();
+begin
+  //
+  inherited SetUpStartingState();
+  fBodyInertiaTensor.X.X := InertiaTensor.fm11;
+  fBodyInertiaTensor.X.Y := InertiaTensor.fm12;
+  fBodyInertiaTensor.X.Z := InertiaTensor.fm13;
+  fBodyInertiaTensor.Y.X := InertiaTensor.fm21;
+  fBodyInertiaTensor.Y.Y  := InertiaTensor.fm22;
+  fBodyInertiaTensor.Y.Z  := InertiaTensor.fm23;
+  fBodyInertiaTensor.Z.X := InertiaTensor.fm31;
+  fBodyInertiaTensor.Z.Y := InertiaTensor.fm32;
+  fBodyInertiaTensor.Z.Z  := InertiaTensor.fm33;
+
+  fBodyInverseInertiaTensor := fBodyInertiaTensor;
+
+  InvertMatrix(fBodyInverseInertiaTensor);
+  // Write
+  (*
+    Messagedlg('setting BodyIit: '+ Format('%f,%f,%f,%f,%f,%f,%f,%f,%f',
+    [fBodyInverseInertiaTensor[0][0],fBodyInverseInertiaTensor[0][1],fBodyInverseInertiaTensor[0][2],
+     fBodyInverseInertiaTensor[1][0],fBodyInverseInertiaTensor[1][1],fBodyInverseInertiaTensor[1][2],
+     fBodyInverseInertiaTensor[2][0],fBodyInverseInertiaTensor[2][1],
+     fBodyInverseInertiaTensor[2][2]]),mtinformation,[mbok],0);
+  *)
+  AngularOrientation := IdentityQuaternion;
+  AngularMomentum := VectorTransform(RotationSpeed.AsAffineVector,
+    fBodyInertiaTensor);
+end;
+
+procedure TGLRigidBodyInertia.CalcAuxiliary();
+var
+  IRt: TAffineMAtrix;
+  Rt: TAffineMAtrix;
+  Scale: TAffineVector;
+  RMatrix: TGLMatrix;
+begin
+  // TODO: sort this out
+  fBodyInverseInertiaTensor := IdentityMatrix;
+  // compute auxiliary variables
+  R := QuaternionToAffineMatrix(AngularOrientation);
+  Rt := R;
+  TransposeMatrix(Rt);
+
+  IRt := MatrixMultiply(fBodyInverseInertiaTensor, Rt);
+  InverseInertiaTensor := MatrixMultiply(R, IRt);
+
+  RotationSpeed.AsAffineVector := VectorTransform(AngularMomentum,
+    InverseInertiaTensor);
+  TranslationSpeed.AsAffineVector := VectorScale(LinearMomentum, 1 / Mass);
+
+  Scale := OwnerBaseSceneObject.Scale.AsAffineVector;
+  OwnerBaseSceneObject.BeginUpdate;
+
+  SetMatrix(RMatrix, R);
+  OwnerBaseSceneObject.SetMatrix(RMatrix);
+  // OwnerBaseSceneObject.Matrix:=QuaternionToMatrix(AngularOrientation);
+  OwnerBaseSceneObject.Scale.AsAffineVector := Scale;
+
+  OwnerBaseSceneObject.position.x := LinearPosition.X; // position
+  OwnerBaseSceneObject.position.y := LinearPosition.Y;
+  OwnerBaseSceneObject.position.z := LinearPosition.Z;
+  OwnerBaseSceneObject.EndUpdate;
+end;
+
+procedure TGLRigidBodyInertia.StateToArray(var StateArray: TStateArray;
+  StatePos: Integer);
+begin
+  // with State do
+  begin
+    // copy Linear Position
+    StateArray[StatePos] := LinearPosition.X;
+    StateArray[StatePos + 1] := LinearPosition.Y;
+    StateArray[StatePos + 2] := LinearPosition.Z;
+    // copy Linear Momentum
+    StateArray[StatePos + 3] := LinearMomentum.X;
+    StateArray[StatePos + 4] := LinearMomentum.Y;
+    StateArray[StatePos + 5] := LinearMomentum.Z;
+    // copy Angular Orientation
+    StateArray[StatePos + 6] := AngularOrientation.imagPart.X;
+    StateArray[StatePos + 7] := AngularOrientation.imagPart.Y;
+    StateArray[StatePos + 8] := AngularOrientation.imagPart.Z;
+    StateArray[StatePos + 9] := AngularOrientation.RealPart;
+    // copy Angular Momentum
+    StateArray[StatePos + 10] := AngularMomentum.X;
+    StateArray[StatePos + 11] := AngularMomentum.Y;
+    StateArray[StatePos + 12] := AngularMomentum.Z;
+  end;
+end;
+
+procedure TGLRigidBodyInertia.ArrayToState( { var } StateArray: TStateArray;
+  StatePos: Integer);
+begin
+  // restore Linear Position
+  LinearPosition.X := StateArray[StatePos];
+  LinearPosition.Y := StateArray[StatePos + 1];
+  LinearPosition.Z := StateArray[StatePos + 2];
+  // restore Linear Momentum
+  LinearMomentum.X := StateArray[StatePos + 3];
+  LinearMomentum.Y := StateArray[StatePos + 4];
+  LinearMomentum.Z := StateArray[StatePos + 5];
+  // restore Angular Orientation
+  AngularOrientation.imagPart.X := StateArray[StatePos + 6];
+  AngularOrientation.imagPart.Y := StateArray[StatePos + 7];
+  AngularOrientation.imagPart.Z := StateArray[StatePos + 8];
+  AngularOrientation.RealPart := StateArray[StatePos + 9];
+  // restore Angular Momentum
+  AngularMomentum.X := StateArray[StatePos + 10];
+  AngularMomentum.Y := StateArray[StatePos + 11];
+  AngularMomentum.Z := StateArray[StatePos + 12];
+end;
+
+procedure TGLRigidBodyInertia.SetLinearDamping(const val: TgxDamping);
+begin
+  // FLinearDamping.Assign(val);
+end;
+
+
+procedure TGLRigidBodyInertia.SetAngularDamping(const val: TgxDamping);
+begin
+  // FAngularDamping.Assign(val);
+end;
+
+
+constructor TGLRigidBodyInertia.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+  Mass := 1;
+  fDensity := 1;
+  StateSize := 13;
+
+  fInertiaTensor := TGLInertiaTensor.Create(Self);
+  fRotationSpeed := TgCoordinates.CreateInitialized(Self, VectorMake(0, 0, 0));
+
+  // LinearPosition:=OwnerBaseSceneObject.Position.AsAffineVector;
+  AngularOrientation := IdentityQuaternion; // fromAngleAxis(0,XVector);
+
+  fTorque := nullVector;
+  fForce := nullVector;
+
+  // DampingEnabled:=False;
+  // FTranslationDamping:=TgxDamping.Create(Self);
+  FRotationDamping := TgxDamping.Create(Self);
+  // RotationDamping:=TgxDamping.Create(Self);
+
+  R := IdentityMatrix;
+  InverseInertiaTensor := IdentityMatrix;
+
+  // CalcAuxiliary();
+  // SetDESolver(ssEuler);
+end;
+
+//---------------------------------------------------------------------------
+
+destructor TGLRigidBodyInertia.Destroy;
+begin
+  // FLinearDamping.Free;
+  // FAngularDamping.Free;
+  fInertiaTensor.Free();
+  fRotationSpeed.Free();
+  FRotationDamping.Free;
+
+  inherited Destroy;
+end;
+
+procedure TGLRigidBodyInertia.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    // FRigidBody.Assign(TGLRigidBodyInertia(Source));
+
+    Mass := TGLRigidBodyInertia(Source).Mass;
+    fDensity := TGLRigidBodyInertia(Source).fDensity;
+    fBodyInertiaTensor := TGLRigidBodyInertia(Source).fBodyInertiaTensor;
+    fBodyInverseInertiaTensor := TGLRigidBodyInertia(Source)
+      .fBodyInverseInertiaTensor;
+
+    InertiaTensor.Assign(TGLRigidBodyInertia(Source).InertiaTensor);
+
+    LinearPosition := TGLRigidBodyInertia(Source).LinearPosition;
+    AngularOrientation := TGLRigidBodyInertia(Source).AngularOrientation;
+
+    LinearMomentum := TGLRigidBodyInertia(Source).LinearMomentum;
+    AngularMomentum := TGLRigidBodyInertia(Source).AngularMomentum;
+
+    // TranslationSpeed.AsAffineVector:=TGLRigidBodyInertia(Source).TranslationSpeed.AsAffineVector;
+    RotationSpeed.Assign(TGLRigidBodyInertia(Source).RotationSpeed);
+
+    // fForce:=TGLRigidBodyInertia(Source).fForce;
+    fTorque := TGLRigidBodyInertia(Source).fTorque;
+
+    // fInverseInertiaTensor:=TGLRigidBodyInertia(Source).fInverseInertiaTensor;
+
+    // RigidBody.fTorque:=TGLRigidBodyInertia(Source).fTorque;
+    // RigidBody.fForce:=TGLRigidBodyInertia(Source).fForce;
+
+    FRotationDamping.Assign(TGLRigidBodyInertia(Source).FRotationDamping);
+
+    // DampingEnabled:=TGLRigidBodyInertia(Source).DampingEnabled;
+    // FTranslationDamping.Assign(TGLRigidBodyInertia(Source).LinearDamping);
+    // FRotationDamping.Assign(TGLRigidBodyInertia(Source).AngularDamping);
+
+  end;
+  inherited Assign(Source);
+end;
+
+class function TGLRigidBodyInertia.FriendlyName: String;
+begin
+  Result := 'Rigid Body Inertia';
+end;
+
+class function TGLRigidBodyInertia.FriendlyDescription: String;
+begin
+  Result := 'An inertia model for rigid bodies';
+end;
+
+class function TGLRigidBodyInertia.UniqueItem: Boolean;
+begin
+  Result := True;
+end;
+
+// **************************************************************************
+// *****************      DoProgress     ************************************
+// **************************************************************************
+
+(*
+procedure TGLRigidBodyInertia.DoProgress(const progressTime : TProgressTimes);
+  var
+  TempScale:TaffineVector;
+  UndampedLinearMomentum,DampedLinearMomentum:Real;
+  UnDampedAngularMomentum,DampedAngularMomentum:Real;
+  i:integer;
+  begin
+  // Write('Calculating next state...');
+
+  with OwnerBaseSceneObject do
+  with progressTime do
+  begin
+
+  if (DampingEnabled=true) then
+  begin
+  UndampedLinearMomentum:=VectorLength(LinearMomentum);
+  DampedLinearMomentum:=TranslationDamping.Calculate(UndampedLinearMomentum,deltaTime);
+  {   if GLScene.VectorGeometry.vSIMD=1 then
+  //  RigidBody.LinearMomentum:=VectorScale(VectorNormalize(RigidBody.LinearMomentum),DampedLinearMomentum)
+  else
+  }        begin
+  if Length(LinearMomentum)<>0 then
+  LinearMomentum:=VectorScale(VectorNormalize(LinearMomentum),DampedLinearMomentum)
+  else
+  LinearMomentum:=NullVector; //line not required
+  end;
+
+  UndampedAngularMomentum:=VectorLength(AngularMomentum);
+  DampedAngularMomentum:=RotationDamping.Calculate(UndampedAngularMomentum,deltaTime);
+  AngularMomentum:=VectorScale(VectorNormalize(AngularMomentum),DampedAngularMomentum);
+
+  //     ApplyForce(VectorScale(RigidBody.LinearVelocity,-0.5));    //Either apply resistive force & torque
+  //     ApplyTorque(VectorLength(RigidBody.AngularVelocity));      //or use TgxDamping
+  end;
+
+  //      Euler(RigidBody,deltaTime);
+  //      RungeKutta4(DeltaTime);
+  //DESolver(RigidBody,DeltaTime);
+
+  //update OwnerBaseSceneObject
+  TempScale:=Scale.AsAffineVector;
+  Matrix:=QuaternionToMatrix(AngularOrientation);
+
+  position.AsAffineVector:=LinearPosition;
+  Scale.AsAffineVector:=TempScale;
+
+  //calc auxiliary variables for next iteration
+  CalcAuxiliary();
+  end;
+  end;
+*)
+
+procedure TGLRigidBodyInertia.WriteToFiler(writer: TWriter);
+begin
+  inherited WriteToFiler(writer);
+  with writer do
+  begin
+    // WriteInteger(0); // Archive Version 0
+    // FRigidBody.WriteToFiler(writer);
+    // WriteFloat(fMass);
+    WriteFloat(fDensity);
+    Write(fBodyInertiaTensor, SizeOf(fBodyInertiaTensor));
+    Write(fBodyInverseInertiaTensor, SizeOf(fBodyInverseInertiaTensor));
+
+    fInertiaTensor.WriteToFiler(writer);
+
+    Write(AngularOrientation, SizeOf(AngularOrientation));
+    Write(AngularMomentum, SizeOf(AngularMomentum));
+
+    // Write(LinearVelocity,SizeOf(LinearVelocity));
+    RotationSpeed.WriteToFiler(writer);
+    // Write(AngularVelocity,SizeOf(AngularVelocity));
+
+    Write(fTorque, SizeOf(fTorque));
+    // Write(fForce,SizeOf(fForce));
+
+    FRotationDamping.WriteToFiler(writer);
+
+    // WriteInteger(Integer(FDESolverType));
+    // WriteBoolean(FDampingEnabled);
+    // FLinearDamping.WriteToFiler(writer);
+    // FAngularDamping.WriteToFiler(writer);
+  end;
+end;
+
+procedure TGLRigidBodyInertia.ReadFromFiler(reader: TReader);
+begin
+  inherited ReadFromFiler(reader);
+  with reader do
+  begin
+    // ReadInteger; // ignore archiveVersion
+    // FRigidBody.ReadFromFiler(Reader);
+    // fMass:=ReadFloat;
+    fDensity := ReadFloat;
+    Read(fBodyInertiaTensor, SizeOf(fBodyInertiaTensor));
+    Read(fBodyInverseInertiaTensor, SizeOf(fBodyInverseInertiaTensor));
+
+    InertiaTensor.ReadFromFiler(reader);
+
+    Read(AngularOrientation, SizeOf(AngularOrientation));
+    Read(AngularMomentum, SizeOf(AngularMomentum));
+
+    // Read(LinearVelocity,SizeOf(LinearVelocity));
+    RotationSpeed.ReadFromFiler(reader);
+    // Read(AngularVelocity,SizeOf(AngularVelocity));
+
+    Read(fTorque, SizeOf(fTorque));
+    // Read(fForce, SizeOf(fForce));
+
+    FRotationDamping.ReadFromFiler(reader);
+    // SetDESolver(TDESolverType(ReadInteger));
+    // FDampingEnabled:=ReadBoolean;
+    // FLinearDamping.ReadFromFiler(reader);
+    // FAngularDamping.ReadFromFiler(reader);
+  end;
+  // SetDESolver(fDESolverType);
+  // CalcAuxiliary();
+  SetUpStartingState();
+end;
+
+function GetOrCreateRigidBodyInertia(behaviours: TgxBehaviours)
+  : TGLRigidBodyInertia;
+var
+  i: Integer;
+begin
+  i := behaviours.IndexOfClass(TGLRigidBodyInertia);
+  if i >= 0 then
+    Result := TGLRigidBodyInertia(behaviours[i])
+  else
+    Result := TGLRigidBodyInertia.Create(behaviours);
+end;
+
+function GetOrCreateRigidBodyInertia(obj: TgxBaseSceneObject)
+  : TGLRigidBodyInertia;
+begin
+  Result := GetOrCreateRigidBodyInertia(obj.behaviours);
+end;
+
+// ------------------------------------------------------------------
+initialization
+// ------------------------------------------------------------------
+
+// class registrations
+RegisterXCollectionItemClass(TgxParticleInertia);
+RegisterXCollectionItemClass(TGLRigidBodyInertia);
+
+end.

+ 263 - 0
Sourcex/GXS.PhysJoints.pas

@@ -0,0 +1,263 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit GXS.PhysJoints;
+
+(*
+  This unit isn't used at all at the moment, just putting down some ideas
+  for serial-link manipulators
+*)
+
+interface
+
+uses
+  GXS.Scene,
+  GLScene.VectorTypes,
+  GLScene.VectorGeometry;
+
+type
+
+  (*
+    //
+    //                         Joint(Z1)      Joint(Z3)
+    //                          / \            |_| (Wrist)
+    //                         / \/\           //
+    //                        / / \ \         //
+    //                       / /   \ \(1)    //(2)
+    //             Link(0)  / /     \ \     //
+    //                     / /       \ \   //
+    //                    / /         \ \ //
+    //                   / /           \/\/
+    //         Joint(Z0)/ /             \/
+    //               |------|          Joint(Z2)
+    //               | Base |
+    //     --------------------------------------------
+    //     X(n) = Common normal between joint axis Z(n-1) & Z(n)
+  *)
+
+  TGLBaseJoint = class(TObject)
+  end;
+
+  TGLBaseLink = class(TObject)
+  end;
+
+  TGLJoint = class(TGLBaseJoint)
+    Link1: TGLBaseLink; // if Link1 is nil, assumed to be base
+    Link2: TGLBaseLink; // if Link2 is nil, assumed to be wrist
+    // Object1:TgxBaseSceneObject;
+    // Object2:TgxBaseSceneObject;
+  end;
+
+  // Links are mainly for used for Serial-Link manipulators
+
+  // Direct & Inverse Kinematics algorithms are planned
+  TGLLink = class(TGLBaseLink)
+    // Link Parameters
+    fLinkLength: Real; // Length of common normal which is orthogonal to both
+    // joint axes Z[n-1] and Z[n] (a.k.a.  L)
+    fTwistAngle: Real; // Twist angle between joint axes, if joint frames were
+    // coincident (a.k.a.  Theta?)
+    fLinkAngle: Real;
+    // Angle between common normals X[n-1] and X[n] (a.k.a.  Alpha?)
+    fLinkDistance: Real;
+    // Distance along joint axis Z[n-1] between intersection
+    // points of common normals X[n-1] and X[n] (a.k.a.  d)
+(*
+    //
+    // A-Matrix
+    // [ Cos(Theta)   -Sin(Theta)*Cos(Alpha)    Sin(Theta)*Sin(Alpha)   L*Cos(Theta) ]
+    // [ Sin(Theta)    Cos(Theta)*cos(Alpha)   -Cos(Theta)*Sin(Alpha)   L*Sin(Theta) ]
+    // [    0            Sin(Alpha)                   Cos(Alpha)           d         ]
+    // [    0               0                            0                 1         ]
+    //
+*)
+    A: TGLMatrix;
+    constructor Create(LinkLength, TwistAngle, LinkAngle, LinkDistance: Real);
+    // constructor Create();virtual;
+  end;
+
+  // see html file for description of the different links
+(*
+  // Type 1 Two-Link Manipulator
+  //
+  // _ ________
+  // / \        \
+  // / \/________/
+  // /  /
+  // /  /
+  // /  /
+  // /  /
+  // /  /
+  // \_/
+  //
+*)
+  TGLType1Link = class(TGLLink)
+    Length: Real; // fixed
+    Angle: Real; // variable
+(*
+    // A-Matrix
+    // [ C1   -S1    0    L1C1 ]
+    // [ S1    C1    0    L1S1 ]
+    // [  0     0    1      0  ]
+    // [  0     0    0      1  ]
+    //
+*)
+    constructor Create(Length, Angle: Real);
+  end;
+(*
+  // Type 2 Two-Link Manipulator
+  // ___
+  // /   \___________________
+  // | + |___________________|
+  // \   /
+  // | |
+  // | |
+  // | |
+  // | |
+  // | |
+  // | |
+  // __|_|__
+  // |___.___|
+  //
+*)
+  TGLType2Link = class(TGLLink)
+    Length: Real; // fixed
+    Angle: Real; // variable
+    constructor Create(Length, Angle: Real);
+  end;
+(*
+  // Type 3 Two-Link Manipulator
+  // _______
+  // _________|       |__
+  // <-|_________|       |__|->
+  // |__   __|
+  // | |
+  // | |
+  // | |
+  // | |
+  // | |
+  // _|_|_
+  // |__.__|
+*)
+  TGLType3Link = class(TGLLink)
+    Length: Real; // fixed
+    Angle: Real; // variable
+(*
+    // A-Matrix
+    // [  1    0    0    0  ]
+    // [  0    1    0    0  ]
+    // [  0    0    1    d2 ]
+    // [  0    0    0    1  ]
+    //
+*)
+    constructor Create(Length, Angle: Real);
+  end;
+
+  TGLType4Link = class(TGLLink)
+    Length: Real; // fixed
+    Angle: Real; // variable
+    constructor Create(Length, Angle: Real);
+  end;
+(*
+  // Type 5 Two-Link Manipulator
+  //
+  // _
+  // ________|_|__
+  // <-|_____________|->
+  // | |
+  // | |
+  // | |
+  // | |
+  // | |
+  // __| |__
+  // |__| |__|
+  // |_|
+  // |
+  // V
+  //
+*)
+  TGLType5Link = class(TGLLink)
+    Length: Real; // variable
+    constructor Create(Length, Angle: Real);
+  end;
+
+  TGLType6Link = class(TGLLink)
+    Length: Real; // fixed
+    Angle: Real; // variable
+    constructor Create(Length, Angle: Real);
+  end;
+
+  TGLType7Link = class(TGLLink)
+    Length: Real; // fixed
+    Angle: Real; // variable
+    constructor Create(Length, Angle: Real);
+  end;
+
+  TGLType8Link = class(TGLLink)
+    Length: Real; // variable
+    constructor Create(Length, Angle: Real);
+  end;
+
+  TGLPrismaticJoint = class(TGLJoint)
+  end;
+
+  TGLRevoluteJoint = class(TGLJoint)
+  end;
+
+  TGLBallAndSocketJoint = class(TGLJoint)
+  end;
+
+implementation //--------------------------------------------------------------
+
+constructor TGLLink.Create(LinkLength, TwistAngle, LinkAngle,
+  LinkDistance: Real);
+begin
+  fLinkLength := LinkLength;
+  fTwistAngle := TwistAngle;
+  fLinkAngle := LinkAngle;
+  fLinkDistance := LinkDistance;
+end;
+
+constructor TGLType1Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType2Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType3Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType4Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType5Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType6Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType7Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+constructor TGLType8Link.Create(Length, Angle: Real);
+begin
+  inherited Create(Length, 0, Angle, 0);
+end;
+
+//---------------------------------------------------------------------------
+
+end.

+ 894 - 0
Sourcex/GXS.PhysManager.pas

@@ -0,0 +1,894 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit GXS.PhysManager;
+
+(* The Manager for Scene Physics Interactions (Phys) *)
+
+interface
+
+uses
+  System.Classes,
+  System.SysUtils,
+
+  GLScene.XCollection,
+  GLScene.VectorGeometry,
+  GXS.Scene,
+  GXS.PhysForces,
+  GXS.Behaviours;
+
+type
+
+  // only ssEuler is usable at the moment
+  TDESolverType = (ssEuler, ssRungeKutta4, ssVerlet);
+  // TDESolver = procedure((*RigidBody:TgxRigidBody;*)DeltaTime:Real) of object;
+  TStateArray = array of Real;
+  TgxPhysManager = class;
+
+  (*
+    ***Euler***, EulerImproved, EulerModified, MidPoint
+    RungeKutta2, ***RungeKutta4***, RungKutta4Adaptive
+    State Variables:  Position,  Velocity
+
+    Verlet
+    State Variables:  Position, Old Position
+  *)
+
+  // need to have state array(s) seperate from inertias to allow for implicit & explicit methods
+  TDESolver = class(TObject)
+  public
+    StateSize: Integer;
+    StateArray: TStateArray;
+    Owner: TgxPhysManager;
+    function StateToArray(): TStateArray; virtual;
+    procedure ArrayToState(StateArray: TStateArray); virtual;
+    procedure Solve(DeltaTime: Real); virtual; abstract;
+    constructor Create(aOwner: TgxPhysManager); // override; //abstract;
+    destructor Destroy; override;
+    // procedure Assign(Source: TPersistent); override;
+  end;
+
+  // explicit   e.g. Euler, Mid-point, Runge-Kutta integration
+  TDESolverExplicit = class(TDESolver)
+  public
+    StateArrayDot: TStateArray; // Velocity stored
+    function CalcStateDot(): TStateArray; virtual;
+  end;
+
+  TDESolverEuler = class(TDESolverExplicit)
+  public
+    procedure Solve(DeltaTime: Real); override;
+  end;
+
+  TDESolverRungeKutta4 = class(TDESolverExplicit)
+  public
+    procedure Solve(DeltaTime: Real); override;
+  end;
+
+  // implicit   e.g. Verlet Integration
+  TDESolverImplicit = class(TDESolver)
+  public
+    LastStateArray: TStateArray; // Last state stored
+  end;
+
+  TDESolverVerlet = class(TDESolverImplicit)
+  public
+  end;
+
+  TgxForces = class;
+  TgxBaseForceFieldEmitter = class;
+  // TgxPhysManager = class;
+
+  (* purpose of TgxBaseInertia is to allow for inertias that may be constrained
+   to 1 or 2 dimensions
+   Shouldn't be used directly, instead use TgxParticleInertia (for a 3D particle)
+   TgxRigidBodyInertia (for a 3D rigid-body) or define a new sub-class
+   e.g.  Tgx1DParticleInertia, this will allow for faster speed *)
+  TgxBaseInertia = class(TgxBehaviour)
+  private
+    FDampingEnabled: Boolean;
+    FManager: TgxPhysManager;
+    FManagerName: String; // NOT persistent, temporarily used for persistence
+  protected
+    procedure Loaded; override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+  public
+    StateSize: Integer; // don't re-declare this in sub-classes
+    // just initialise it in constructor
+    procedure StateToArray(var StateArray: TStateArray;
+      StatePos: Integer); virtual;
+    procedure ArrayToState( { var } StateArray: TStateArray;
+      StatePos: Integer); virtual;
+    procedure CalcStateDot(var StateArray: TStateArray;
+      StatePos: Integer); virtual;
+    procedure RemoveForces(); virtual;
+    procedure CalculateForceFieldForce(ForceFieldEmitter
+      : TgxBaseForceFieldEmitter); virtual;
+    procedure CalcAuxiliary(); virtual;
+    procedure SetUpStartingState(); virtual;
+    function CalculateKE(): Real; virtual;
+    function CalculatePE(): Real; virtual;
+    constructor Create(aOwner: TXCollection); override; // abstract;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure SetManager(const val: TgxPhysManager);
+  published
+    property DampingEnabled: Boolean read FDampingEnabled write FDampingEnabled;
+    property Manager: TgxPhysManager read FManager write SetManager;
+  end;
+
+  (* A base for different types of force-field behaviours *)
+  TgxBaseForceFieldEmitter = class(TgxBehaviour)
+  private
+    FManager: TgxPhysManager;
+    FManagerName: String; // NOT persistent, temporarily used for persistence
+  protected
+    procedure Loaded; override;
+    procedure WriteToFiler(writer: TWriter); override;
+    procedure ReadFromFiler(reader: TReader); override;
+  public
+    constructor Create(aOwner: TXCollection); override; // abstract;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure SetManager(const val: TgxPhysManager);
+    function CalculateForceField(Body: TgxBaseSceneObject): TAffineVector; virtual;
+  published
+    property Manager: TgxPhysManager read FManager write SetManager;
+  end;
+
+  (* The Simple Physics Interaction (SPI) manager can only deal with objects from one scene
+    More than one physics manager can be assigned to a scene *)
+  TgxPhysManager = class(TComponent)
+    // StateSize:Integer;
+  protected
+    fInertias: TList; // list of all inertias with manager = self
+    fForceFieldEmitters: TList; // list of all forcefield emitters
+    fForces: TgxForces; // Collection of forces acting on/between objects
+    fDESolverType: TDESolverType;
+    DESolver: TDESolver;
+    fScene: TgxScene;
+  protected
+    procedure Loaded; override;
+    procedure DefineProperties(Filer: TFiler); override;
+    procedure WriteForces(stream: TStream);
+    procedure ReadForces(stream: TStream);
+    procedure SetForces(const val: TgxForces);
+    function GetForces: TgxForces;
+    procedure SetInertias(const val: TList);
+    procedure SetForceFieldEmitters(const val: TList);
+    procedure SetScene(const val: TgxScene);
+  public
+    procedure RegisterInertia(aInertia: TgxBaseInertia);
+    procedure DeRegisterInertia(aInertia: TgxBaseInertia);
+    procedure DeRegisterAllInertias;
+    procedure RegisterForceFieldEmitter(aForceField: TgxBaseForceFieldEmitter);
+    procedure DeRegisterForceFieldEmitter(aForceField: TgxBaseForceFieldEmitter);
+    procedure DeRegisterAllForceFieldEmitters;
+    procedure Notification(AComponent: TComponent;
+      Operation: TOperation); override;
+    constructor Create(aOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure CalculateNextState(DeltaTime: Real);
+    function CalculateKE(): Real;
+    function CalculatePE(): Real;
+    procedure SetDESolver(SolverType: TDESolverType);
+    function FindObjectByName(Name: String): TgxBaseSceneObject;
+    function FindForceFieldEmitterByName(Name: String): TgxBaseSceneObject;
+    property Inertias: TList read fInertias write SetInertias; // stored False;
+    property ForceFieldEmitters: TList read fForceFieldEmitters
+      write SetForceFieldEmitters; // stored False;
+  published
+    property Forces: TgxForces read GetForces write SetForces; // stored False;
+    property Solver: TDESolverType read fDESolverType write SetDESolver;
+    property Scene: TgxScene read fScene write SetScene;
+  end;
+
+  TgxForces = class(TXCollection)
+  protected
+    function GetForce(index: Integer): TgxForce;
+  public
+    constructor Create(aOwner: TPersistent); override;
+    // destructor Destroy;override;
+    class function ItemsClass: TXCollectionItemClass; override;
+    property Force[index: Integer]: TgxForce read GetForce; default;
+    function CanAdd(aClass: TXCollectionItemClass): Boolean; override;
+  end;
+
+implementation // ------------------------------------------------------------
+
+procedure TgxPhysManager.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  (* if Operation=opRemove then
+    begin
+    if AComponent=FScene then FScene:=nil;
+    end;
+  *)
+end;
+
+procedure TgxPhysManager.DefineProperties(Filer: TFiler);
+begin
+  inherited DefineProperties(Filer);
+  Filer.DefineBinaryProperty('ForcesData', ReadForces, WriteForces,
+    (Assigned(fForces) and (fForces.Count > 0)));
+end;
+
+procedure TgxPhysManager.Loaded;
+begin
+  inherited Loaded;
+  if Assigned(fForces) then
+    fForces.Loaded;
+end;
+
+function TgxPhysManager.FindObjectByName(Name: String): TgxBaseSceneObject;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to fInertias.Count - 1 do
+  begin
+    if (TgxBaseInertia(fInertias.Items[i]).OwnerBaseSceneObject.GetNamePath =
+      Name) then
+    begin
+      Result := TgxBaseInertia(fInertias.Items[i]).OwnerBaseSceneObject;
+    end
+    else if Owner.FindComponent(Name) <> nil then
+    begin
+      Result := TgxBaseSceneObject(Owner.FindComponent(Name));
+    end;
+  end;
+end;
+
+function TgxPhysManager.FindForceFieldEmitterByName(Name: String)
+  : TgxBaseSceneObject;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to fForceFieldEmitters.Count - 1 do
+  begin
+    if (TgxBaseForceFieldEmitter(fForceFieldEmitters.Items[i])
+      .OwnerBaseSceneObject.GetNamePath = Name) then
+    begin
+      Result := TgxBaseForceFieldEmitter(fForceFieldEmitters.Items[i])
+        .OwnerBaseSceneObject;
+    end;
+  end;
+end;
+
+procedure TgxPhysManager.WriteForces(stream: TStream);
+var
+  writer: TWriter;
+begin
+  // Writing forces
+  writer := TWriter.Create(stream, 16384);
+  try
+    Forces.WriteToFiler(writer);
+  finally
+    writer.Free;
+  end;
+end;
+
+procedure TgxPhysManager.ReadForces(stream: TStream);
+var
+  reader: TReader;
+begin
+  reader := TReader.Create(stream, 16384);
+  try
+    Forces.ReadFromFiler(reader);
+  finally
+    reader.Free;
+  end;
+end;
+
+procedure TgxPhysManager.SetForces(const val: TgxForces);
+begin
+  Forces.Assign(val);
+end;
+
+procedure TgxPhysManager.SetInertias(const val: TList);
+begin
+  fInertias.Assign(val);
+end;
+
+procedure TgxPhysManager.SetForceFieldEmitters(const val: TList);
+begin
+  fForceFieldEmitters.Assign(val);
+end;
+
+procedure TgxPhysManager.SetScene(const val: TgxScene);
+begin
+  // fScene:=val;
+  if fScene <> val then
+  begin
+    if Assigned(fScene) then
+      fScene.RemoveFreeNotification(Self);
+    fScene := val;
+    if Assigned(fScene) then
+      fScene.FreeNotification(Self);
+  end;
+end;
+
+function TgxPhysManager.GetForces: TgxForces;
+begin
+  if not Assigned(fForces) then
+    fForces := TgxForces.Create(Self);
+  Result := fForces;
+end;
+
+// Not accurate yet, because Forces should be re-calculated for each KVector.
+// Since forces will depend on distances between objects, then this will require
+// a central physics manager, that calculates KVector for all objects, then calculate forces
+// between objects for this new estimated state.
+//
+
+function TDESolver.StateToArray(): TStateArray;
+var
+  i { ,j } : Integer;
+  currentpos: Integer;
+  // state:TStateArray;
+begin
+  currentpos := 0;
+  for i := 0 to Owner.fInertias.Count - 1 do
+  begin
+    TgxBaseInertia(Owner.fInertias.Items[i]).StateToArray(StateArray,
+      currentpos);
+    currentpos := currentpos + TgxBaseInertia(Owner.fInertias.Items[i])
+      .StateSize;
+  end;
+  Result := StateArray;
+end;
+
+procedure TDESolver.ArrayToState(StateArray: TStateArray);
+var
+  i: Integer;
+  currentpos: Integer;
+begin
+  currentpos := 0;
+  for i := 0 to Owner.fInertias.Count - 1 do
+  begin
+    TgxBaseInertia(Owner.fInertias.Items[i]).ArrayToState(StateArray,
+      currentpos);
+    currentpos := currentpos + TgxBaseInertia(Owner.fInertias.Items[i])
+      .StateSize;
+  end;
+end;
+
+constructor TDESolver.Create(aOwner: TgxPhysManager);
+begin
+  Self.Owner := aOwner;
+end;
+
+destructor TDESolver.Destroy;
+begin
+  //
+end;
+
+function TDESolverExplicit.CalcStateDot(): TStateArray;
+var
+  i { ,j } : Integer;
+  currentpos: Integer;
+  state: TStateArray;
+begin
+  //
+  SetLength(state, StateSize);
+  for i := 0 to StateSize - 1 do
+    state[i] := StateArray[i];
+  // state:=StateArray;
+  currentpos := 0;
+  for i := 0 to Owner.fInertias.Count - 1 do
+  begin
+    TgxBaseInertia(Owner.fInertias.Items[i]).CalcStateDot(state, currentpos);
+    currentpos := currentpos + TgxBaseInertia(Owner.fInertias.Items[i])
+      .StateSize;
+  end;
+  Result := state;
+end;
+
+procedure TDESolverRungeKutta4.Solve(DeltaTime: Real);
+var
+  // X,X0:TStateArray;
+  Kvectors: array [0 .. 3] of TStateArray;
+  n: Integer;
+  StateArray0: TStateArray;
+  tempStateArray: TStateArray;
+  // tempState:TgxBInertia;
+begin
+  // tempState:=TgxBInertia.Create(nil);
+  // tempState.Assign(Self);
+  tempStateArray := StateToArray();
+  StateArray0 := tempStateArray;
+
+  for n := 0 to 3 do
+    SetLength(Kvectors[n], Length(StateArray0));
+
+  Kvectors[0] := CalcStateDot();
+  for n := 0 to StateSize - 1 do
+    tempStateArray[n] := tempStateArray[n] + DeltaTime / 2 * Kvectors[0][n];
+  ArrayToState(tempStateArray);
+
+  Kvectors[1] := CalcStateDot();
+  for n := 0 to StateSize - 1 do
+    tempStateArray[n] := tempStateArray[n] + DeltaTime / 2 * Kvectors[1][n];
+  ArrayToState(tempStateArray);
+
+  Kvectors[2] := CalcStateDot();
+  for n := 0 to StateSize - 1 do
+    tempStateArray[n] := tempStateArray[n] + DeltaTime / 2 * Kvectors[2][n];
+  ArrayToState(tempStateArray);
+
+  Kvectors[3] := CalcStateDot();
+
+  for n := 0 to StateSize - 1 do
+  begin
+    tempStateArray[n] := StateArray0[n] + DeltaTime / 6 *
+      (Kvectors[0][n] + 2 * Kvectors[1][n] + 2 * Kvectors[2][n] +
+      Kvectors[3][n]);
+  end;
+
+  ArrayToState(tempStateArray);
+
+  // NormalizeQuaternion(AngularOrientation);
+  // tempState.Free();
+end;
+
+procedure TDESolverEuler.Solve(DeltaTime: Real);
+var
+  i, j: Integer;
+  tempState, tempStateDot: TStateArray;
+  // force1:TAffineVector;
+  Inertia1: TgxBaseInertia;
+  tempForce: TAffineVector;
+  // UnDampedMomentum,DampedMomentum:Real;
+begin
+{$IFDEF DEBUG}
+  Write('Euler integration');
+{$ENDIF}
+  for i := 0 to Owner.fInertias.Count - 1 do
+  begin
+    Inertia1 := TgxBaseInertia(Owner.fInertias.Items[i]);
+    // TGLRigidBodyInertia(FObjects.Items[i]).SetTorque(0,0,0);
+    for j := 0 to Owner.fForceFieldEmitters.Count - 1 do
+    begin
+      Inertia1.CalculateForceFieldForce
+        (TgxBaseForceFieldEmitter(Owner.fForceFieldEmitters.Items[j]));
+      // Inertia1.ApplyForce(TgxForceFieldEmitter(FForceFieldEmitters.Items[j]).CalculateForceField(Inertia1.OwnerBaseSceneObject));
+    end;
+  end;
+
+  for i := 0 to Owner.Forces.Count - 1 do
+  begin
+    { force1:= } Owner.Forces.Force[i].CalculateForce();
+  end;
+
+  tempState := StateToArray();
+  tempStateDot := CalcStateDot();
+  for i := 0 to StateSize - 1 do
+    tempState[i] := tempState[i] + DeltaTime * tempStateDot[i];
+
+  ArrayToState(tempState);
+
+  for i := 0 to Owner.fInertias.Count - 1 do
+  begin
+    // TGLInertia(FObjects.Items[i]).SetForce(0,0,0);
+    Inertia1 := TgxBaseInertia(Owner.fInertias.Items[i]);
+    if Inertia1.DampingEnabled = true then
+    begin
+      // UnDampedMomentum:=VectorLength(Inertia1.TranslationSpeed.AsAffineVector);
+      // DampedMomentum:= Inertia1.TranslationDamping.Calculate(UnDampedMomentum,deltaTime);
+      // if  UnDampedMomentum<>0 then
+      begin
+        // ScaleVector(Inertia1.TranslationSpeed.AsAffineVector,DampedMomentum/UnDampedMomentum);
+        // ScaleVector(Inertia1.LinearMomentum,DampedMomentum/UnDampedMomentum);
+      end;
+      // Inertia1.TranslationDamping.Calculate(VectorLength(Inertia1.LinearMomentum),deltaTime);
+    end;
+    Inertia1.CalcAuxiliary();
+    Inertia1.RemoveForces();
+  end;
+  // NormalizeQuaternion(AngularOrientation);
+end;
+
+constructor TgxPhysManager.Create(aOwner: TComponent);
+begin
+  inherited Create(aOwner);
+  fInertias := TList.Create();
+  fForceFieldEmitters := TList.Create();
+  fForces := TgxForces.Create(Self);
+  SetDESolver(ssEuler);
+  ///RegisterManager(Self);
+end;
+
+destructor TgxPhysManager.Destroy;
+begin
+  // fScene:=nil;
+  DeRegisterAllInertias();
+  DeRegisterAllForceFieldEmitters();
+///  DeRegisterManager(Self);
+  fInertias.Free();
+  fForceFieldEmitters.Free();
+  fForces.Free();
+  inherited Destroy;
+end;
+
+procedure TgxPhysManager.Assign(Source: TPersistent);
+begin
+  inherited Assign(Source);
+end;
+
+procedure TgxPhysManager.SetDESolver(SolverType: TDESolverType);
+var
+  tempSolver: TDESolver;
+begin
+  if Assigned(DESolver) then
+  begin
+    if (fDESolverType <> SolverType) then
+      case SolverType of
+        ssRungeKutta4:
+          begin
+            // DESolver:=RungeKutta4;
+          end;
+        ssEuler:
+          begin
+            // DESolver:=Euler;
+          end;
+      end;
+  end
+  else
+  begin
+    // if (fDESolverType<>SolverType) then
+    case SolverType of
+      ssRungeKutta4:
+        begin
+          DESolver := TDESolverRungeKutta4.Create(Self);
+        end;
+      ssEuler:
+        begin
+          DESolver := TDESolverEuler.Create(Self);
+        end;
+    end;
+    fDESolverType := SolverType;
+  end;
+end;
+
+procedure TgxPhysManager.RegisterInertia(aInertia: TgxBaseInertia);
+begin
+  if Assigned(aInertia) then
+    if fInertias.IndexOf(aInertia) < 0 then
+    begin
+      fInertias.Add(aInertia);
+      aInertia.FManager := Self;
+      DESolver.StateSize := DESolver.StateSize + aInertia.StateSize;
+      SetLength(DESolver.StateArray, DESolver.StateSize);
+    end;
+end;
+
+procedure TgxPhysManager.DeRegisterInertia(aInertia: TgxBaseInertia);
+begin
+  if Assigned(aInertia) then
+  begin
+    aInertia.FManager := nil;
+    fInertias.Remove(aInertia);
+    DESolver.StateSize := DESolver.StateSize - aInertia.StateSize;
+    SetLength(DESolver.StateArray, DESolver.StateSize);
+  end;
+
+end;
+
+procedure TgxPhysManager.DeRegisterAllInertias;
+var
+  i: Integer;
+begin
+  // Fast deregistration
+  for i := 0 to fInertias.Count - 1 do
+    TgxBaseInertia(fInertias[i]).FManager := nil;
+  fInertias.Clear;
+  DESolver.StateSize := 0;
+  // SetLEngth(StateArray,0);
+end;
+
+procedure TgxPhysManager.RegisterForceFieldEmitter
+  (aForceField: TgxBaseForceFieldEmitter);
+begin
+  if Assigned(aForceField) then
+    if fForceFieldEmitters.IndexOf(aForceField) < 0 then
+    begin
+      fForceFieldEmitters.Add(aForceField);
+      aForceField.FManager := Self;
+    end;
+end;
+
+procedure TgxPhysManager.DeRegisterForceFieldEmitter
+  (aForceField: TgxBaseForceFieldEmitter);
+begin
+  if Assigned(aForceField) then
+  begin
+    aForceField.FManager := nil;
+    fForceFieldEmitters.Remove(aForceField);
+  end;
+end;
+
+procedure TgxPhysManager.DeRegisterAllForceFieldEmitters;
+var
+  i: Integer;
+begin
+  // Fast deregistration
+  for i := 0 to fForceFieldEmitters.Count - 1 do
+    TgxBaseForceFieldEmitter(fForceFieldEmitters[i]).FManager := nil;
+  fForceFieldEmitters.Clear;
+end;
+
+function TgxPhysManager.CalculateKE(): Real;
+var
+  Total: Real;
+  i: Integer;
+begin
+  Total := 0;
+  for i := 0 to fInertias.Count - 1 do
+  begin
+    // calculate fInertias[i] KE
+    Total := Total + TgxBaseInertia(fInertias.Items[i]).CalculateKE();
+  end;
+  Result := Total;
+end;
+
+function TgxPhysManager.CalculatePE(): Real;
+var
+  Total: Real;
+  i: Integer;
+begin
+  Total := 0;
+  for i := 0 to fInertias.Count - 1 do
+  begin
+    // calculate fobject[i] PE
+    Total := Total + TgxBaseInertia(fInertias.Items[i]).CalculatePE();
+  end;
+  Result := Total;
+end;
+
+procedure TgxPhysManager.CalculateNextState(DeltaTime: Real);
+begin
+  if Assigned(DESolver) then
+    DESolver.Solve(DeltaTime);
+end;
+
+constructor TgxForces.Create(aOwner: TPersistent);
+begin
+  // Assert(aOwner is TgxBaseSceneObject);
+  inherited Create(aOwner);
+end;
+
+{ destructor TgxForces.Destroy;
+  begin
+  inherited Destroy;
+  end;
+}
+
+class function TgxForces.ItemsClass: TXCollectionItemClass;
+begin
+  Result := TgxForce;
+end;
+
+function TgxForces.GetForce(index: Integer): TgxForce;
+begin
+  Result := TgxForce(Items[index]);
+end;
+
+function TgxForces.CanAdd(aClass: TXCollectionItemClass): Boolean;
+begin
+  Result := { (not aClass.InheritsFrom(TGLEffect)) and }
+    (inherited CanAdd(aClass));
+end;
+
+// -----------------------------------------------------------------------------
+
+procedure TgxBaseInertia.SetManager(const val: TgxPhysManager);
+begin
+  if val <> FManager then
+  begin
+    if Assigned(FManager) then
+      FManager.DeRegisterInertia(Self);
+    if Assigned(val) then
+      val.RegisterInertia(Self);
+    // Write(val.GetNamePath);
+  end;
+end;
+
+procedure TgxBaseInertia.Loaded;
+var
+  mng: TComponent;
+begin
+  inherited;
+  if FManagerName <> '' then
+  begin
+///?    mng := FindManager(TgxPhysManager, FManagerName);
+    if Assigned(mng) then
+      Manager := TgxPhysManager(mng);
+    FManagerName := '';
+  end;
+end;
+
+procedure TgxBaseInertia.WriteToFiler(writer: TWriter);
+begin
+  inherited;
+  with writer do
+  begin
+    WriteInteger(0); // Archive Version 0
+    WriteBoolean(FDampingEnabled);
+    if Assigned(FManager) then
+      WriteString(FManager.GetNamePath)
+    else
+      WriteString('');
+  end;
+end;
+
+procedure TgxBaseInertia.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    ReadInteger; // ignore archiveVersion
+    FDampingEnabled := ReadBoolean;
+    FManagerName := ReadString;
+    Manager := nil;
+  end;
+  // Loaded;     //DB100
+end;
+
+constructor TgxBaseInertia.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+  FDampingEnabled := true;
+end;
+
+destructor TgxBaseInertia.Destroy;
+begin
+  SetManager(nil);
+  inherited Destroy;
+end;
+
+procedure TgxBaseInertia.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    StateSize := TgxBaseInertia(Source).StateSize;
+    FDampingEnabled := TgxBaseInertia(Source).DampingEnabled;
+    Manager := TgxBaseInertia(Source).Manager;
+  end;
+  inherited Assign(Source);
+end;
+
+procedure TgxBaseInertia.StateToArray(var StateArray: TStateArray;
+  StatePos: Integer);
+begin
+end;
+
+procedure TgxBaseInertia.ArrayToState( { var } StateArray: TStateArray;
+  StatePos: Integer);
+begin
+end;
+
+procedure TgxBaseInertia.CalcStateDot(var StateArray: TStateArray;
+  StatePos: Integer);
+begin
+end;
+
+procedure TgxBaseInertia.RemoveForces();
+begin
+end;
+
+procedure TgxBaseInertia.CalculateForceFieldForce(ForceFieldEmitter
+  : TgxBaseForceFieldEmitter);
+begin
+end;
+
+function TgxBaseInertia.CalculateKE(): Real;
+begin
+  Result := 0;
+end;
+
+function TgxBaseInertia.CalculatePE(): Real;
+begin
+  Result := 0;
+end;
+
+procedure TgxBaseInertia.CalcAuxiliary();
+begin
+end;
+
+procedure TgxBaseInertia.SetUpStartingState();
+begin
+end;
+
+// -----------------------------------------------------------------------------
+
+procedure TgxBaseForceFieldEmitter.SetManager(const val: TgxPhysManager);
+begin
+  if val <> FManager then
+  begin
+    if Assigned(FManager) then
+      FManager.DeRegisterForceFieldEmitter(Self);
+    if Assigned(val) then
+      val.RegisterForceFieldEmitter(Self);
+  end;
+end;
+
+procedure TgxBaseForceFieldEmitter.Loaded;
+var
+  mng: TComponent;
+begin
+  inherited;
+  if FManagerName <> '' then
+  begin
+///?    mng := FindManager(TgxPhysManager, FManagerName);
+    if Assigned(mng) then
+      Manager := TgxPhysManager(mng);
+    FManagerName := '';
+  end;
+end;
+
+procedure TgxBaseForceFieldEmitter.WriteToFiler(writer: TWriter);
+begin
+  inherited; // Dan Bartlett
+  with writer do
+  begin
+    WriteInteger(0); // Archive Version 0
+    if Assigned(FManager) then
+      WriteString(FManager.GetNamePath)
+    else
+      WriteString('');
+  end;
+end;
+
+procedure TgxBaseForceFieldEmitter.ReadFromFiler(reader: TReader);
+begin
+  inherited;
+  with reader do
+  begin
+    ReadInteger; // ignore archiveVersion
+    FManagerName := ReadString;
+    Manager := nil;
+  end;
+  // Loaded;  //DB100
+end;
+
+constructor TgxBaseForceFieldEmitter.Create(aOwner: TXCollection);
+begin
+  inherited Create(aOwner);
+end;
+
+destructor TgxBaseForceFieldEmitter.Destroy;
+begin
+  SetManager(nil);
+  inherited Destroy;
+end;
+
+procedure TgxBaseForceFieldEmitter.Assign(Source: TPersistent);
+begin
+  if Source.ClassType = Self.ClassType then
+  begin
+    Manager := TgxBaseForceFieldEmitter(Source).Manager;
+  end;
+  inherited Assign(Source);
+end;
+
+// CalculateForceField
+function TgxBaseForceFieldEmitter.CalculateForceField(Body: TgxBaseSceneObject)
+  : TAffineVector;
+begin
+  Result := nullVector;
+end;
+
+initialization // ------------------------------------------------------------
+
+// RegisterClasses([TgxForces]);
+// RegisterClasses([TgxPhysManager, TgxBaseInertia, TgxBaseForceFieldEmitter]);
+// RegisterXCollectionItemClass(TgxBaseInertia);
+// RegisterXCollectionItemClass(TgxBaseForceFieldEmitter);
+// RegisterXCollectionItemClass(TGLPhysicsForce);
+
+// ------------------------------------------------------------------
+
+end.

+ 1 - 1
Sourcex/GXS.Sounds.BASS.pas

@@ -21,7 +21,7 @@ uses
   FMX.Forms,
 
   GLScene.VectorTypes,
-  GXS.Sound,
+  GXS.SoundManager,
   GXS.Scene,
   GLScene.VectorGeometry,
   BASS.Import;

+ 1 - 1
Sourcex/GXS.Sounds.OpenAL.pas

@@ -32,7 +32,7 @@ uses
   GXS.Scene,
   GLScene.VectorGeometry,
   GLScene.Coordinates,
-  GXS.Sound,
+  GXS.SoundManager,
   GXS.SoundFileObjects;
 
 type

+ 1 - 1
Sourcex/GXS.Sounds.WaveOut.pas

@@ -13,7 +13,7 @@ uses
 
   System.Classes,
   System.SysUtils,
-  GXS.Sound,
+  GXS.SoundManager,
   GXS.SoundFileObjects;
 
 type