LZScene

Форк
0
/
GLVerletTypes.pas 
2738 строк · 80.5 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
   Base Verlet modelling/simulation classes.
6
   This unit is generic, GLScene-specific sub-classes are in GLVerletClasses.
7

8
   Note that currently, the SatisfyConstraintForEdge methods push the nodes in
9
   the edge uniformly - it should push the closer node more for correct physics.
10
   It's a matter of leverage. 
11

12
	 History :  
13
       18/11/14 - PW - Renamed VerletClasses.pas to GLVerletTypes
14
       10/11/12 - PW - Added CPP compatibility: changed vector arrays to records
15
       25/11/09 - DanB - Fix for TGLVerletGlobalConstraint.TranslateKickbackTorque
16
       31/03/07 - DaStr - Added $I GLScene.inc
17
       14/04/04 - MF - Fixed force for springs, was referring to deltaP...
18
       13/04/04 - MF - Minor drag changes
19
       13/04/04 - EG - Added TVCHeightField and TVCSlider, fixed TVCFloor
20
                          and TVFSpring, altered the way world Drag operates 
21
       06/03/04 - MF - Small updates to accomodate hair
22
       11/07/03 - EG - Optimized TVCCube collider
23
       11/07/03 - MF - A bit of a documentation effort
24
       10/07/03 - MF - Verlets now use spatial partitioning objects to speed
25
                          up space queries
26
       10/07/03 - MF - Renaming TVerletAssembly to TGLVerletWorld
27
       24/06/03 - MF - Added force kickbacks for integration with external
28
                          physics. Needs to be split into force+torque and add
29
                          friction to the kickback
30
       19/06/03 - MF - Added TGLVerletGlobalConstraint.SatisfyConstraintForEdge
31
                          and implemented for TVCSphere and TVCCapsule 
32
       19/06/03 - MF - Added friction to TVCCylinder
33
       19/06/03 - MF - Added surface normals to all colliders - surface
34
                          normal is identical to Normalize(Movement)!
35
       18/06/03 - MF - Moved FrictionRatio to TGLVerletGlobalFrictionConstraint
36
       18/06/03 - EG - Updated TVCCapsule
37
       18/06/03 - MF - Updated TVCFloor to use a normal and a point
38
       18/06/03 - MF - Added TVCCapsule
39
       17/06/03 - MF - Added TVFAirResistance
40
       17/06/03 - MF - Added TVCCube collider
41
       16/06/03 - MF - Fixed TVFSpring.SetRestlengthToCurrent
42
       24/07/02 - EG - Added TVCCylinder
43
       18/07/02 - EG - Improved forces & constraints
44
       23/06/02 - EG - Stricter encapsulation, fixed some leaks,
45
                          Various optimizations (+25%)
46
       21/06/02 - EG - Creation (original code by Mattias Fagerlund)
47
    
48
}
49
unit GLVerletTypes;
50

51
interface
52

53
{$I GLScene.inc}
54

55
uses
56
  Classes, SysUtils, Types,
57
 //GLScene
58
  GLCrossPlatform, GLVectorGeometry, GLVectorLists, GLSpacePartition,
59
  GLGeometryBB, GLVectorTypes;
60

61
const
62
   G_DRAG = 0.0001;
63
   cDEFAULT_CONSTRAINT_FRICTION = 0.6;
64

65
type
66
   TGLVerletEdgeList = class;
67
   TGLVerletWorld = class;
68

69
   TVerletProgressTimes = packed record
70
      deltaTime, newTime : Double;
71
      sqrDeltaTime, invSqrDeltaTime : Single;
72
   end;
73

74
   // TVerletNode
75
   //
76
   { Basic verlet node }
77
   TVerletNode = class(TSpacePartitionLeaf)
78
      private
79
			 
80
         FForce : TAffineVector;
81
         FOwner : TGLVerletWorld;
82
         FWeight, FInvWeight : Single;
83
         FRadius : Single;
84
         FNailedDown : Boolean;
85
         FFriction : Single;
86
         FChangedOnStep : Integer;
87
         function GetSpeed: TAffineVector;
88

89
		protected
90
			 
91
         FLocation, FOldLocation : TAffineVector;
92

93
         procedure SetLocation(const Value: TAffineVector);virtual;
94

95
         procedure SetWeight(const value : Single);
96

97
         procedure AfterProgress; virtual;
98

99
      public
100
			 
101
         constructor CreateOwned(const aOwner : TGLVerletWorld); virtual;
102
         destructor Destroy; override;
103

104
         { Applies friction }
105
         procedure ApplyFriction(const friction, penetrationDepth : Single;
106
                                 const surfaceNormal : TAffineVector);
107
         { Simple and less accurate method for friction }
108
         procedure OldApplyFriction(const friction, penetrationDepth : Single);
109

110
         { Perform Verlet integration }
111
         procedure Verlet(const vpt : TVerletProgressTimes); virtual;
112

113
         { Initlializes the node. For the base class, it just makes sure that
114
         FOldPosition = FPosition, so that speed is zero }
115
         procedure Initialize; dynamic;
116

117
         { Calculates the distance to another node }
118
         function DistanceToNode(const node : TVerletNode) : Single;
119

120
         { Calculates the movement of the node }
121
         function GetMovement : TAffineVector;
122

123
         { The TVerletNode inherits from TSpacePartitionLeaf, and it needs to
124
         know how to publish itself. The owner ( a TGLVerletWorld ) has a spatial
125
         partitioning object}
126
         procedure UpdateCachedAABBAndBSphere; override;
127

128
         { The VerletWorld that owns this verlet }
129
         property Owner : TGLVerletWorld read FOwner;
130

131
         { The location of the verlet }
132
         property Location : TAffineVector read FLocation write SetLocation;
133

134
         { The old location of the verlet. This is used for verlet integration }
135
         property OldLocation : TAffineVector read FOldLocation write FOldLocation;
136

137
         { The radius of the verlet node - this has been more or less deprecated }
138
         property Radius : Single read FRadius write FRadius;
139

140
         { A sum of all forces that has been applied to this verlet node during a step }
141
         property Force : TAffineVector read FForce write FForce;
142

143
         { If the node is nailed down, it can't be moved by either force,
144
         constraint or verlet integration - but you can still move it by hand }
145
         property NailedDown : Boolean read FNailedDown write FNailedDown;
146

147
         { The weight of a node determines how much it's affected by a force }
148
         property Weight : Single read FWeight write SetWeight;
149

150
         { InvWeight is 1/Weight, and is kept up to date automatically }
151
         property InvWeight : Single read FInvWeight;
152

153
         { Returns the speed of the verlet node. Speed = Movement / deltatime }
154
         property Speed : TAffineVector read GetSpeed;
155

156
         { Each node has a friction that effects how it reacts during contacts.}
157
         property Friction : Single read FFriction write FFriction;
158

159
         { What phyisics step was this node last changed? Used to keep track
160
         of when the spatial partitioning needs to be updated }
161
         property ChangedOnStep : Integer read FChangedOnStep;
162
   end;
163

164
   TVerletNodeClass = class of TVerletNode;
165

166
   // TVerletNodeList
167
   //
168
   TVerletNodeList = class(TList)
169
      private
170
			 
171
         function GetItems(i : Integer): TVerletNode;
172
         procedure SetItems(i : Integer; const value : TVerletNode);
173

174
      public
175
			 
176
         property Items[i : Integer] : TVerletNode read GetItems write SetItems; default;
177
   end;
178

179
   // TVerletConstraint
180
   //
181
   TVerletConstraint = class (TObject)
182
      private
183
			 
184
         FOwner : TGLVerletWorld;
185
         FEnabled : Boolean;
186
         FTag : Integer;
187

188
      public
189
			 
190
         constructor Create(const aOwner : TGLVerletWorld); virtual;
191
         destructor Destroy; override;
192

193
         { Updates the position of one or several nodes to make sure that they
194
            don't violate the constraint }
195
         procedure SatisfyConstraint(const iteration, maxIterations : Integer); virtual; abstract;
196
         { Notifies removal of a node }
197
         procedure RemoveNode(const aNode : TVerletNode); virtual; abstract;
198
         { Method that's fired before the physics iterations are performed}
199
         procedure BeforeIterations; virtual;
200

201
         { Onwer of the constraint }
202
         property Owner : TGLVerletWorld read FOwner;
203
         { Determines if the constraint should be enforced or not }
204
         property Enabled : Boolean read FEnabled write FEnabled;
205
         { Tag field reserved for the user. }
206
         property Tag : Integer read FTag write FTag;
207
   end;
208

209
   // TGLVerletDualConstraint
210
   //
211
   TGLVerletDualConstraint = class (TVerletConstraint)
212
      private
213
			 
214
         FNodeA, FNodeB : TVerletNode;
215

216
      public
217
			 
218
         procedure RemoveNode(const aNode : TVerletNode); override;
219

220
         { Reference to NodeA. }
221
         property NodeA : TVerletNode read FNodeA write FNodeA;
222
         { Reference to NodeB. }
223
         property NodeB : TVerletNode read FNodeB write FNodeB;
224
   end;
225

226
   // TVerletGroupConstraint
227
   //
228
   TVerletGroupConstraint = class (TVerletConstraint)
229
      private
230
			 
231
         FNodes : TVerletNodeList;
232

233
      public
234
			 
235
         constructor Create(const aOwner : TGLVerletWorld); override;
236
         destructor Destroy; override;
237

238
         procedure RemoveNode(const aNode : TVerletNode); override;
239

240
         { The list of nodes that this constraint will effect}
241
         property Nodes : TVerletNodeList read FNodes;
242
   end;
243

244
   // TGLVerletEdge
245
   // Verlet edges simulate rigid collission edges
246
   TGLVerletEdge = class(TSpacePartitionLeaf)
247
      private
248
			 
249
         FNodeA: TVerletNode;
250
         FNodeB: TVerletNode;
251

252
      public
253
			 
254
         { The TGLVerletEdge inherits from TSpacePartitionLeaf, and it needs to
255
         know how to publish itself. The owner ( a TGLVerletWorld ) has a spatial
256
         partitioning object}
257
         procedure UpdateCachedAABBAndBSphere; override;
258

259
         constructor CreateEdgeOwned(const aNodeA, aNodeB : TVerletNode);
260

261
         { One of the nodes in the edge }
262
         property NodeA : TVerletNode read FNodeA write FNodeA;
263

264
         { One of the nodes in the edge }
265
         property NodeB : TVerletNode read FNodeB write FNodeB;
266
   end;
267

268
   TGLVerletEdgeList = class(TList)
269
      private
270
			 
271
         function GetItems(i: Integer): TGLVerletEdge;
272
         procedure SetItems(i: Integer; const Value: TGLVerletEdge);
273

274
      public
275
			 
276
         property Items[i : Integer] : TGLVerletEdge read GetItems write SetItems; default;
277
   end;
278

279
   // TGLVerletGlobalConstraint
280
   //
281
   TGLVerletGlobalConstraint = class (TVerletConstraint)
282
      private
283
			 
284
         FKickbackForce: TAffineVector;
285
         FKickbackTorque : TAffineVector;
286
         FLocation: TAffineVector;
287
         procedure SetLocation(const Value: TAffineVector); virtual;
288

289
      public
290
			 
291
         constructor Create(const aOwner : TGLVerletWorld); override;
292
         destructor Destroy; override;
293

294
         procedure RemoveNode(const aNode : TVerletNode); override;
295
         procedure BeforeIterations; override;
296

297
         procedure SatisfyConstraint(const iteration, maxIterations : Integer); override;
298
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
299
                        const iteration, maxIterations : Integer); virtual; abstract;
300
         procedure SatisfyConstraintForEdge(const aEdge : TGLVerletEdge;
301
                        const iteration, maxIterations : Integer); virtual;
302

303
         property Location : TAffineVector read FLocation write SetLocation;
304

305
         { The force that this collider has experienced while correcting the
306
         verlet possitions. This force can be applied to ODE bodies, for
307
         instance }
308
         property KickbackForce : TAffineVector read FKickbackForce write FKickbackForce;
309
         { The torque that this collider has experienced while correcting the
310
         verlet possitions, in reference to the center of the collider. The
311
         torque  force can be applied to ODE bodies, but it must first be
312
         translated. A torque can be trasnalted by 
313
         
314
         EM(b) = EM(a) + EF x VectorSubtract(b, a). 
315
         
316
         Simply adding the torque to the body will NOT work correctly. See
317
         TranslateKickbackTorque}
318
         property KickbackTorque : TAffineVector read FKickbackTorque write FKickbackTorque;
319

320
         procedure AddKickbackForceAt(const Pos : TAffineVector; const Force : TAffineVector);
321

322
         function TranslateKickbackTorque(const TorqueCenter : TAffineVector) : TAffineVector;
323
   end;
324

325
   // TGLVerletGlobalFrictionConstraint
326
   //
327
   TGLVerletGlobalFrictionConstraint = class (TGLVerletGlobalConstraint)
328
      private
329
			 
330
         FFrictionRatio: Single;
331

332
      public
333
			 
334
         constructor Create(const aOwner : TGLVerletWorld); override;
335
         
336
         property FrictionRatio : Single read FFrictionRatio write FFrictionRatio;
337
   end;
338

339
   TGLVerletGlobalFrictionConstraintSP = class(TGLVerletGlobalFrictionConstraint)
340
      public
341
         procedure SatisfyConstraint(const iteration, maxIterations : Integer); override;
342
         procedure PerformSpaceQuery; virtual; abstract;
343
   end;
344

345
   TGLVerletGlobalFrictionConstraintSphere = class(TGLVerletGlobalFrictionConstraintSP)
346
      private
347
         FCachedBSphere: TBSphere;
348

349
         procedure SetLocation(const Value: TAffineVector); override;
350
      public
351
         procedure UpdateCachedBSphere;
352
         procedure PerformSpaceQuery; override;
353
         function GetBSphere : TBSphere; virtual; abstract;
354

355
         property CachedBSphere : TBSphere read FCachedBSphere;
356
   end;
357

358
   TGLVerletGlobalFrictionConstraintBox = class(TGLVerletGlobalFrictionConstraintSP)
359
      private
360
         FCachedAABB: TAABB;
361

362
         procedure SetLocation(const Value: TAffineVector); override;
363
      public
364
         procedure UpdateCachedAABB;
365

366
         procedure PerformSpaceQuery; override;
367
         function GetAABB : TAABB; virtual; abstract;
368

369
         property CachedAABB : TAABB read FCachedAABB;
370
   end;
371

372
   // TVerletConstraintList
373
   //
374
   TVerletConstraintList = class(TList)
375
      private
376
			 
377
         function GetItems(i : Integer): TVerletConstraint;
378
         procedure SetItems(i : Integer; const Value: TVerletConstraint);
379

380
      public
381
			 
382
         property Items[i : Integer] : TVerletConstraint read GetItems write SetItems; default;
383
   end;
384

385
   // TVerletForce
386
   //
387
   { Generic verlet force. }
388
   TVerletForce = class (TObject)
389
      private
390
			 
391
         FOwner : TGLVerletWorld;
392

393
      public
394
			 
395
         constructor Create(const aOwner : TGLVerletWorld); virtual;
396
         destructor Destroy; override;
397

398
         // Implementation should add force to force resultant for all relevant nodes
399
         procedure AddForce(const vpt : TVerletProgressTimes); virtual; abstract;
400

401
         // Notifies removal of a node
402
         procedure RemoveNode(const aNode : TVerletNode); virtual; abstract;
403

404
         property Owner : TGLVerletWorld read FOwner;
405
   end;
406

407
   // TGLVerletDualForce
408
   //
409
   { A verlet force that applies to two specified nodes. }
410
   TGLVerletDualForce = class (TVerletForce)
411
      private
412
			 
413
         FNodeA, FNodeB : TVerletNode;
414

415
      public
416
			 
417
         procedure RemoveNode(const aNode : TVerletNode); override;
418

419
         { Reference to NodeA. }
420
         property NodeA : TVerletNode read FNodeA write FNodeA;
421
         { Reference to NodeB. }
422
         property NodeB : TVerletNode read FNodeB write FNodeB;
423
   end;
424

425
   // TVerletGroupForce
426
   //
427
   { A verlet force that applies to a specified group of nodes. }
428
   TVerletGroupForce = class (TVerletForce)
429
      private
430
			 
431
         FNodes : TVerletNodeList;
432

433
      public
434
			 
435
         constructor Create(const aOwner : TGLVerletWorld); override;
436
         destructor Destroy; override;
437

438
         procedure RemoveNode(const aNode : TVerletNode); override;
439

440
         { Nodes of the force group, referred, NOT owned. }
441
         property Nodes : TVerletNodeList read FNodes;
442
   end;
443

444
   // TGLVerletGlobalForce
445
   //
446
   { A global force (applied to all verlet nodes). }
447
   TGLVerletGlobalForce = class (TVerletForce)
448
      private
449
			 
450

451
      public
452
			 
453
         procedure RemoveNode(const aNode : TVerletNode); override;
454

455
         procedure AddForce(const vpt : TVerletProgressTimes); override;
456
         procedure AddForceToNode(const aNode : TVerletNode); virtual; abstract;
457
   end;
458

459
   // TVerletForceList
460
   //
461
   TVerletForceList = class (TList)
462
      private
463
			 
464
         function GetItems(i : Integer): TVerletForce;
465
         procedure SetItems(i : Integer; const Value: TVerletForce);
466

467
      public
468
			 
469
         property Items[i : Integer] : TVerletForce read GetItems write SetItems; default;
470
   end;
471

472
   TVCStick = class;
473
   TVFSpring = class;
474
   TVCSlider = class;
475

476
   TUpdateSpacePartion = (uspEveryIteration, uspEveryFrame, uspNever);
477
   TCollisionConstraintTypes = (cctEdge, cctNode);
478
   TCollisionConstraintTypesSet = set of TCollisionConstraintTypes;
479
   
480
   // TGLVerletWorld
481
   //
482
   TGLVerletWorld = class (TObject)
483
      private
484
			 
485
         FIterations : Integer;
486
         FNodes : TVerletNodeList;
487
         FConstraints : TVerletConstraintList;
488
         FForces : TVerletForceList;
489
         FMaxDeltaTime, FSimTime : Single;
490
         FDrag : Single;
491
         FCurrentDeltaTime: Single;
492
         FInvCurrentDeltaTime : Single;
493
         FSolidEdges: TGLVerletEdgeList;
494
         FSpacePartition: TBaseSpacePartition;
495
         FCurrentStepCount: Integer;
496
         FUpdateSpacePartion: TUpdateSpacePartion;
497
         FCollisionConstraintTypes: TCollisionConstraintTypesSet;
498
         FConstraintsWithBeforeIterations: TVerletConstraintList;
499
         FVerletNodeClass: TVerletNodeClass;
500
         FInertia: Boolean;
501
         FInertaPauseSteps : Integer;
502

503
		protected
504
			 
505
         procedure AccumulateForces(const vpt : TVerletProgressTimes); virtual;
506
         procedure Verlet(const vpt : TVerletProgressTimes); virtual;
507
         procedure SatisfyConstraints(const vpt : TVerletProgressTimes); virtual;
508

509
         procedure DoUpdateSpacePartition;
510

511
      public
512
			 
513
         constructor Create; virtual;
514
         destructor Destroy; override;
515

516
         function  AddNode(const aNode : TVerletNode) : Integer;
517
         procedure RemoveNode(const aNode : TVerletNode);
518
         
519
         function  AddConstraint(const aConstraint : TVerletConstraint) : Integer;
520
         procedure RemoveConstraint(const aConstraint : TVerletConstraint);
521

522
         function  AddForce(const aForce : TVerletForce) : Integer;
523
         procedure RemoveForce(const aForce : TVerletForce);
524

525
         procedure AddSolidEdge(const aNodeA, aNodeB : TVerletNode);
526

527
         procedure PauseInertia(const IterationSteps : Integer);
528

529
         function CreateOwnedNode(const location : TAffineVector;
530
                                  const aRadius : Single = 0;
531
                                  const aWeight : Single = 1) : TVerletNode;
532
         function CreateStick(const aNodeA, aNodeB : TVerletNode;
533
                              const Slack : Single = 0) : TVCStick;
534
         function CreateSpring(const aNodeA, aNodeB : TVerletNode;
535
                               const aStrength, aDamping : Single; const aSlack : Single = 0) : TVFSpring;
536
         function CreateSlider(const aNodeA, aNodeB : TVerletNode;
537
                               const aSlideDirection : TAffineVector) : TVCSlider;
538

539
         procedure Initialize; dynamic;
540
         procedure CreateOctree(const OctreeMin, OctreeMax : TAffineVector;
541
          const LeafThreshold, MaxTreeDepth : Integer);
542

543
         function Progress(const deltaTime, newTime : Double) : Integer; virtual;
544

545
         function FirstNode : TVerletNode;
546
         function LastNode : TVerletNode;
547

548
         property Drag : Single read FDrag write FDrag;
549
         property Iterations : Integer read FIterations write FIterations;
550
         property Nodes : TVerletNodeList read FNodes;
551
         property Constraints : TVerletConstraintList read FConstraints;
552
         property ConstraintsWithBeforeIterations : TVerletConstraintList read FConstraintsWithBeforeIterations;
553

554
         property SimTime : Single read FSimTime write FSimTime;
555
         property MaxDeltaTime : Single read FMaxDeltaTime write FMaxDeltaTime;
556

557
         property CurrentDeltaTime : Single read FCurrentDeltaTime;
558
         property SolidEdges : TGLVerletEdgeList read FSolidEdges write FSolidEdges;
559
         property CurrentStepCount : Integer read FCurrentStepCount;
560
         property SpacePartition: TBaseSpacePartition read FSpacePartition;
561
         property UpdateSpacePartion : TUpdateSpacePartion read FUpdateSpacePartion write FUpdateSpacePartion;
562
         property CollisionConstraintTypes : TCollisionConstraintTypesSet read FCollisionConstraintTypes write FCollisionConstraintTypes;
563
         property VerletNodeClass : TVerletNodeClass read FVerletNodeClass write FVerletNodeClass;
564
         property Inertia : boolean read FInertia write FInertia;
565
   end;
566

567
   // TVFGravity
568
   //
569
   TVFGravity = class(TGLVerletGlobalForce)
570
      private
571
			 
572
         FGravity : TAffineVector;
573

574
      public
575
			 
576
         constructor Create(const aOwner : TGLVerletWorld); override;
577

578
         procedure AddForceToNode(const aNode : TVerletNode); override;
579

580
         property Gravity : TAffineVector read FGravity write FGravity;
581
   end;
582

583
   // TVFAirResistance
584
   //
585
   TVFAirResistance = class(TGLVerletGlobalForce)
586
      private
587
			 
588
         FDragCoeff: Single;
589
         FWindDirection: TAffineVector;
590
         FWindMagnitude: Single;
591
         FWindChaos: Single;
592
         procedure SetWindDirection(const Value: TAffineVector);
593

594
      public
595
			 
596
         constructor Create(const aOwner : TGLVerletWorld); override;
597
         procedure AddForceToNode(const aNode : TVerletNode); override;
598

599
         property DragCoeff : Single read FDragCoeff write FDragCoeff;
600
         property WindDirection : TAffineVector read FWindDirection write SetWindDirection;
601
         property WindMagnitude : Single read FWindMagnitude write FWindMagnitude;
602
         { Measures how chaotic the wind is, as a fraction of the wind magnitude }
603
         property WindChaos : Single read FWindChaos write FWindChaos;
604
   end;
605

606
   // TVFSpring
607
   //
608
   TVFSpring = class (TGLVerletDualForce)
609
      private
610
			 
611
         FRestLength : Single;
612
         FStrength : Single;
613
         FDamping : Single;
614
         FSlack : Single;
615
         FForceFactor : Single;
616

617
      protected
618
          
619
         procedure SetSlack(const value : Single);
620

621
      public
622
			 
623
         procedure AddForce(const vpt : TVerletProgressTimes); override;
624

625
         // Must be invoked after adjust node locations or strength 
626
         procedure SetRestLengthToCurrent;
627

628
         property Strength : Single read FStrength write FStrength;
629
         property Damping : Single read FDamping write FDamping;
630
         property Slack : Single read FSlack write SetSlack;
631
   end;
632

633
   // TVCFloor
634
   //
635
   { Floor collision constraint }
636
   TVCFloor = class (TGLVerletGlobalFrictionConstraintSP)
637
      private
638
			 
639
         FBounceRatio, FFloorLevel : Single;
640
         FNormal : TAffineVector;
641

642
      protected
643
          
644
         procedure SetNormal(const value : TAffineVector);
645

646
      public
647
			 
648
         constructor Create(const aOwner : TGLVerletWorld); override;
649

650
         procedure PerformSpaceQuery; override;
651
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
652
                        const iteration, maxIterations : Integer); override;
653

654
         property BounceRatio : Single read FBounceRatio write FBounceRatio;
655
         property FloorLevel : Single read FFloorLevel write FFloorLevel;
656
         property Normal : TAffineVector read FNormal write SetNormal;
657
   end;
658

659
   TVCHeightField = class;
660
   TVCHeightFieldOnNeedHeight = function (hfConstraint : TVCHeightField; node : TVerletNode) : Single of object;
661

662
   // TVCHeightField
663
   //
664
   { HeightField collision constraint (punctual!) }
665
   TVCHeightField = class (TVCFloor)
666
      private
667
			 
668
         FOnNeedHeight : TVCHeightFieldOnNeedHeight;
669

670
      public
671
			 
672
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
673
                        const iteration, maxIterations : Integer); override;
674

675
         property OnNeedHeight : TVCHeightFieldOnNeedHeight read FOnNeedHeight write FOnNeedHeight;
676
   end;
677

678
   // TVCStick
679
   //
680
   { Stick constraint.
681
      Imposes a fixed distance between two nodes. }
682
   TVCStick = class (TGLVerletDualConstraint)
683
      private
684
			 
685
         FSlack : Single;
686
         FRestLength : Single;
687

688
      public
689
			 
690
         procedure SatisfyConstraint(const iteration, maxIterations : Integer); override;
691
         procedure SetRestLengthToCurrent;
692

693
         property Slack : Single read FSlack write FSlack;
694
         property RestLength : Single read FRestLength write FRestLength;
695
   end;
696

697
   // TVCRigidBody
698
   //
699
   { Rigid body constraint.
700
      Regroups several nodes in a rigid body conformation, somewhat similar
701
      to a stick but for multiple nodes. 
702
      EXPERIMENTAL, DOES NOT WORK!
703
      }
704
   TVCRigidBody = class (TVerletGroupConstraint)
705
      private
706
			 
707
         FNodeParams : array of TAffineVector;
708
         FNodeCoords : array of TAffineVector;
709
         FNatMatrix, FInvNatMatrix : TAffineMatrix;
710

711
      protected
712
			 
713
         procedure ComputeBarycenter(var barycenter : TAffineVector);
714
         procedure ComputeNaturals(const barycenter : TAffineVector;
715
                                   var natX, natY, natZ : TAffineVector);
716

717
      public
718
			 
719
         procedure ComputeRigidityParameters;
720
         procedure SatisfyConstraint(const iteration, maxIterations : Integer); override;
721
   end;
722

723
   // TVCSlider
724
   //
725
   { Slider constraint.
726
      Imposes that two nodes be aligned on a defined direction, on which they
727
      can slide freely. Note that the direction is fixed and won't rotate
728
      with the verlet assembly!. }
729
   TVCSlider = class (TGLVerletDualConstraint)
730
      private
731
			 
732
         FSlideDirection : TAffineVector;
733
         FConstrained : Boolean;
734

735
      protected
736
          
737
         procedure SetSlideDirection(const value : TAffineVector);
738

739
      public
740
			 
741
         procedure SatisfyConstraint(const iteration, maxIterations : Integer); override;
742

743
         property SlideDirection : TAffineVector read FSlideDirection write SetSlideDirection;
744
         { Constrain NodeB to the halfplane defined by NodeA and SlideDirection. } 
745
         property Constrained : Boolean read FConstrained write FConstrained;
746
   end;
747

748
   // TVCSphere
749
   //
750
   { Sphere collision constraint. }
751
   TVCSphere = class (TGLVerletGlobalFrictionConstraintSphere)
752
      private
753
			 
754
         FRadius  : Single;
755

756
      public
757
			 
758
         function GetBSphere : TBSphere; override;
759
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
760
                           const iteration, maxIterations : Integer); override;
761

762
         procedure SatisfyConstraintForEdge(const aEdge : TGLVerletEdge;
763
                        const iteration, maxIterations : Integer); override;
764

765
         property Radius : Single read FRadius write FRadius;
766
   end;
767

768
   // TVCCylinder
769
   //
770
   { Cylinder collision constraint.
771
      The cylinder is considered infinite by this constraint. }
772
   TVCCylinder = class (TGLVerletGlobalFrictionConstraint)
773
      private
774
			 
775
         FAxis : TAffineVector;
776
         FRadius, FRadius2  : Single;
777

778
      protected
779
			 
780
         procedure SetRadius(const val : Single);
781

782
      public
783
			 
784
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
785
                           const iteration, maxIterations : Integer); override;
786

787
         { A base point on the cylinder axis.
788
            Can theoretically be anywhere, however, to reduce floating point
789
            precision issues, choose it in the area where collision detection
790
            will occur. }
791
         //property Base : TAffineVector read FBase write FBase;
792
         { Cylinder axis vector.
793
            Must be normalized. }
794
         property Axis : TAffineVector read FAxis write FAxis;
795
         { Cylinder radius. }
796
         property Radius : Single read FRadius write SetRadius;
797
   end;
798

799
   // TVCCube
800
   //
801
   { Cube collision constraint. }
802
   TVCCube = class (TGLVerletGlobalFrictionConstraintBox)
803
      private
804
			 
805
         FHalfSides : TAffineVector;
806
         FSides: TAffineVector;
807
         FDirection: TAffineVector;
808
         procedure SetSides(const Value: TAffineVector);
809

810
      public
811
			 
812
         function GetAABB : TAABB; override;
813

814
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
815
                           const iteration, maxIterations : Integer); override;
816

817
         // Broken and very slow!
818
         procedure SatisfyConstraintForEdge(const aEdge : TGLVerletEdge;
819
                        const iteration, maxIterations : Integer); override;//}
820

821
         property Direction : TAffineVector read FDirection write FDirection;
822
         property Sides : TAffineVector read FSides write SetSides;
823
   end;
824

825
   // TVCCapsule
826
   //
827
   { Capsule collision constraint. }
828
   TVCCapsule = class (TGLVerletGlobalFrictionConstraintSphere)
829
      private
830
			 
831
         FAxis : TAffineVector;
832
         FRadius, FRadius2, FLength, FLengthDiv2 : Single;
833

834
      protected
835
			 
836
         procedure SetAxis(const val : TAffineVector);
837
         procedure SetRadius(const val : Single);
838
         procedure SetLength(const val : Single);
839

840
      public
841
			 
842
         function GetBSphere: TBSphere; override;
843

844
         procedure SatisfyConstraintForNode(const aNode : TVerletNode;
845
                           const iteration, maxIterations : Integer); override;
846

847
         procedure SatisfyConstraintForEdge(const aEdge : TGLVerletEdge;
848
                        const iteration, maxIterations : Integer); override;
849

850
         // property Base : TAffineVector read FBase write FBase;
851
         property Axis : TAffineVector read FAxis write SetAxis;
852
         property Radius : Single read FRadius write SetRadius;
853
         property Length : Single read FLength write SetLength;
854
   end;
855

856

857
// ------------------------------------------------------------------
858
// ------------------------------------------------------------------
859
// ------------------------------------------------------------------
860
implementation
861
// ------------------------------------------------------------------
862
// ------------------------------------------------------------------
863
// ------------------------------------------------------------------
864
// ------------------
865
// ------------------ TVerletNode ------------------
866
// ------------------
867

868
// Create
869
//
870
constructor TVerletNode.CreateOwned(const aOwner : TGLVerletWorld);
871
begin
872

873
   inherited CreateOwned(aOwner.SpacePartition);
874
   if Assigned(aOwner) then
875
      aOwner.AddNode(Self);
876

877
   FWeight:=1;
878
   FInvWeight:=1;
879
   FRadius:=0;
880
   FFriction:=1;
881
end;
882

883
// Destroy
884
//
885
destructor TVerletNode.Destroy;
886
begin
887
   if Assigned(FOwner) then
888
      FOwner.RemoveNode(Self);
889

890
   inherited;
891
end;
892

893
// ApplyFriction
894
//
895
{ TODO: Improve the friction calculations
896

897
  Friction = - NormalForce * FrictionConstant
898

899
  To compute the NormalForce, which is the force acting on the normal of the
900
  collider, we can use the fact that F = m*a.
901

902
  m is the weight of the node, a is the acceleration (retardation) caused by the
903
  collission.
904

905
  Acceleration := - PenetrationDepth / Owner.FCurrentDeltaTime;
906

907
  The force with which the node has been "stopped" from penetration
908
  NormalForce := Weight * Acceleration;
909

910
  This force should be applied to stopping the movement.
911
}
912
procedure TVerletNode.ApplyFriction(const friction, penetrationDepth : Single;
913
                                    const surfaceNormal : TAffineVector);
914
var
915
   frictionMove, move, moveNormal : TAffineVector;
916
   realFriction : Single;
917
begin
918
   if (penetrationDepth>0) then begin
919
       realFriction := friction*FFriction;
920
       if realFriction>0 then begin
921
           VectorSubtract(Location, OldLocation, move);
922
           moveNormal:=VectorScale(surfaceNormal, VectorDotProduct(move, surfaceNormal));
923
           frictionMove:=VectorSubtract(move, moveNormal);
924
           if penetrationDepth>Radius then
925
              ScaleVector(frictionMove, realFriction)
926
           else ScaleVector(frictionMove, realFriction*Sqrt(penetrationDepth/Radius));
927
           VectorAdd(OldLocation, frictionMove, FOldLocation);
928
       end;
929
   end;
930
end;
931

932
// OldApplyFriction
933
//
934
procedure TVerletNode.OldApplyFriction(const friction, penetrationDepth : Single);
935
var
936
   frictionMove, move : TAffineVector;
937
//   pd : Single;
938
begin
939
   VectorSubtract(Location, OldLocation, move);
940
   VectorScale(move, friction*FFriction, frictionMove);
941
   //pd:=Abs(penetrationDepth);
942
   //ScaleVector(frictionMove, friction*pd);
943
   VectorAdd(OldLocation, frictionMove, FOldLocation);
944
end;
945

946
// DistanceToNode
947
//
948
function TVerletNode.DistanceToNode(const node : TVerletNode) : Single;
949
begin
950
   Result:=VectorDistance(Location, node.Location);
951
end;
952

953
// GetMovement
954
//
955
function TVerletNode.GetMovement : TAffineVector;
956
begin
957
   Result:=VectorSubtract(Location, OldLocation);
958
end;
959

960
// Initialize
961
//
962
procedure TVerletNode.Initialize;
963
begin
964
   FOldLocation:=Location;
965
end;
966

967
// SetWeight
968
//
969
procedure TVerletNode.SetWeight(const value : Single);
970
begin
971
   FWeight:=value;
972
   if value<>0 then
973
      FInvWeight:=1/value
974
   else FInvWeight:=1;
975
end;
976

977
// Verlet
978
//
979
procedure TVerletNode.Verlet(const vpt : TVerletProgressTimes);
980
var
981
  newLocation, temp, move, accel : TAffineVector;
982
begin
983
   if NailedDown then begin
984
      FOldLocation:=Location;
985
   end else begin
986
      if Owner.Inertia then begin
987
         temp:=Location;
988
         VectorSubtract(Location, OldLocation, move);
989

990
         ScaleVector(move, 1-Owner.Drag);//*Sqr(deltaTime));
991

992
         VectorAdd(Location, move, newLocation);
993

994
         VectorScale(Force, vpt.sqrDeltaTime*FInvWeight, accel);
995
         AddVector(newLocation, accel);
996

997
         Location:=newLocation;
998
         FOldLocation:=temp;
999
      end else begin
1000
         newLocation := Location;
1001
         VectorScale(Force, vpt.sqrDeltaTime*FInvWeight, accel);
1002
         AddVector(newLocation, accel);
1003

1004
         Location := newLocation;
1005
         FOldLocation:=Location;
1006
      end;
1007
   end;
1008
end;
1009

1010
// Updated
1011
//
1012
procedure TVerletNode.AfterProgress;
1013
begin
1014
   // nothing here, reserved for subclass use
1015
end;
1016

1017
// ------------------
1018
// ------------------ TVerletNodeList ------------------
1019
// ------------------
1020

1021
// GetItems
1022
//
1023
function TVerletNodeList.GetItems(i : Integer) : TVerletNode;
1024
begin
1025
   Result:=Get(i);
1026
end;
1027

1028
// SetItems
1029
//
1030
procedure TVerletNodeList.SetItems(i : Integer; const value : TVerletNode);
1031
begin
1032
   Put(i, value);
1033
end;
1034

1035
function TVerletNode.GetSpeed: TAffineVector;
1036
begin
1037
  result := VectorScale(VectorSubtract(FLocation, FOldLocation), 1/Owner.CurrentDeltaTime);
1038
end;
1039

1040
// ------------------
1041
// ------------------ TVerletConstraint ------------------
1042
// ------------------
1043

1044
// Create
1045
//
1046
constructor TVerletConstraint.Create(const aOwner : TGLVerletWorld);
1047
begin
1048
   inherited Create;
1049
   if Assigned(aOwner) then
1050
      aOwner.AddConstraint(Self);
1051
   FEnabled:=True;
1052
end;
1053

1054
// Destroy
1055
//
1056
destructor TVerletConstraint.Destroy;
1057
begin
1058
   if Assigned(FOwner) then
1059
      FOwner.RemoveConstraint(Self);
1060
   inherited;
1061
end;
1062

1063
// Create
1064
//
1065
procedure TVerletConstraint.BeforeIterations;
1066
begin
1067
  // NADA!
1068
end;
1069

1070
// ------------------
1071
// ------------------ TGLVerletDualConstraint ------------------
1072
// ------------------
1073

1074
// RemoveNode
1075
//
1076
procedure TGLVerletDualConstraint.RemoveNode(const aNode : TVerletNode);
1077
begin
1078
   if FNodeA=aNode then
1079
      FNodeA:=nil;
1080
   if FNodeB=aNode then
1081
      FNodeB:=nil;
1082
   if (FNodeA=nil) and (FNodeA=nil) then
1083
      Free;
1084
end;
1085

1086
// ------------------
1087
// ------------------ TVerletGroupConstraint ------------------
1088
// ------------------
1089

1090
// Create
1091
//
1092
constructor TVerletGroupConstraint.Create(const aOwner : TGLVerletWorld);
1093
begin
1094
   inherited Create(aOwner);
1095
   FNodes:=TVerletNodeList.Create;
1096
end;
1097

1098
// Destroy
1099
//
1100
destructor TVerletGroupConstraint.Destroy;
1101
begin
1102
   FNodes.Free;
1103
   inherited;
1104
end;
1105

1106
// RemoveNode
1107
//
1108
procedure TVerletGroupConstraint.RemoveNode(const aNode : TVerletNode);
1109
begin
1110
   FNodes.Remove(aNode);
1111
end;
1112

1113
// ------------------
1114
// ------------------ TGLVerletGlobalConstraint ------------------
1115
// ------------------
1116

1117
// RemoveNode
1118
//
1119

1120
procedure TGLVerletGlobalConstraint.AddKickbackForceAt(const Pos : TAffineVector; const Force: TAffineVector);
1121
var
1122
  dPos : TAffineVector;
1123
begin
1124
  // Sum forces
1125
  AddVector(FKickbackForce, Force);
1126

1127
  // Sum torques
1128
  dPos := VectorSubtract(Pos, FLocation);
1129
  AddVector(FKickbackTorque, VectorCrossProduct(dPos, Force));
1130
end;
1131

1132
function TGLVerletGlobalConstraint.TranslateKickbackTorque(
1133
  const TorqueCenter: TAffineVector): TAffineVector;
1134
begin
1135
  // EM(b) = EM(a) + EF x VectorSubtract(b, a). 
1136
  Result := VectorAdd(FKickbackTorque, VectorCrossProduct(VectorSubtract(TorqueCenter, FLocation), FKickbackForce));
1137
end;
1138

1139
procedure TGLVerletGlobalConstraint.BeforeIterations;
1140
begin
1141
  inherited;
1142
  FKickbackForce := NullVector;
1143
  FKickbackTorque := NullVector;
1144
end;
1145

1146
procedure TGLVerletGlobalConstraint.RemoveNode(const aNode : TVerletNode);
1147
begin
1148
   // nothing to do here
1149
end;
1150

1151
// SetLocation
1152
//
1153
procedure TGLVerletGlobalConstraint.SetLocation(const Value: TAffineVector);
1154
begin
1155
  FLocation := Value;
1156
end;
1157

1158
// SatisfyConstraint
1159
//
1160
procedure TGLVerletGlobalConstraint.SatisfyConstraint(const iteration, maxIterations : Integer);
1161
var
1162
   i : Integer;
1163
   node : TVerletNode;
1164
begin
1165
   if cctNode in Owner.CollisionConstraintTypes then
1166
     for i:=0 to Owner.Nodes.Count-1 do begin
1167
        node:=TVerletNode(Owner.Nodes[i]);
1168
        if not node.NailedDown then
1169
           SatisfyConstraintForNode(node, iteration, maxIterations);
1170
     end;//}
1171

1172
   if cctEdge in Owner.CollisionConstraintTypes then
1173
     for i:=0 to Owner.SolidEdges.Count-1 do begin
1174
         SatisfyConstraintForEdge(Owner.SolidEdges[i], iteration, maxIterations);
1175
   end;//}
1176
end;
1177

1178
// SatisfyConstraintForEdge
1179
//
1180
procedure TGLVerletGlobalConstraint.SatisfyConstraintForEdge(
1181
  const aEdge: TGLVerletEdge; const iteration, maxIterations: Integer);
1182
begin
1183
  // Purely virtual, but can't be abstract...
1184
end;
1185

1186
// ------------------
1187
// ------------------ TGLVerletGlobalFrictionConstraint ------------------
1188
// ------------------
1189

1190
// Create
1191
//
1192
constructor TGLVerletGlobalFrictionConstraint.Create(const aOwner: TGLVerletWorld);
1193
begin
1194
   inherited;
1195
   FFrictionRatio:=cDEFAULT_CONSTRAINT_FRICTION;
1196
end;
1197

1198
// ------------------
1199
// ------------------ TGLVerletGlobalFrictionConstraintSP ------------------
1200
// ------------------
1201

1202
// SatisfyConstraint
1203
//
1204
procedure TGLVerletGlobalFrictionConstraintSP.SatisfyConstraint(
1205
                              const iteration, maxIterations: Integer);
1206
var
1207
   i : Integer;
1208
   node : TVerletNode;
1209
   edge : TGLVerletEdge;
1210
   SP : TBaseSpacePartition;
1211
   Leaf : TSpacePartitionLeaf;
1212
begin
1213
   if Owner.SpacePartition=nil then begin
1214
      inherited;
1215
      Exit;
1216
   end;
1217

1218
   PerformSpaceQuery;
1219
   SP := Owner.SpacePartition;
1220

1221
   for i:=0 to SP.QueryResult.Count-1 do begin
1222
      Leaf:=SP.QueryResult[i];
1223
      if Leaf is TVerletNode then begin
1224
         if cctNode in Owner.CollisionConstraintTypes then begin
1225
            node := Leaf as TVerletNode;
1226
            if not node.NailedDown then
1227
               SatisfyConstraintForNode(node, iteration, maxIterations);
1228
         end;
1229
      end else if Leaf is TGLVerletEdge then begin
1230
         if cctEdge in Owner.CollisionConstraintTypes then begin
1231
            edge := Leaf as TGLVerletEdge;
1232
            SatisfyConstraintForEdge(edge, iteration, maxIterations);
1233
         end;
1234
      end else Assert(False, 'Bad objects in list!');
1235
   end;
1236
end;
1237

1238
// ------------------
1239
// ------------------ TVerletConstraintList ------------------
1240
// ------------------
1241

1242
// GetItems
1243
//
1244
function TVerletConstraintList.GetItems(i : Integer) : TVerletConstraint;
1245
begin
1246
   Result:=Get(i);
1247
end;
1248

1249
// SetItems
1250
//
1251
procedure TVerletConstraintList.SetItems(i : Integer;
1252
                                         const value : TVerletConstraint);
1253
begin
1254
   Put(i, value);
1255
end;
1256

1257
// ------------------
1258
// ------------------ TVerletForce ------------------
1259
// ------------------
1260

1261
// Create
1262
//
1263
constructor TVerletForce.Create(const aOwner : TGLVerletWorld);
1264
begin
1265
   inherited Create;
1266
   if Assigned(aOwner) then
1267
      aOwner.AddForce(Self);
1268
end;
1269

1270
// Destroy
1271
//
1272
destructor TVerletForce.Destroy;
1273
begin
1274
   if Assigned(FOwner) then
1275
      FOwner.RemoveForce(Self);
1276
   inherited;
1277
end;
1278

1279
// ------------------
1280
// ------------------ TVerletGroupForce ------------------
1281
// ------------------
1282

1283
// Create
1284
//
1285
constructor TVerletGroupForce.Create(const aOwner : TGLVerletWorld);
1286
begin
1287
   inherited Create(aOwner);
1288
   FNodes:=TVerletNodeList.Create;
1289
end;
1290

1291
// Destroy
1292
//
1293
destructor TVerletGroupForce.Destroy;
1294
begin
1295
   FNodes.Free;
1296
   inherited;
1297
end;
1298

1299
// RemoveNode
1300
//
1301
procedure TVerletGroupForce.RemoveNode(const aNode : TVerletNode);
1302
begin
1303
   FNodes.Remove(aNode);
1304
end;
1305

1306
// ------------------
1307
// ------------------ TGLVerletGlobalForce ------------------
1308
// ------------------
1309

1310
// RemoveNode
1311
//
1312
procedure TGLVerletGlobalForce.RemoveNode(const aNode : TVerletNode);
1313
begin
1314
   // nothing to do here
1315
end;
1316

1317
// AddForce
1318
//
1319
procedure TGLVerletGlobalForce.AddForce;
1320
var
1321
   i : Integer;
1322
   node : TVerletNode;
1323
begin
1324
   for i:=0 to Owner.Nodes.Count-1 do begin
1325
      node:=TVerletNode(Owner.Nodes.List[i]);
1326
      if not node.NailedDown then
1327
         AddForceToNode(node);
1328
   end;
1329
end;
1330

1331
// ------------------
1332
// ------------------ TGLVerletDualForce ------------------
1333
// ------------------
1334

1335
// RemoveNode
1336
//
1337
procedure TGLVerletDualForce.RemoveNode(const aNode : TVerletNode);
1338
begin
1339
   if FNodeA=aNode then
1340
      FNodeA:=nil;
1341
   if FNodeB=aNode then
1342
      FNodeB:=nil;
1343
end;
1344

1345
// ------------------
1346
// ------------------ TVerletForceList ------------------
1347
// ------------------
1348

1349
// GetItems
1350
//
1351
function TVerletForceList.GetItems(i : Integer) : TVerletForce;
1352
begin
1353
   Result:=Get(i);
1354
end;
1355

1356
// SetItems
1357
//
1358
procedure TVerletForceList.SetItems(i : Integer; const value : TVerletForce);
1359
begin
1360
   Put(i, value);
1361
end;
1362

1363
// ------------------
1364
// ------------------ TGLVerletWorld ------------------
1365
// ------------------
1366

1367
// Create
1368
//
1369
constructor TGLVerletWorld.Create;
1370
begin
1371
   inherited;
1372
   FDrag:=G_DRAG;
1373
   FNodes:=TVerletNodeList.Create;
1374
   FConstraints:=TVerletConstraintList.Create;
1375
   FConstraintsWithBeforeIterations:=TVerletConstraintList.Create;
1376
   FForces:=TVerletForceList.Create;
1377
   FMaxDeltaTime:=0.02;
1378
   FIterations:=3;
1379
   FSolidEdges := TGLVerletEdgeList.Create;
1380
   FCurrentStepCount := 0;
1381
   FUpdateSpacePartion := uspNever;
1382
   FCollisionConstraintTypes := [cctNode, cctEdge];
1383
   FSpacePartition := nil;
1384
   FVerletNodeClass := TVerletNode;
1385
   FInertia := True;
1386
end;
1387

1388
// Destroy
1389
//
1390
destructor TGLVerletWorld.Destroy;
1391
var
1392
   i : Integer;
1393
begin
1394
   // Delete all nodes
1395
   for i:=0 to FNodes.Count-1 do with FNodes[i] do begin
1396
      FOwner:=nil;
1397
      Free;
1398
   end;
1399
   FreeAndNil(FNodes);
1400
   // Delete all constraints
1401
   for i:=0 to FConstraints.Count-1 do with FConstraints[i] do begin
1402
      FOwner:=nil;
1403
      Free;
1404
   end;
1405
   FreeAndNil(FConstraints);
1406
   // Delete all forces
1407
   for i:=0 to FForces.Count-1 do with FForces[i] do begin
1408
      FOwner:=nil;
1409
      Free;
1410
   end;
1411
   FreeAndNil(FForces);
1412
   FreeAndNil(FConstraintsWithBeforeIterations);
1413

1414
   for i := 0 to FSolidEdges.Count-1 do
1415
    FSolidEdges[i].Free;
1416
   FreeAndNil(FSolidEdges);
1417

1418
   FreeAndNil(FSpacePartition);
1419

1420
   inherited;
1421
end;
1422

1423
// AccumulateForces
1424
//
1425
procedure TGLVerletWorld.AccumulateForces(const vpt : TVerletProgressTimes);
1426
var
1427
   i : Integer;
1428
begin
1429
   // First of all, reset all forces
1430
   for i:=0 to FNodes.Count-1 do
1431
      FNodes[i].FForce:=NullVector;
1432
   // Now, update all forces in the assembly!
1433
   for i:=0 to FForces.Count-1 do
1434
      FForces[i].AddForce(vpt);
1435
end;
1436

1437
// AddNode
1438
//
1439
function TGLVerletWorld.AddNode(const aNode : TVerletNode) : Integer;
1440
begin
1441
   if Assigned(aNode.FOwner) then
1442
      aNode.Owner.FNodes.Remove(aNode);
1443
   Result:=FNodes.Add(aNode);
1444
   aNode.FOwner:=Self;
1445
end;
1446

1447
// RemoveNode
1448
//
1449
procedure TGLVerletWorld.RemoveNode(const aNode : TVerletNode);
1450
var
1451
   i : Integer;
1452
begin
1453
   if aNode.Owner=Self then begin
1454
      FNodes.Remove(aNode);
1455
      aNode.FOwner:=nil;
1456
      // drop refs in constraints
1457
      for i:=FConstraints.Count-1 downto 0 do
1458
         FConstraints[i].RemoveNode(aNode);
1459
      // drop refs in forces
1460
      for i:=FForces.Count-1 downto 0 do
1461
         FForces[i].RemoveNode(aNode);
1462
   end;
1463
end;
1464

1465
// AddConstraint
1466
//
1467
function TGLVerletWorld.AddConstraint(const aConstraint : TVerletConstraint) : Integer;
1468
begin
1469
   if Assigned(aConstraint.FOwner) then
1470
      aConstraint.Owner.FConstraints.Remove(aConstraint);
1471
   Result:=FConstraints.Add(aConstraint);
1472
   aConstraint.FOwner:=Self;
1473
end;
1474

1475
// RemoveConstraint
1476
//
1477
procedure TGLVerletWorld.RemoveConstraint(const aConstraint : TVerletConstraint);
1478
begin
1479
   if aConstraint.Owner=Self then begin
1480
      FConstraints.Remove(aConstraint);
1481
      aConstraint.FOwner:=nil;
1482
   end;
1483
end;
1484

1485
// AddForce
1486
//
1487
function TGLVerletWorld.AddForce(const aForce : TVerletForce) : Integer;
1488
begin
1489
   if Assigned(aForce.FOwner) then
1490
      aForce.Owner.FForces.Remove(aForce);
1491
   Result:=FForces.Add(aForce);
1492
   aForce.FOwner:=Self;
1493
end;
1494

1495
// RemoveForce
1496
//
1497
procedure TGLVerletWorld.RemoveForce(const aForce : TVerletForce);
1498
begin
1499
   if aForce.Owner=Self then begin
1500
      FForces.Remove(aForce);
1501
      aForce.FOwner:=nil;
1502
   end;
1503
end;
1504

1505
// AddSolidEdge
1506
//
1507
procedure TGLVerletWorld.AddSolidEdge(const aNodeA, aNodeB: TVerletNode);
1508
var
1509
  VerletEdge : TGLVerletEdge;
1510
begin
1511
  VerletEdge := TGLVerletEdge.CreateEdgeOwned(aNodeA, aNodeB);
1512
  SolidEdges.Add(VerletEdge);
1513
end;
1514

1515
// FirstNode
1516
//
1517
function TGLVerletWorld.FirstNode : TVerletNode;
1518
begin
1519
   Assert(FNodes.Count>0, 'There are no nodes in the assembly!');
1520
   Result:=FNodes[0];
1521
end;
1522

1523
// lastNode
1524
//
1525
function TGLVerletWorld.LastNode : TVerletNode;
1526
begin
1527
   Assert(FNodes.Count>0, 'There are no nodes in the assembly!');
1528
   Result:=FNodes[FNodes.Count-1];
1529
end;
1530

1531
// CreateOwnedNode
1532
//
1533
function TGLVerletWorld.CreateOwnedNode(const location : TAffineVector;
1534
            const aRadius : Single = 0; const aWeight : Single=1) : TVerletNode;
1535
begin
1536
   Result:=VerletNodeClass.CreateOwned(self);
1537
   Result.Location:=Location;
1538
   Result.OldLocation:=Location;
1539
   Result.Weight:=aWeight;
1540
   Result.Radius:=aRadius;
1541
end;
1542

1543
// CreateStick
1544
//
1545
function TGLVerletWorld.CreateStick(const aNodeA, aNodeB : TVerletNode; const Slack : Single = 0) : TVCStick;
1546
begin
1547
   Assert(aNodeA <> aNodeB, 'Can''t create stick between same node!');
1548
   Result:=TVCStick.Create(Self);
1549
   Result.NodeA:=aNodeA;
1550
   Result.NodeB:=aNodeB;
1551
   Result.SetRestLengthToCurrent;
1552
   Result.Slack := Slack;
1553
end;
1554

1555
// CreateSpring
1556
//
1557
function TGLVerletWorld.CreateSpring(const aNodeA, aNodeB : TVerletNode;
1558
              const aStrength, aDamping : Single; const aSlack : Single = 0) : TVFSpring;
1559
begin
1560
   Result:=TVFSpring.Create(Self);
1561
   Result.NodeA:=aNodeA;
1562
   Result.NodeB:=aNodeB;
1563
   Result.Strength:=aStrength;
1564
   Result.Damping:=aDamping;
1565
   Result.Slack:=aSlack;
1566
   Result.SetRestLengthToCurrent;
1567
end;
1568

1569
// CreateSlider
1570
//
1571
function TGLVerletWorld.CreateSlider(const aNodeA, aNodeB : TVerletNode;
1572
                                   const aSlideDirection : TAffineVector) : TVCSlider;
1573
begin
1574
   Result:=TVCSlider.Create(Self);
1575
   Result.NodeA:=aNodeA;
1576
   Result.NodeB:=aNodeB;
1577
   Result.SlideDirection:=aSlideDirection;
1578
end;
1579

1580
// Initialize
1581
//
1582
procedure TGLVerletWorld.Initialize;
1583
var
1584
   i : Integer;
1585
begin
1586
   for i:=0 to FNodes.Count-1 do
1587
      FNodes[i].Initialize;
1588
end;
1589

1590
// Progress
1591
//
1592
function TGLVerletWorld.Progress(const deltaTime, newTime : Double) : Integer;
1593
var
1594
   i : Integer;
1595
   ticks : Integer;
1596
   myDeltaTime : Single;
1597
   vpt : TVerletProgressTimes;
1598
begin
1599
   ticks:=0;
1600
   myDeltaTime:=FMaxDeltaTime;
1601
   FCurrentDeltaTime:=FMaxDeltaTime;
1602
   FInvCurrentDeltaTime:=1/FCurrentDeltaTime;
1603

1604
   vpt.deltaTime:=myDeltaTime;
1605
   vpt.sqrDeltaTime:=Sqr(myDeltaTime);
1606
   vpt.invSqrDeltaTime:=1/vpt.sqrDeltaTime;
1607

1608
   while FSimTime<newTime do begin
1609
      Inc(ticks);
1610
      FSimTime:=FSimTime+myDeltaTime;
1611
      vpt.newTime:=FSimTime;
1612
      Verlet(vpt);
1613
      AccumulateForces(vpt);
1614
      SatisfyConstraints(vpt);
1615

1616
      if FInertaPauseSteps>0 then
1617
      begin
1618
        dec(FInertaPauseSteps);
1619
        if FInertaPauseSteps=0 then
1620
          Inertia := true;
1621
      end;
1622

1623
      Break;
1624
   end;
1625

1626
   Result:=ticks;
1627

1628
   for i:=0 to FNodes.Count-1 do
1629
      FNodes[i].AfterProgress;
1630
end;
1631

1632
// DoUpdateSpacePartition
1633
//
1634
procedure TGLVerletWorld.DoUpdateSpacePartition;
1635
var
1636
  i : Integer;
1637
begin
1638
  if Assigned(SpacePartition) then
1639
  begin
1640
    for i:=0 to FSolidEdges.Count-1 do
1641
      if (FSolidEdges[i].FNodeA.FChangedOnStep=FCurrentStepCount) or
1642
         (FSolidEdges[i].FNodeB.FChangedOnStep=FCurrentStepCount) then
1643
        FSolidEdges[i].Changed;
1644

1645
    for i:=0 to FNodes.Count-1 do
1646
      if (FNodes[i].FChangedOnStep=FCurrentStepCount) then
1647
        FNodes[i].Changed;
1648
  end;
1649
end;
1650

1651
// SatisfyConstraints
1652
//
1653
procedure TGLVerletWorld.SatisfyConstraints(const vpt : TVerletProgressTimes);
1654
var
1655
   i, j : Integer;
1656
   Constraint : TVerletConstraint;
1657
begin
1658
   for i:=0 to FConstraintsWithBeforeIterations.Count-1 do
1659
   begin
1660
     Constraint := FConstraintsWithBeforeIterations[i];
1661
     Constraint.BeforeIterations;
1662
   end;
1663

1664
   if UpdateSpacePartion=uspEveryFrame then
1665
     inc(FCurrentStepCount);
1666

1667
   for j:=0 to Iterations-1 do
1668
   begin
1669
      for i:=0 to FConstraints.Count-1 do with FConstraints[i] do
1670
         if Enabled then
1671
            SatisfyConstraint(j, Iterations);//}
1672

1673
      if UpdateSpacePartion=uspEveryIteration then
1674
        DoUpdateSpacePartition;
1675
   end;
1676

1677
   if UpdateSpacePartion=uspEveryFrame then
1678
    DoUpdateSpacePartition;//}
1679
end;
1680

1681
// Verlet
1682
//
1683
procedure TGLVerletWorld.Verlet(const vpt : TVerletProgressTimes);
1684
var
1685
   i : Integer;
1686
begin
1687
   if UpdateSpacePartion<>uspNever then
1688
     inc(FCurrentStepCount);
1689

1690
   for i:=0 to FNodes.Count-1 do
1691
      FNodes[i].Verlet(vpt);
1692

1693
   if UpdateSpacePartion<>uspNever then
1694
    DoUpdateSpacePartition;
1695
end;
1696

1697
// ------------------
1698
// ------------------ TVFGravity ------------------
1699
// ------------------
1700

1701
// Create
1702
//
1703
constructor TVFGravity.Create(const aOwner : TGLVerletWorld);
1704
begin
1705
   inherited;
1706
   FGravity.V[0]:=0;
1707
   FGravity.V[1]:=-9.81;
1708
   FGravity.V[2]:=0;
1709
end;
1710

1711
// AddForceToNode
1712
//
1713
procedure TVFGravity.AddForceToNode(const aNode : TVerletNode);
1714
begin
1715
   CombineVector(aNode.FForce, Gravity, @aNode.Weight);
1716
end;
1717

1718
// ------------------
1719
// ------------------ TVFSpring ------------------
1720
// ------------------
1721

1722
// SetSlack
1723
//
1724
procedure TVFSpring.SetSlack(const value : Single);
1725
begin
1726
   if value<=0 then
1727
      FSlack:=0
1728
   else FSlack:=value;
1729
end;
1730

1731
// AddForce
1732
//
1733
procedure TVFSpring.AddForce;
1734
var
1735
   hTerm, dTerm : Single;
1736
   deltaV, force : TAffineVector;
1737
   deltaLength : Single;
1738
begin
1739
   VectorSubtract(NodeA.Location, NodeB.Location, force);
1740
   deltaLength:=VectorLength(force);
1741

1742
   if deltaLength>FSlack then begin
1743
     hTerm:=(FRestLength-deltaLength)*FForceFactor;
1744
     force:=VectorScale(force, hTerm/deltaLength);
1745
   end else force:=NullVector;
1746
   if FDamping<>0 then begin
1747
      VectorSubtract(NodeA.GetMovement, NodeB.GetMovement, deltaV);
1748
      dTerm:=-0.25*FDamping*vpt.invSqrDeltaTime;
1749
      CombineVector(force, deltaV, dTerm);
1750
   end;
1751

1752
   AddVector(NodeA.FForce, force);
1753
   SubtractVector(NodeB.FForce, force);
1754
end;
1755

1756
// SetRestLengthToCurrent
1757
//
1758
procedure TVFSpring.SetRestLengthToCurrent;
1759
begin
1760
   FRestLength:=VectorDistance(NodeA.Location, NodeB.Location);
1761
   FForceFactor:=FStrength/FRestLength;
1762
end;
1763

1764
// ------------------
1765
// ------------------ TVFAirResistance ------------------
1766
// ------------------
1767

1768
procedure TVFAirResistance.AddForceToNode(const aNode: TVerletNode);
1769
var
1770
  s, F, FCurrentWindBurst : TAffineVector;
1771
  sMag : Single;
1772
  r : Single;
1773
  Chaos : Single;
1774
begin
1775
  s := aNode.Speed;
1776

1777
  if FWindMagnitude<>0 then
1778
  begin
1779
    Chaos := FWindMagnitude * FWindChaos;
1780
    FCurrentWindBurst.V[0] := FWindDirection.V[0] * FWindMagnitude + Chaos * (random-0.5) * 2;
1781
    FCurrentWindBurst.V[1] := FWindDirection.V[1] * FWindMagnitude + Chaos * (random-0.5) * 2;
1782
    FCurrentWindBurst.V[2] := FWindDirection.V[2] * FWindMagnitude + Chaos * (random-0.5) * 2;
1783

1784
    s := VectorSubtract(s, FCurrentWindBurst);
1785
  end;
1786

1787
  sMag := VectorLength(s);
1788

1789
  r := aNode.Radius + 1;
1790

1791
  if sMag<> 0 then
1792
  begin
1793
    F := VectorScale(s, - sqr(sMag) * sqr(r) * pi * FDragCoeff);
1794

1795
    aNode.FForce := VectorAdd(aNode.FForce, F);
1796
  end;
1797
end;
1798

1799
constructor TVFAirResistance.Create(const aOwner: TGLVerletWorld);
1800
begin
1801
  inherited;
1802

1803
  FDragCoeff := 0.001;
1804
  FWindDirection.V[0] := 0;
1805
  FWindDirection.V[1] := 0;
1806
  FWindDirection.V[2] := 0;
1807
  FWindMagnitude := 0;
1808
  FWindChaos := 0;
1809
end;
1810

1811
procedure TVFAirResistance.SetWindDirection(const Value: TAffineVector);
1812
begin
1813
  FWindDirection := VectorNormalize(Value);
1814
end;
1815

1816
// ------------------
1817
// ------------------ TVCFloor ------------------
1818
// ------------------
1819

1820
// Create
1821
//
1822
constructor TVCFloor.Create(const aOwner: TGLVerletWorld);
1823
begin
1824
  inherited;
1825
  MakeVector(FNormal, 0, 1, 0);
1826
  MakeVector(FLocation, 0, 0, 0);
1827
end;
1828

1829
// PerformSpaceQuery
1830
//
1831
procedure TVCFloor.PerformSpaceQuery;
1832
begin
1833
   Owner.SpacePartition.QueryPlane(FLocation, FNormal);
1834
end;
1835

1836
// SatisfyConstraintForNode
1837
//
1838
procedure TVCFloor.SatisfyConstraintForNode(const aNode : TVerletNode;
1839
                                            const iteration, maxIterations : Integer);
1840
var
1841
   penetrationDepth : Single;
1842
   currentPenetrationDepth : Single;
1843
   d : TAffineVector;
1844
   correction : TAffineVector;
1845
begin
1846
   currentPenetrationDepth:=-PointPlaneDistance(aNode.Location, FLocation, FNormal)
1847
                            +aNode.Radius+FFloorLevel;
1848

1849
   // Record how far down the node goes
1850
   penetrationDepth:=currentPenetrationDepth;
1851
   // Correct the node location
1852
   if currentPenetrationDepth>0 then begin
1853
      correction:=VectorScale(FNormal, currentPenetrationDepth);
1854
      if BounceRatio>0 then begin
1855
         d:=VectorSubtract(aNode.FLocation, aNode.FOldLocation);
1856
         if FrictionRatio>0 then
1857
            aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
1858
         AddVector(aNode.FLocation, correction);
1859
         aNode.FOldLocation:=VectorAdd(aNode.FLocation, VectorScale(d, BounceRatio));
1860
      end else begin
1861
         AddVector(aNode.FLocation, correction);
1862
         if FrictionRatio>0 then
1863
            aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
1864
         aNode.FChangedOnStep:=Owner.CurrentStepCount;
1865
      end;
1866
   end;
1867
end;
1868

1869
// SetNormal
1870
//
1871
procedure TVCFloor.SetNormal(const Value: TAffineVector);
1872
begin
1873
  FNormal := Value;
1874
  NormalizeVector(FNormal);
1875
end;
1876

1877
// ------------------
1878
// ------------------ TVCHeightField ------------------
1879
// ------------------
1880

1881
// SatisfyConstraintForNode
1882
//
1883
procedure TVCHeightField.SatisfyConstraintForNode(const aNode : TVerletNode;
1884
                                            const iteration, maxIterations : Integer);
1885
var
1886
   penetrationDepth : Single;
1887
   currentPenetrationDepth : Single;
1888
   d : TAffineVector;
1889
   correction : TAffineVector;
1890
begin
1891
   currentPenetrationDepth:=-PointPlaneDistance(aNode.Location, FLocation, FNormal)+aNode.Radius;
1892
   if Assigned(FOnNeedHeight) then
1893
      currentPenetrationDepth:=currentPenetrationDepth+FOnNeedHeight(Self, aNode);
1894

1895
   // Record how far down the node goes
1896
   penetrationDepth:=currentPenetrationDepth;
1897
   // Correct the node location
1898
   if currentPenetrationDepth>0 then begin
1899
      correction:=VectorScale(FNormal, currentPenetrationDepth);
1900
      if BounceRatio>0 then begin
1901
         d:=VectorSubtract(aNode.FLocation, aNode.FOldLocation);
1902
         if FrictionRatio>0 then
1903
            aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
1904
         AddVector(aNode.FLocation, correction);
1905
         aNode.FOldLocation:=VectorAdd(aNode.FLocation, VectorScale(d, BounceRatio));
1906
      end else begin
1907
         AddVector(aNode.FLocation, correction);
1908
         if FrictionRatio>0 then
1909
            aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
1910
         aNode.FChangedOnStep:=Owner.CurrentStepCount;
1911
      end;
1912
   end;
1913
end;
1914

1915
// ------------------
1916
// ------------------ TVCStick ------------------
1917
// ------------------
1918

1919
// SatisfyConstraint
1920
//
1921
procedure TVCStick.SatisfyConstraint(const iteration, maxIterations : Integer);
1922
var
1923
   delta : TAffineVector;
1924
   f, r : Single;
1925
   deltaLength, diff : Single;
1926
const
1927
   cDefaultDelta : TAffineVector = (X:0.01; Y:0; Z:0);
1928
begin
1929
   Assert((NodeA<>NodeB), 'The nodes are identical - that causes division by zero!');
1930

1931
   VectorSubtract(NodeB.Location, NodeA.Location, delta);
1932
   deltaLength:=VectorLength(delta);
1933
   // Avoid div by zero!
1934
   if deltaLength<1e-3 then begin
1935
      delta:=cDefaultDelta;
1936
      deltaLength:=0.01;
1937
   end;
1938

1939
   diff:=(deltaLength-RestLength)/deltaLength;
1940

1941
   if Abs(diff)>Slack then begin
1942
      r:=1/(NodeA.InvWeight+NodeB.InvWeight);
1943
      if diff<0 then
1944
         diff:=(diff+Slack)*r
1945
      else diff:=(diff-Slack)*r;
1946

1947
      // Take into acount the different weights of the nodes!
1948

1949
      if not NodeA.NailedDown then begin
1950
         f:=diff*NodeA.InvWeight;
1951
         CombineVector(NodeA.FLocation, delta, f);
1952
         NodeA.FChangedOnStep := Owner.CurrentStepCount;
1953
      end;
1954
      if not NodeB.NailedDown then begin
1955
         f:=-diff*NodeB.InvWeight;
1956
         CombineVector(NodeB.FLocation, delta, f);
1957
         NodeB.FChangedOnStep := Owner.CurrentStepCount;
1958
      end;
1959
   end;
1960
end;
1961

1962
// SetRestLengthToCurrent
1963
//
1964
procedure TVCStick.SetRestLengthToCurrent;
1965
begin
1966
   FRestLength:=VectorDistance(NodeA.Location, NodeB.Location);
1967
end;
1968

1969
// ------------------
1970
// ------------------ TVCRigidBody ------------------
1971
// ------------------
1972

1973
// ComputeBarycenter
1974
//
1975
procedure TVCRigidBody.ComputeBarycenter(var barycenter : TAffineVector);
1976
var
1977
   i : Integer;
1978
   totWeight : Single;
1979
begin
1980
   // first we compute the barycenter
1981
   totWeight:=0;
1982
   barycenter:=NullVector;
1983
   for i:=0 to Nodes.Count-1 do with Nodes[i] do begin
1984
      CombineVector(barycenter, Location, @Weight);
1985
      totWeight:=totWeight+Weight;
1986
   end;
1987
   if totWeight>0 then
1988
      ScaleVector(barycenter, 1/totWeight);
1989
end;
1990

1991
// ComputeNaturals
1992
//
1993
procedure TVCRigidBody.ComputeNaturals(const barycenter : TAffineVector;
1994
                                       var natX, natY, natZ : TAffineVector);
1995
var
1996
   i : Integer;
1997
   delta : TAffineVector;
1998
begin
1999
   natX:=NullVector;
2000
   natY:=NullVector;
2001
   natZ:=NullVector;
2002
   for i:=0 to Nodes.Count-1 do begin
2003
      delta:=VectorSubtract(Nodes[i].Location, barycenter);
2004
      CombineVector(natX, delta, FNodeParams[i].V[0]);
2005
      CombineVector(natY, delta, FNodeParams[i].V[1]);
2006
      CombineVector(natZ, delta, FNodeParams[i].V[2]);
2007
   end;
2008
end;
2009

2010
// ComputeRigidityParameters
2011
//
2012
procedure TVCRigidBody.ComputeRigidityParameters;
2013
var
2014
   i : Integer;
2015
   barycenter : TAffineVector;
2016
   d : Single;
2017
begin
2018
   // first we compute the barycenter
2019
   ComputeBarycenter(barycenter);
2020
   // next the parameters
2021
   SetLength(FNodeParams, Nodes.Count);
2022
   SetLength(FNodeCoords, Nodes.Count);
2023
   for i:=0 to Nodes.Count-1 do begin
2024
      FNodeCoords[i]:=VectorSubtract(Nodes[i].Location, barycenter);
2025
      d:=Nodes[i].Weight/VectorLength(FNodeCoords[i]);
2026
      FNodeParams[i].V[0]:=FNodeCoords[i].V[0]*d;
2027
      FNodeParams[i].V[1]:=FNodeCoords[i].V[1]*d;
2028
      FNodeParams[i].V[2]:=FNodeCoords[i].V[2]*d;
2029
   end;
2030

2031
   ComputeNaturals(barycenter, FNatMatrix.V[0], FNatMatrix.V[1], FNatMatrix.V[2]);
2032

2033
   FNatMatrix.V[2]:=VectorCrossProduct(FNatMatrix.V[0], FNatMatrix.V[1]);
2034
   FNatMatrix.V[1]:=VectorCrossProduct(FNatMatrix.V[2], FNatMatrix.V[0]);
2035
   NormalizeVector(FNatMatrix.V[0]);
2036
   NormalizeVector(FNatMatrix.V[1]);
2037
   NormalizeVector(FNatMatrix.V[2]);
2038

2039
   FInvNatMatrix:=FNatMatrix;
2040
//   TransposeMatrix(FInvNatMatrix);
2041
   InvertMatrix(FInvNatMatrix);
2042
end;
2043

2044
// SatisfyConstraint
2045
//
2046
procedure TVCRigidBody.SatisfyConstraint(const iteration, maxIterations : Integer);
2047
var
2048
   i : Integer;
2049
   barycenter, delta : TAffineVector;
2050
   nrjBase, nrjAdjust : TaffineVector;
2051
   natural : array [0..2] of TAffineVector;
2052
   deltas : array of TAffineVector;
2053
begin
2054
   Assert(Nodes.Count=Length(FNodeParams), 'You forgot to call ComputeRigidityParameters!');
2055
   // compute the barycenter
2056
   ComputeBarycenter(barycenter);
2057
   // compute the natural axises
2058
   ComputeNaturals(barycenter, natural[0], natural[1], natural[2]);
2059

2060
   natural[2]:=VectorCrossProduct(natural[0], natural[1]);
2061
   natural[1]:=VectorCrossProduct(natural[2], natural[0]);
2062
   for i:=0 to 2 do
2063
      NormalizeVector(natural[i]);
2064

2065
   natural[0]:=VectorTransform(natural[0], FInvNatMatrix);
2066
   natural[1]:=VectorTransform(natural[1], FInvNatMatrix);
2067
   natural[2]:=VectorTransform(natural[2], FInvNatMatrix);
2068
   // make the natural axises orthonormal, by picking the longest two
2069
{   for i:=0 to 2 do
2070
      vectNorm[i]:=VectorNorm(natural[i]);
2071
   if (vectNorm[0]<vectNorm[1]) and (vectNorm[0]<vectNorm[2]) then begin
2072
      natural[0]:=VectorCrossProduct(natural[1], natural[2]);
2073
      natural[1]:=VectorCrossProduct(natural[2], natural[0]);
2074
   end else if (vectNorm[1]<vectNorm[0]) and (vectNorm[1]<vectNorm[2]) then begin
2075
      natural[1]:=VectorCrossProduct(natural[2], natural[0]);
2076
      natural[2]:=VectorCrossProduct(natural[0], natural[1]);
2077
   end else begin
2078
      natural[2]:=VectorCrossProduct(natural[0], natural[1]);
2079
      natural[0]:=VectorCrossProduct(natural[1], natural[2]);
2080
   end; }
2081

2082
   // now the axises are back, recompute the position of all points
2083
   SetLength(deltas, Nodes.Count);
2084
   nrjBase:=NullVector;
2085
   for i:=0 to Nodes.Count-1 do begin
2086
      nrjBase:=VectorAdd(nrjBase, VectorCrossProduct(VectorSubtract(Nodes[i].Location, barycenter),
2087
                                                     Nodes[i].GetMovement));
2088
   end;
2089

2090
   nrjAdjust:=NullVector;
2091
   for i:=0 to Nodes.Count-1 do begin
2092
      delta:=VectorCombine3(natural[0], natural[1], natural[2],
2093
                            FNodeCoords[i].V[0], FNodeCoords[i].V[1], FNodeCoords[i].V[2]);
2094
      deltas[i]:=VectorSubtract(VectorAdd(barycenter, delta), Nodes[i].Location);
2095
      nrjAdjust:=VectorAdd(nrjBase, VectorCrossProduct(VectorSubtract(Nodes[i].Location, barycenter),
2096
                                                       deltas[i]));
2097
      Nodes[i].Location:=VectorAdd(Nodes[i].Location, deltas[i]);
2098
      Nodes[i].FOldLocation:=VectorAdd(Nodes[i].FOldLocation, deltas[i]);
2099
//      Nodes[i].FOldLocation:=Nodes[i].Location;
2100
   end;
2101

2102
   deltas[0]:=nrjBase;
2103
   deltas[1]:=nrjAdjust;
2104
end;
2105

2106
// ------------------
2107
// ------------------ TVCSlider ------------------
2108
// ------------------
2109

2110
// SetSlideDirection
2111
//
2112
procedure TVCSlider.SetSlideDirection(const value : TAffineVector);
2113
begin
2114
   FSlideDirection:=VectorNormalize(value);
2115
end;
2116

2117
// SatisfyConstraint
2118
//
2119
procedure TVCSlider.SatisfyConstraint(const iteration, maxIterations : Integer);
2120
var
2121
   delta : TAffineVector;
2122
   f, r : Single;
2123
   projB : TAffineVector;
2124
begin
2125
   Assert((NodeA<>NodeB), 'The nodes are identical - that causes division by zero!');
2126

2127
   // project B in the plane defined by A and SlideDirection
2128
   projB:=VectorSubtract(NodeB.Location, NodeA.Location);
2129
   f:=VectorDotProduct(projB, SlideDirection);
2130
   projB:=VectorCombine(NodeB.Location, SlideDirection, 1, -f);
2131
   if Constrained and (f<0) then
2132
      NodeB.Location:=projB;
2133

2134
   VectorSubtract(projB, NodeA.Location, delta);
2135

2136
   // Take into acount the different weights of the nodes!
2137
   r:=1/(NodeA.InvWeight+NodeB.InvWeight);
2138

2139
   if not NodeA.NailedDown then begin
2140
      f:=r*NodeA.InvWeight;
2141
      CombineVector(NodeA.FLocation, delta, f);
2142
      NodeA.FChangedOnStep:=Owner.CurrentStepCount;
2143
   end;
2144
   if not NodeB.NailedDown then begin
2145
      f:=-r*NodeB.InvWeight;
2146
      CombineVector(NodeB.FLocation, delta, f);
2147
      NodeB.FChangedOnStep:=Owner.CurrentStepCount;
2148
   end;
2149
end;
2150

2151
// ------------------
2152
// ------------------ TVCSphere ------------------
2153
// ------------------
2154

2155

2156
// SatisfyConstraintForEdge
2157
//
2158
function TVCSphere.GetBSphere: TBSphere;
2159
begin
2160
  result.Center := FLocation;
2161
  result.Radius := FRadius;
2162
end;
2163

2164
procedure TVCSphere.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
2165
  const iteration, maxIterations: Integer);
2166
var
2167
  closestPoint, move, delta, contactNormal : TAffineVector;
2168
  deltaLength, diff : Single;
2169
begin
2170
  // If the edge penetrates the sphere, try pushing the nodes until it no
2171
  // longer does
2172
  closestPoint := PointSegmentClosestPoint(FLocation, aEdge.NodeA.FLocation, aEdge.NodeB.FLocation);
2173

2174
  // Find the distance between the two
2175
  VectorSubtract(closestPoint, Location, delta);
2176

2177
  deltaLength := VectorLength(delta);
2178

2179
  if deltaLength<Radius then  begin
2180
      if deltaLength>0 then begin
2181
         contactNormal := VectorScale(delta, 1/deltaLength);
2182
         aEdge.NodeA.ApplyFriction(FFrictionRatio, Radius-Abs(DeltaLength), contactNormal);
2183
         aEdge.NodeB.ApplyFriction(FFrictionRatio, Radius-Abs(DeltaLength), contactNormal);
2184
      end;
2185

2186
      // Move it outside the sphere!
2187
      diff:=(Radius-deltaLength)/deltaLength;
2188
      VectorScale(delta, diff, move);
2189

2190
      AddVector(aEdge.NodeA.FLocation, move);
2191
      AddVector(aEdge.NodeB.FLocation, move);
2192

2193
      // Add the force to the kickback
2194
      // F = a * m
2195
      // a = move / deltatime
2196
      AddKickbackForceAt(
2197
        FLocation,
2198
        VectorScale(move, -(aEdge.NodeA.FWeight + aEdge.NodeB.FWeight)  * Owner.FInvCurrentDeltaTime));
2199

2200
      aEdge.NodeA.FChangedOnStep := Owner.CurrentStepCount;
2201
      aEdge.NodeB.FChangedOnStep := Owner.CurrentStepCount;
2202
  end;
2203
end;
2204

2205
// SatisfyConstraintForNode
2206
//
2207
procedure TVCSphere.SatisfyConstraintForNode(const aNode : TVerletNode;
2208
  const iteration, maxIterations : Integer);
2209
var
2210
   delta, move, contactNormal : TAffineVector;
2211
   deltaLength, diff : Single;
2212
begin
2213
   // Find the distance between the two
2214
   VectorSubtract(aNode.Location, Location, delta);
2215

2216
   // Is it inside the sphere?
2217
   deltaLength:=VectorLength(delta)-aNode.Radius;
2218
   if Abs(deltaLength)<Radius then begin
2219
      if deltaLength>0 then begin
2220
         contactNormal := VectorScale(delta, 1/deltaLength);
2221
         aNode.ApplyFriction(FFrictionRatio, Radius-Abs(DeltaLength), contactNormal);
2222
      end
2223
      else
2224
        // Slow it down - this part should not be fired
2225
        aNode.OldApplyFriction(FFrictionRatio, Radius-Abs(DeltaLength));
2226

2227
      // Move it outside the sphere!
2228
      diff:=(Radius-deltaLength)/deltaLength;
2229
      VectorScale(delta, diff, move);
2230

2231
      AddVector(aNode.FLocation, move);
2232
      aNode.FChangedOnStep := Owner.CurrentStepCount;
2233

2234
      // Add the force to the kickback
2235
      // F = a * m
2236
      // a = move / deltatime
2237
      AddKickbackForceAt(
2238
        FLocation,
2239
        VectorScale(move, -aNode.FWeight * Owner.FInvCurrentDeltaTime));
2240
   end;
2241
end;
2242

2243
// ------------------
2244
// ------------------ TVCCylinder ------------------
2245
// ------------------
2246

2247
// SetRadius
2248
//
2249
procedure TVCCylinder.SetRadius(const val : Single);
2250
begin
2251
   FRadius:=val;
2252
   FRadius2:=Sqr(val);
2253
end;
2254

2255
// SatisfyConstraintForNode
2256
//
2257
procedure TVCCylinder.SatisfyConstraintForNode(const aNode : TVerletNode;
2258
                                    const iteration, maxIterations : Integer);
2259
var
2260
   proj, newLocation, move : TAffineVector;
2261
   f, dist2, penetrationDepth : Single;
2262
begin
2263
   // Compute projection of node position on the axis
2264
   f:=PointProject(aNode.Location, FLocation, FAxis);
2265
   proj:=VectorCombine(FLocation, FAxis, 1, f);
2266

2267
   // Sqr distance
2268
   dist2:=VectorDistance2(proj, aNode.Location);
2269
   if dist2<FRadius2 then begin
2270
      // move out of the cylinder
2271
      VectorLerp(proj, aNode.Location, FRadius*RSqrt(dist2), newLocation);
2272

2273
      move := VectorSubtract(aNode.FLocation, newLocation);
2274

2275
      penetrationDepth := VectorLength(Move);
2276

2277
      aNode.ApplyFriction(FFrictionRatio, penetrationDepth, VectorScale(move, 1/penetrationDepth));
2278

2279
      aNode.FLocation := newLocation;
2280
      aNode.FChangedOnStep := Owner.CurrentStepCount;
2281
   end;
2282
end;
2283

2284
// ------------------
2285
// ------------------ TVCCube ------------------
2286
// ------------------
2287

2288
function TVCCube.GetAABB:TAABB;
2289
begin
2290
  VectorAdd(FLocation, FHalfSides, result.max);
2291
  VectorSubtract(FLocation, FHalfSides, result.min);
2292
end;
2293

2294
// BROKEN AND VERY SLOW!
2295
procedure TVCCube.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
2296
  const iteration, maxIterations: Integer);
2297
var
2298
  Corners : array[0..7] of TAffineVector;
2299
  EdgeRelative : array[0..1] of TAffineVector;
2300

2301
  shortestMove{, contactNormal} : TAffineVector;
2302
  shortestDeltaLength : Single;
2303

2304
  procedure AddCorner(CornerID : Integer; x,y,z : Single);
2305
  begin
2306
    x := (x-0.5)*2;
2307
    y := (y-0.5)*2;
2308
    z := (z-0.5)*2;
2309
    MakeVector(Corners[CornerID], FHalfSides.V[0]*x, FHalfSides.V[1]*y, FHalfSides.V[2]*z);
2310
    AddVector(Corners[CornerID], FLocation);
2311
  end;
2312

2313
  procedure TryEdge(Corner0, Corner1 : Integer);
2314
  var
2315
    CubeEdgeClosest, aEdgeClosest : TAffineVector;
2316
    CenteraEdge, move : TAffineVector;
2317
    deltaLength : Single;
2318
  begin
2319
    SegmentSegmentClosestPoint(
2320
      Corners[Corner0],
2321
      Corners[Corner1],
2322
      aEdge.NodeA.FLocation,
2323
      aEdge.NodeB.FLocation,
2324
      CubeEdgeClosest,
2325
      aEdgeClosest);
2326

2327
    CenteraEdge := VectorSubtract(aEdgeClosest, FLocation);
2328

2329
    if (abs(CenteraEdge.V[0])<FHalfSides.V[0]) and
2330
       (abs(CenteraEdge.V[1])<FHalfSides.V[1]) and
2331
       (abs(CenteraEdge.V[2])<FHalfSides.V[2]) then
2332
    begin
2333
      // The distance to move the edge is the difference between CenterCubeEdge and
2334
      // CenteraEdge
2335
      move := VectorSubtract(CubeEdgeClosest, aEdgeClosest);
2336

2337
      deltaLength := VectorLength(move);
2338

2339
      if (deltaLength>0) and (deltaLength<shortestDeltaLength) then
2340
      begin
2341
        shortestDeltaLength := deltaLength;
2342
        shortestMove := move;
2343
      end;
2344
    end;
2345
  end;
2346
begin
2347
  // DISABLED!
2348
  exit;
2349

2350
  // Early out test
2351
  EdgeRelative[0] := VectorSubtract(aEdge.FNodeA.FLocation, FLocation);
2352
  EdgeRelative[1] := VectorSubtract(aEdge.FNodeB.FLocation, FLocation);
2353

2354
  // If both edges are on the same side of _any_ box side, the edge can't
2355
  // cut the box
2356
  if ((EdgeRelative[0].V[0]> FHalfSides.V[0]) and (EdgeRelative[1].V[0] >FHalfSides.V[0])) or
2357
     ((EdgeRelative[0].V[0]<-FHalfSides.V[0]) and (EdgeRelative[1].V[0]<-FHalfSides.V[0])) or
2358

2359
     ((EdgeRelative[0].V[1]> FHalfSides.V[1]) and (EdgeRelative[1].V[1]> FHalfSides.V[1])) or
2360
     ((EdgeRelative[0].V[1]<-FHalfSides.V[1]) and (EdgeRelative[1].V[1]<-FHalfSides.V[1])) or
2361

2362
     ((EdgeRelative[0].V[2]> FHalfSides.V[2]) and (EdgeRelative[1].V[2]> FHalfSides.V[2])) or
2363
     ((EdgeRelative[0].V[2]<-FHalfSides.V[2]) and (EdgeRelative[1].V[2]<-FHalfSides.V[2])) then
2364
  begin
2365
    exit;
2366
  end;
2367

2368
  // For each cube edge:
2369
  //   find closest positions between CubeEdge and aEdge
2370
  //   if aEdgeClosestPosition within cube then
2371
  //     move nodes until closest position is outside cube
2372
  //     exit
2373
  AddCorner(0, 0, 0, 0);
2374
  AddCorner(1, 1, 0, 0);
2375
  AddCorner(2, 1, 1, 0);
2376
  AddCorner(3, 0, 1, 0);
2377

2378
  AddCorner(4, 0, 0, 1);
2379
  AddCorner(5, 1, 0, 1);
2380
  AddCorner(6, 1, 1, 1);
2381
  AddCorner(7, 0, 1, 1);
2382

2383
  shortestDeltaLength := 10e30;
2384

2385
  TryEdge(0,1);
2386
  TryEdge(1,2);
2387
  TryEdge(2,3);
2388
  TryEdge(3,0);
2389

2390
  TryEdge(4,5);
2391
  TryEdge(5,6);
2392
  TryEdge(6,7);
2393
  TryEdge(7,4);
2394

2395
  TryEdge(0,3);
2396
  TryEdge(1,5);
2397
  TryEdge(2,6);
2398
  TryEdge(3,7);
2399

2400
  if shortestDeltaLength<10e8 then
2401
  begin
2402
     //contactNormal := VectorScale(shortestMove, 1/shortestDeltaLength);
2403

2404
     {aEdge.NodeA.ApplyFriction(FFrictionRatio, shortestDeltaLength, contactNormal);
2405
     aEdge.NodeB.ApplyFriction(FFrictionRatio, shortestDeltaLength, contactNormal);//}
2406

2407
     AddVector(aEdge.NodeA.FLocation, shortestMove);
2408
     AddVector(aEdge.NodeB.FLocation, shortestMove);//}
2409

2410
     aEdge.NodeA.Changed;
2411
     aEdge.NodeB.Changed;
2412

2413
     aEdge.NodeA.FChangedOnStep := Owner.CurrentStepCount;
2414
     aEdge.NodeB.FChangedOnStep := Owner.CurrentStepCount;
2415
  end;
2416
end;//*)
2417

2418
procedure TVCCube.SatisfyConstraintForNode(const aNode: TVerletNode;
2419
  const iteration, maxIterations: Integer);
2420
var
2421
   p, absP, contactNormal : TAffineVector;
2422
   dp : Single;
2423
   smallestSide : Integer;
2424
begin
2425
   // TODO: Direction of Cube should be used to rotate the nodes location, as it
2426
   // stands, the cube can only face in one direction.
2427

2428
   p:=VectorSubtract(aNode.FLocation, FLocation);
2429

2430
   absP.V[0]:=FHalfSides.V[0]-Abs(p.V[0]);
2431
   absP.V[1]:=FHalfSides.V[1]-Abs(p.V[1]);
2432
   absP.V[2]:=FHalfSides.V[2]-Abs(p.V[2]);
2433

2434
   if (PInteger(@absP.V[0])^<=0) or (PInteger(@absP.V[1])^<=0) or(PInteger(@absP.V[2])^<=0) then
2435
      Exit;
2436

2437
   if absP.V[0]<absP.V[1] then
2438
      if absP.V[0]<absP.V[2] then
2439
         smallestSide:=0
2440
      else smallestSide:=2
2441
   else if absP.V[1]<absP.V[2] then
2442
      smallestSide:=1
2443
   else smallestSide:=2;
2444

2445
   contactNormal:=NullVector;
2446

2447
   // Only move along the "shortest" axis
2448
   if PInteger(@p.V[smallestSide])^>=0 then begin
2449
      dp:=absP.V[smallestSide];
2450
      contactNormal.V[smallestSide]:=1;
2451
      aNode.ApplyFriction(FFrictionRatio, dp, contactNormal);
2452
      aNode.FLocation.V[smallestSide]:=aNode.FLocation.V[smallestSide]+dp;
2453
   end else begin
2454
      dp:=absP.V[smallestSide];
2455
      contactNormal.V[smallestSide]:=-1;
2456
      aNode.ApplyFriction(FFrictionRatio, dp, contactNormal);
2457
      aNode.FLocation.V[smallestSide]:=aNode.FLocation.V[smallestSide]-dp;
2458
   end;
2459

2460
   aNode.FChangedOnStep:=Owner.CurrentStepCount;
2461
end;
2462

2463
procedure TVCCube.SetSides(const Value: TAffineVector);
2464
begin
2465
  FSides := Value;
2466
  FHalfSides := VectorScale(Sides, 0.5);
2467
  UpdateCachedAABB;
2468
end;
2469

2470
// ------------------
2471
// ------------------ TVCCapsule ------------------
2472
// ------------------
2473

2474
{ TVCCapsule }
2475
// SetAxis
2476
//
2477
procedure TVCCapsule.SetAxis(const val : TAffineVector);
2478
begin
2479
   FAxis:=VectorNormalize(val);
2480
   UpdateCachedBSphere;
2481
end;
2482

2483
// SetLength
2484
//
2485
procedure TVCCapsule.SetLength(const val : Single);
2486
begin
2487
   FLength:=val;
2488
   FLengthDiv2:=val*0.5;
2489
   UpdateCachedBSphere;
2490
end;
2491

2492
// SetRadius
2493
//
2494
procedure TVCCapsule.SetRadius(const val : Single);
2495
begin
2496
   FRadius:=val;
2497
   FRadius2:=Sqr(val);
2498
   UpdateCachedBSphere;
2499
end;
2500

2501
// GetBSphere
2502
//
2503
function TVCCapsule.GetBSphere: TBSphere;
2504
begin
2505
  result.Center := FLocation;
2506
  result.Radius := Length + Radius;
2507
end;
2508

2509
// SatisfyConstraintForNode
2510
//
2511
procedure TVCCapsule.SatisfyConstraintForNode(const aNode : TVerletNode;
2512
                                              const iteration, maxIterations : Integer);
2513
var
2514
   p, n2, penetrationDepth  : Single;
2515
   closest, v : TAffineVector;
2516
   newLocation, move : TAffineVector;
2517

2518
begin
2519
   // Find the closest point to location on the capsule axis
2520
   p:=ClampValue(PointProject(aNode.Location, FLocation, FAxis),
2521
                 -FLengthDiv2, FLengthDiv2);
2522
   closest:=VectorCombine(FLocation, FAxis, 1, p);
2523

2524
   // vector from closest to location
2525
   VectorSubtract(aNode.Location, closest, v);
2526

2527
   // should it be altered?
2528
   n2:=VectorNorm(v);
2529

2530
   if n2<FRadius2 then
2531
   begin
2532
      newLocation := VectorCombine(closest, v, 1, Sqrt(FRadius2/n2));
2533

2534
      // Do friction calculations
2535
      move := VectorSubtract(newLocation,aNode.FLocation);
2536
      penetrationDepth := VectorLength(move);
2537

2538
      //aNode.OldApplyFriction(FFrictionRatio, penetrationDepth);
2539
      aNode.ApplyFriction(FFrictionRatio, penetrationDepth, VectorScale(move, 1/penetrationDepth));
2540

2541
      aNode.FLocation:=newLocation;
2542
      aNode.FChangedOnStep := Owner.CurrentStepCount;
2543

2544
      AddKickbackForceAt(
2545
        FLocation,
2546
        VectorScale(move, -aNode.FWeight * Owner.FInvCurrentDeltaTime));
2547
   end;
2548
end;
2549

2550

2551
procedure TVCCapsule.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
2552
  const iteration, maxIterations: Integer);
2553
var
2554
   sphereLocation, closestPoint, dummy, delta, move, contactNormal : TAffineVector;
2555
   Ax0, Ax1 : TAffineVector;
2556
   deltaLength, diff, penetrationDepth : Single;
2557
begin
2558
  VectorScale(FAxis, FLengthDiv2, Ax0);
2559
  AddVector(Ax0, FLocation);
2560
  VectorScale(FAxis, -FLengthDiv2, Ax1);
2561
  AddVector(Ax1, FLocation);
2562

2563
   SegmentSegmentClosestPoint(
2564
    aEdge.NodeA.FLocation,
2565
    aEdge.NodeB.FLocation,
2566
    Ax0,
2567
    Ax1,
2568
    dummy,
2569
    sphereLocation);
2570

2571
  // If the edge penetrates the sphere, try pushing the nodes until it no
2572
  // longer does
2573
  closestPoint := PointSegmentClosestPoint(sphereLocation, aEdge.NodeA.FLocation, aEdge.NodeB.FLocation);
2574

2575
  // Find the distance between the two
2576
  VectorSubtract(closestPoint, sphereLocation, delta);
2577

2578
  deltaLength := VectorLength(delta);
2579

2580
  if deltaLength<Radius then  begin
2581
      // Move it outside the sphere!
2582
      diff:=(Radius-deltaLength)/deltaLength;
2583
      VectorScale(delta, diff, move);
2584

2585
      penetrationDepth := VectorLength(move);
2586
      contactNormal := VectorScale(move, 1/penetrationDepth);
2587
      aEdge.NodeA.ApplyFriction(FFrictionRatio, penetrationDepth, contactNormal);
2588
      aEdge.NodeB.ApplyFriction(FFrictionRatio, penetrationDepth, contactNormal);
2589

2590
      AddVector(aEdge.NodeA.FLocation, move);
2591
      AddVector(aEdge.NodeB.FLocation, move);
2592

2593
      aEdge.NodeA.FChangedOnStep := Owner.CurrentStepCount;
2594
      aEdge.NodeB.FChangedOnStep := Owner.CurrentStepCount;
2595

2596
      AddKickbackForceAt(
2597
        FLocation,
2598
        VectorScale(move, -(aEdge.NodeA.FWeight + aEdge.NodeB.FWeight)  * Owner.FInvCurrentDeltaTime));
2599
  end;
2600

2601
end;
2602
// ------------------
2603
// ------------------ TGLVerletEdge ------------------
2604
// ------------------
2605

2606
{ TGLVerletEdge }
2607

2608
constructor TGLVerletEdge.CreateEdgeOwned(const aNodeA, aNodeB: TVerletNode);
2609
begin
2610
  FNodeA := aNodeA;
2611
  FNodeB := aNodeB;
2612

2613
  inherited CreateOwned(aNodeA.Owner.SpacePartition);
2614
end;
2615

2616
// ------------------
2617
// ------------------ TGLVerletEdgeList ------------------
2618
// ------------------
2619

2620
procedure TGLVerletEdge.UpdateCachedAABBAndBSphere;
2621
begin
2622
  FCachedAABB.min := FNodeA.FLocation;
2623
  FCachedAABB.max := FNodeA.FLocation;
2624

2625
  AABBInclude(FCachedAABB, FNodeB.FLocation);
2626

2627
  AABBToBSphere(FCachedAABB, FCachedBSphere);
2628
end;
2629

2630
{ TGLVerletEdgeList }
2631

2632
function TGLVerletEdgeList.GetItems(i: Integer): TGLVerletEdge;
2633
begin
2634
  result := Get(i);
2635
end;
2636

2637
procedure TGLVerletEdgeList.SetItems(i: Integer; const Value: TGLVerletEdge);
2638
begin
2639
  put(i, Value);
2640
end;
2641

2642
procedure TVerletNode.UpdateCachedAABBAndBSphere;
2643
begin
2644
  FCachedAABB.min := FLocation;
2645
  FCachedAABB.max := FLocation;
2646
  FCachedBSphere.Center := FLocation;
2647
  FCachedBSphere.Radius := 0;
2648
end;
2649

2650
procedure TVerletNode.SetLocation(const Value: TAffineVector);
2651
begin
2652
  FLocation := Value;
2653
  FChangedOnStep := Owner.CurrentStepCount;
2654
end;
2655

2656
procedure TGLVerletWorld.CreateOctree(const OctreeMin,
2657
  OctreeMax: TAffineVector; const LeafThreshold, MaxTreeDepth: Integer);
2658
var
2659
  Octree : TOctreeSpacePartition;
2660
begin
2661
  Assert(FNodes.Count=0,'You can only create an octree while the world is empty!');
2662

2663
  FreeAndNil(FSpacePartition);
2664

2665
  Octree := TOctreeSpacePartition.Create;
2666

2667
  Octree.SetSize(OctreeMin, OctreeMax);
2668
  Octree.MaxTreeDepth := MaxTreeDepth;
2669
  Octree.LeafThreshold := LeafThreshold;
2670
  Octree.CullingMode := cmGrossCulling;
2671

2672
  FSpacePartition := Octree;
2673

2674
  if FUpdateSpacePartion = uspNever then
2675
    FUpdateSpacePartion := uspEveryFrame;
2676
end;
2677

2678
procedure TGLVerletWorld.PauseInertia(const IterationSteps: Integer);
2679
begin
2680
  FInertaPauseSteps := IterationSteps+1;
2681
  Inertia := false;
2682
end;
2683

2684
{ TGLVerletGlobalFrictionConstraintBox }
2685

2686
procedure TGLVerletGlobalFrictionConstraintBox.PerformSpaceQuery;
2687
begin
2688
  Owner.SpacePartition.QueryAABB(FCachedAABB);
2689
end;
2690

2691
procedure TGLVerletGlobalFrictionConstraintBox.SetLocation(
2692
  const Value: TAffineVector);
2693
begin
2694
  inherited;
2695

2696
  UpdateCachedAABB;
2697
end;
2698

2699
procedure TGLVerletGlobalFrictionConstraintBox.UpdateCachedAABB;
2700
begin
2701
  FCachedAABB := GetAABB;
2702
end;
2703

2704
{ TGLVerletGlobalFrictionConstraintSphere }
2705

2706
procedure TGLVerletGlobalFrictionConstraintSphere.PerformSpaceQuery;
2707
begin
2708
  Owner.SpacePartition.QueryBSphere(FCachedBSphere);
2709
end;
2710

2711
procedure TGLVerletGlobalFrictionConstraintSphere.SetLocation(
2712
  const Value: TAffineVector);
2713
begin
2714
  inherited;
2715
  UpdateCachedBSphere;
2716
end;
2717

2718
procedure TGLVerletGlobalFrictionConstraintSphere.UpdateCachedBSphere;
2719
begin
2720
  FCachedBSphere := GetBSphere;
2721
end;
2722

2723
constructor TGLVerletGlobalConstraint.Create(const aOwner: TGLVerletWorld);
2724
begin
2725
  inherited;
2726
  if Assigned(aOwner) then
2727
    aOwner.ConstraintsWithBeforeIterations.Add(self);
2728
end;
2729

2730
destructor TGLVerletGlobalConstraint.Destroy;
2731
begin
2732
  if Assigned(Owner) then
2733
    Owner.ConstraintsWithBeforeIterations.Remove(self);
2734

2735
  inherited;
2736
end;
2737

2738
end.
2739

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.