LZScene

Форк
0
/
GLNGDManager235.pas 
3302 строки · 103.8 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
  A Newton Game Dynamics Manager for GLScene.
6

7
  Where can I find ... ? 
8
   GLScene                                   (http://glscene.org)
9
   Newton Game Dynamics Engine               (http://newtondynamics.com)
10
   NewtonImport, a Delphi header translation (http://newtondynamics.com/forum/viewtopic.php?f=9&t=5273#p35865)
11
   
12

13
  Notes:
14
  This code is still being developed so any part of it may change at anytime.
15
  To install use the GLS_NGD?.dpk in the GLScene/Delphi? folder.
16

17
   History :  
18
   10/11/12 - PW - Added CPP compatibility: used records with arrays instead of vector arrays
19
   11/17/12 - YP - Check not nil result with GetBodyFromGLSceneObject
20
                      FreeAndNil when destroying objects
21
                      Destroy all relative joints when finalizing a behaviour to avoid random crash
22
                      Smart GetBBoxCollision
23
                      DestroyNewtonData is now common for all procedures
24
   28/06/12 - YP - Updated to newton 2.36 (no api change with 2.35)
25
   02/02/11 - FP - Read/Write to Filer update to version 1
26
                 Use RWFloat instead of RWSingle for Single for lazarus compatibility
27
   02/02/11 - FP - Add initial name for behavior
28
                 Moved two TNGDSurfacePair properties from published to public for Lazarus
29
   01/02/11 - FP - Fixed custom hinge DegToRad limit
30
                 Update newtoncreatebody API with matrix parameter (since newton 2.28)
31
                 Joint draw [parent-to-pivot-to-child] instead of [parent-to-child]
32
   21/01/11 - FP - Huge update: Joint in manager collection. Material (now surface) in manager collection
33
                  Callback as static class function now raise events
34
                  Debugs view use TGLLines instead of TGLRenderPoint
35
                  Reset filer version to zero
36
   16/12/10 - FP - Update to NewtonSDK 2.25-2.26
37
   19/11/10 - FP - Fixed FAngularDamping memory leak for TGLNGDDynamic
38
   19/11/10 - FP - Added UseGravity property for TGLNGDDynamic
39
   05/11/10 - FP - Removed check freeform in TGLNGDStatic.GeTree
40
                  Removed FCollisionArray from TGLNGDBehaviour
41
                  Modified misspelling usevelovity to usevelocity [thx bobrob69]
42
                  Moved Creation of compound collision for freeform from GetCollisionFromBaseSceneObject to SetCollision for TGLNGDDynamic [thx bobrob69]
43
   25/10/10 - FP - Fixed Material badly loaded when created in design time
44
   25/10/10 - FP - Commented 'Release each collision form the array' in TGLNGDBehaviour.SetCollision.
45
                  Changed angular friction in  TGLNGDDynamic.Pick method to be able to pick body with small mass.
46
                  Added Beta Serialize and Deserialise for TGLNGDBehaviour.
47
                  Commented 'rebuild in runtime' in TGLNGDStatic.Render, because this is conflicting with news serialize methods
48
   23/10/10 - Yar - Replace OpenGL1x to OpenGLAdapter
49
   08/10/10 - FP - Added show contact for dynamic in render.
50
                 Uncommented ShowContact property in manager.
51
   07/10/10 - FP - Joints connected to TGLNGDBehaviour are now freed in TGLNGDBehaviour.Destroy
52
   30/09/10 - FP - Removed beta functions of player and car in TGLNGDDynamic.
53
                 Added AddImpulse function in TGLNGDDynamic.
54
   29/09/10 - FP - Moved FManager assignation for MaterialPair from loaded to create
55
   21/09/10 - FP - Added timestep in TContactProcessEvent.
56
                  Removed Manager property of MaterialPair.
57
                  MaterialPair.loaded use the owner.owner component as manager now.
58
                  MaterialPair FilerVersion up to 1
59
   20/09/10 - FP - Call Finalize/Initialize in Setid
60
   20/09/10 - YP - Moved MaterialAutoCreateGroupID call into Material.Initialize
61
   19/09/10 - YP - Added MaterialAutoCreateGroupID to fix loaded order
62
   18/09/10 - YP - Added Get and GetOrCreate NGD behaviors routine
63
   15/07/10 - FP - Creation by Franck Papouin
64
   
65
}
66

67
unit GLNGDManager;
68

69
interface
70

71
{$I GLScene.inc}
72

73
uses
74
  Classes, // TComponent Tlist TWriter TReader TPersistent
75
  SysUtils, //System utilities
76
  Math, // Samevalue isZero to compare single
77
  NewtonImport, NewtonImport_JointLibrary, // Newton
78
  GLVectorGeometry, // PVector TVector TMatrix PMatrix NullHmgVector...
79
  GLVectorLists, // TaffineVectorList for Tree
80
  GLXCollection,   TGLXCollection file function
81
  GLBaseClasses, GLScene, GLManager, GLCrossPlatform, GLCoordinates, //
82
  GLObjects, GLGeomObjects, GLVectorFileObjects, // cube cone freeform...
83
  GLColor, GLGeometryBB; // For show debug
84

85
type
86

87
  NGDFloat = NewtonImport.Float;
88
  PNGDFloat = ^NGDFloat;
89

90
  { Record }
91
  THeightField = record
92
    heightArray: array of Word;
93
    width: Integer;
94
    depth: Integer;
95
    gridDiagonals: Boolean;
96
    widthDepthScale: Single;
97
    heightScale: Single;
98
  end;
99

100
  { Class }
101
  TGLNGDBehaviour = class;
102
  TGLNGDManager = class;
103
  TNGDSurfaceItem = class;
104
  TNGDJoint = class;
105

106
  { Enums }
107
  TNGDSolverModels = (smExact = 0, smLinear1, smLinear2, smLinear3, smLinear4,
108
    smLinear5, smLinear6, smLinear7, smLinear8, smLinear9);
109

110
  TNGDFrictionModels = (fmExact = 0, fmAdaptive);
111
  TNGDPickedActions = (paAttach = 0, paMove, paDetach);
112

113
  TNGDManagerDebug = (mdShowGeometry, mdShowAABB, mdShowCenterOfMass,
114
    mdShowContact, mdShowJoint, mdShowForce, mdShowAppliedForce,
115
    mdShowAppliedVelocity);
116
  TNGDManagerDebugs = set of TNGDManagerDebug;
117

118
  TNGDNewtonCollisions = (nc_Primitive = 0, nc_Convex, nc_BBox, nc_BSphere,
119
    nc_Tree, nc_Mesh, nc_Null, nc_HeightField, nc_NGDFile);
120

121
  TNGDNewtonJoints = (nj_BallAndSocket, nj_Hinge, nj_Slider, nj_Corkscrew,
122
    nj_Universal, nj_CustomBallAndSocket, nj_CustomHinge, nj_CustomSlider,
123
    nj_UpVector, nj_KinematicController);
124

125
  TGLNGDBehaviourList = class(TList)
126
  protected
127
    function GetBehav(index: Integer): TGLNGDBehaviour;
128
    procedure PutBehav(index: Integer; Item: TGLNGDBehaviour);
129
  public
130
    property ItemsBehav[index: Integer]
131
      : TGLNGDBehaviour read GetBehav write PutBehav; default;
132
  end;
133

134
  { Events for Newton Callback }
135

136
  TCollisionIteratorEvent = procedure(const userData: Pointer;
137
    vertexCount: Integer; const cfaceArray: PNGDFloat;
138
    faceId: Integer) of object;
139

140
  TApplyForceAndTorqueEvent = procedure(const cbody: PNewtonBody;
141
    timestep: NGDFloat; threadIndex: Integer) of object;
142

143
  TSetTransformEvent = procedure(const cbody: PNewtonBody;
144
    const cmatrix: PNGDFloat; threadIndex: Integer) of object;
145

146
  TSerializeEvent = procedure(serializeHandle: Pointer; const cbuffer: Pointer;
147
    size: Cardinal) of object;
148

149
  TDeSerializeEvent = procedure(serializeHandle: Pointer; buffer: Pointer;
150
    size: Cardinal) of object;
151

152
  TAABBOverlapEvent = function(const cmaterial: PNewtonMaterial;
153
    const cbody0: PNewtonBody; const cbody1: PNewtonBody;
154
    threadIndex: Integer): Boolean of object;
155

156
  TContactProcessEvent = procedure(const ccontact: PNewtonJoint;
157
    timestep: NGDFloat; threadIndex: Integer) of object;
158

159
  { Class }
160

161
  TNGDDebugOption = class(TPersistent)
162
  strict private
163
    FManager: TGLNGDManager;
164
    FGeomColorDyn: TGLColor; // Green
165
    FGeomColorStat: TGLColor; // Red
166
    FAABBColor: TGLColor; // Yellow
167
    FAABBColorSleep: TGLColor; // Orange
168
    FCenterOfMassColor: TGLColor; // Purple dot
169
    FContactColor: TGLColor; // White
170
    FJointAxisColor: TGLColor; // Blue
171
    FJointPivotColor: TGLColor; // Aquamarine
172
    FForceColor: TGLColor; // Black
173
    FAppliedForceColor: TGLColor; // Silver
174
    FAppliedVelocityColor: TGLColor; // Lime
175
    FCustomColor: TGLColor; // Aqua
176
    FDotAxisSize: Single; // 1
177
    FNGDManagerDebugs: TNGDManagerDebugs; // Default All false
178
    procedure SetNGDManagerDebugs(const Value: TNGDManagerDebugs);
179
    procedure SetDotAxisSize(const Value: Single);
180
    function StoredDotAxis: Boolean;
181

182
  public
183
    constructor Create(AOwner: TComponent);
184
    destructor Destroy; override;
185

186
  published
187
    property GeomColorDyn: TGLColor read FGeomColorDyn write FGeomColorDyn;
188
    property GeomColorStat: TGLColor read FGeomColorStat write FGeomColorStat;
189
    property AABBColor: TGLColor read FAABBColor write FAABBColor;
190
    property AABBColorSleep
191
      : TGLColor read FAABBColorSleep write FAABBColorSleep;
192
    property CenterOfMassColor
193
      : TGLColor read FCenterOfMassColor write FCenterOfMassColor;
194
    property ContactColor: TGLColor read FContactColor write FContactColor;
195
    property JointAxisColor
196
      : TGLColor read FJointAxisColor write FJointAxisColor;
197
    property JointPivotColor
198
      : TGLColor read FJointPivotColor write FJointPivotColor;
199
    property ForceColor: TGLColor read FForceColor write FForceColor;
200
    property AppliedForceColor
201
      : TGLColor read FAppliedForceColor write FAppliedForceColor;
202
    property AppliedVelocityColor
203
      : TGLColor read FAppliedVelocityColor write FAppliedVelocityColor;
204
    property CustomColor: TGLColor read FCustomColor write FCustomColor;
205
    property NGDManagerDebugs: TNGDManagerDebugs read FNGDManagerDebugs write
206
      SetNGDManagerDebugs default[];
207
    property DotAxisSize: Single read FDotAxisSize write SetDotAxisSize stored
208
      StoredDotAxis;
209
  end;
210

211
  TGLNGDManager = class(TComponent)
212

213
  strict private
214
     
215
    FVisible: Boolean; // Show Debug at design time
216
    FVisibleAtRunTime: Boolean; // Show Debug at run time
217
    FDllVersion: Integer;
218
    FSolverModel: TNGDSolverModels; // Default=Exact
219
    FFrictionModel: TNGDFrictionModels; // Default=Exact
220
    FMinimumFrameRate: Integer; // Default=60
221
    FWorldSizeMin: TGLCoordinates; // Default=-100, -100, -100
222
    FWorldSizeMax: TGLCoordinates; // Default=100, 100, 100
223
    FThreadCount: Integer; // Default=1
224
    FGravity: TGLCoordinates; // Default=(0,-9.81,0)
225
    FNewtonSurfaceItem: TCollection;
226
    FNewtonSurfacePair: TOwnedCollection;
227
    FNewtonJointGroup: TOwnedCollection;
228
    FNGDDebugOption: TNGDDebugOption;
229
    FGLLines: TGLLines;
230

231
  private
232
    FNewtonWorld: PNewtonWorld;
233
    FNGDBehaviours: TGLNGDBehaviourList;
234
    FCurrentColor: TGLColor;
235
  protected
236
    procedure Loaded; override;
237
    procedure SetVisible(const Value: Boolean);
238
    procedure SetVisibleAtRunTime(const Value: Boolean);
239
    procedure SetSolverModel(const Value: TNGDSolverModels);
240
    procedure SetFrictionModel(const Value: TNGDFrictionModels);
241
    procedure SetMinimumFrameRate(const Value: Integer);
242
    procedure SetThreadCount(const Value: Integer);
243
    procedure SetGLLines(const Value: TGLLines);
244
    function GetBodyCount: Integer;
245
    function GetConstraintCount: Integer;
246
    procedure AddNode(const coords: TGLCustomCoordinates); overload;
247
    procedure AddNode(const X, Y, Z: Single); overload;
248
    procedure AddNode(const Value: TVector); overload;
249
    procedure AddNode(const Value: TAffineVector); overload;
250
    procedure RebuildAllMaterial;
251
    procedure RebuildAllJoint(Sender: TObject);
252

253
    // Events
254
    procedure NotifyWorldSizeChange(Sender: TObject);
255
    procedure NotifyChange(Sender: TObject); // Debug view
256

257
  public
258
     
259
    constructor Create(AOwner: TComponent); override;
260
    destructor Destroy; override;
261
    procedure Step(deltatime: Single);
262

263
  published
264
     
265

266
    property Visible: Boolean read FVisible write SetVisible default True;
267
    property VisibleAtRunTime: Boolean read FVisibleAtRunTime write
268
      SetVisibleAtRunTime default False;
269
    property SolverModel: TNGDSolverModels read FSolverModel write
270
      SetSolverModel default smExact;
271
    property FrictionModel: TNGDFrictionModels read FFrictionModel write
272
      SetFrictionModel default fmExact;
273
    property MinimumFrameRate: Integer read FMinimumFrameRate write
274
      SetMinimumFrameRate default 60;
275
    property ThreadCount
276
      : Integer read FThreadCount write SetThreadCount default 1;
277
    property DllVersion: Integer read FDllVersion;
278
    property NewtonBodyCount: Integer read GetBodyCount;
279
    property NewtonConstraintCount: Integer read GetConstraintCount;
280
    property Gravity: TGLCoordinates read FGravity write FGravity;
281
    property WorldSizeMin
282
      : TGLCoordinates read FWorldSizeMin write FWorldSizeMin;
283
    property WorldSizeMax
284
      : TGLCoordinates read FWorldSizeMax write FWorldSizeMax;
285
    property NewtonSurfaceItem
286
      : TCollection read FNewtonSurfaceItem write FNewtonSurfaceItem;
287
    property NewtonSurfacePair: TOwnedCollection read FNewtonSurfacePair write
288
      FNewtonSurfacePair;
289
    property DebugOption: TNGDDebugOption read FNGDDebugOption write
290
      FNGDDebugOption;
291
    property Line: TGLLines read FGLLines write SetGLLines;
292
    property NewtonJoint: TOwnedCollection read FNewtonJointGroup write
293
      FNewtonJointGroup;
294
  end;
295

296
  { Basis structures for GLScene behaviour style implementations. }
297
  TGLNGDBehaviour = class(TGLBehaviour)
298
  private
299
    { Private Declartions }
300
    FManager: TGLNGDManager;
301
    FManagerName: string;
302
    FInitialized: Boolean;
303
    FNewtonBody: PNewtonBody;
304
    FCollision: PNewtonCollision;
305
    FNewtonBodyMatrix: TMatrix; // Position and Orientation
306
    FContinuousCollisionMode: Boolean; // Default=False
307
    FNGDNewtonCollisions: TNGDNewtonCollisions;
308
    FCollisionIteratorEvent: TCollisionIteratorEvent;
309
    FOwnerBaseSceneObject: TGLBaseSceneObject;
310
    // FNullCollisionMass: Single; // Default=0
311
    FTreeCollisionOptimize: Boolean; // Default=True
312
    FConvexCollisionTolerance: Single; // Default=0.01 1%
313
    FFileCollision: string;
314
    FNGDSurfaceItem: TNGDSurfaceItem;
315
    FHeightFieldOptions: THeightField;
316
  protected
317
     
318
    procedure Initialize; virtual;
319
    procedure Finalize; virtual;
320
    procedure WriteToFiler(writer: TWriter); override;
321
    procedure ReadFromFiler(reader: TReader); override;
322
    procedure Loaded; override;
323
    procedure SetManager(Value: TGLNGDManager);
324
    procedure SetNewtonBodyMatrix(const Value: TMatrix);
325
    procedure SetContinuousCollisionMode(const Value: Boolean);
326
    function GetNewtonBodyMatrix: TMatrix;
327
    function GetNewtonBodyAABB: TAABB;
328
    procedure UpdCollision; virtual;
329
    procedure Render; virtual;
330
    procedure SetNGDNewtonCollisions(const Value: TNGDNewtonCollisions);
331
    procedure SetNGDSurfaceItem(const Value: TNGDSurfaceItem);
332
    procedure SetHeightFieldOptions(const Value: THeightField);
333

334
    function GetPrimitiveCollision(): PNewtonCollision;
335
    function GetConvexCollision(): PNewtonCollision;
336
    function GetBBoxCollision(): PNewtonCollision;
337
    function GetBSphereCollision(): PNewtonCollision;
338
    function GetTreeCollision(): PNewtonCollision;
339
    function GetMeshCollision(): PNewtonCollision;
340
    function GetNullCollision(): PNewtonCollision;
341
    function GetHeightFieldCollision(): PNewtonCollision;
342
    function GetNGDFileCollision(): PNewtonCollision;
343
    function StoredTolerance: Boolean;
344

345
    // Event
346
    procedure OnCollisionIteratorEvent(const userData: Pointer;
347
      vertexCount: Integer; const cfaceArray: PNGDFloat; faceId: Integer);
348

349
    // CallBack
350
    class procedure NewtonCollisionIterator(const userData: Pointer;
351
      vertexCount: Integer; const faceArray: PNGDFloat;
352
      faceId: Integer); static; cdecl;
353

354
    class procedure NewtonSerialize(serializeHandle: Pointer;
355
      const buffer: Pointer; size: Cardinal); static; cdecl;
356

357
    class procedure NewtonDeserialize(serializeHandle: Pointer;
358
      buffer: Pointer; size: Cardinal); static; cdecl;
359

360
  public
361
     
362
    constructor Create(AOwner: TGLXCollection); override;
363
    destructor Destroy; override;
364
    procedure Reinitialize;
365
    property Initialized: Boolean read FInitialized;
366
    class function UniqueItem: Boolean; override;
367
    property NewtonBodyMatrix: TMatrix read GetNewtonBodyMatrix write
368
      SetNewtonBodyMatrix;
369
    property NewtonBodyAABB: TAABB read GetNewtonBodyAABB;
370
    procedure Serialize(filename: string);
371
    procedure DeSerialize(filename: string);
372
    property HeightFieldOptions: THeightField read FHeightFieldOptions write
373
      SetHeightFieldOptions;
374

375
  published
376
     
377
    property Manager: TGLNGDManager read FManager write SetManager;
378
    property ContinuousCollisionMode
379
      : Boolean read FContinuousCollisionMode write
380
      SetContinuousCollisionMode default False;
381
    property NGDNewtonCollisions
382
      : TNGDNewtonCollisions read FNGDNewtonCollisions
383
      write SetNGDNewtonCollisions default nc_Primitive;
384
    property TreeCollisionOptimize: Boolean read FTreeCollisionOptimize write
385
      FTreeCollisionOptimize default True;
386
    property ConvexCollisionTolerance
387
      : Single read FConvexCollisionTolerance write
388
      FConvexCollisionTolerance stored StoredTolerance;
389
    property FileCollision: string read FFileCollision write FFileCollision;
390
    property NGDSurfaceItem: TNGDSurfaceItem read FNGDSurfaceItem write
391
      SetNGDSurfaceItem;
392
  end;
393

394
  TGLNGDDynamic = class(TGLNGDBehaviour)
395
  strict private
396
     
397
    FAABBmin: TGLCoordinates;
398
    FAABBmax: TGLCoordinates;
399
    FForce: TGLCoordinates;
400
    FTorque: TGLCoordinates;
401
    FCenterOfMass: TGLCoordinates;
402
    FAutoSleep: Boolean; // Default=True
403
    FLinearDamping: Single; // default=0.1
404
    FAngularDamping: TGLCoordinates; // Default=0.1
405
    FDensity: Single; // Default=1
406
    FUseGravity: Boolean; // Default=True
407
    FNullCollisionVolume: Single; // Default=0
408
    FApplyForceAndTorqueEvent: TApplyForceAndTorqueEvent;
409
    FSetTransformEvent: TSetTransformEvent;
410
    FCustomForceAndTorqueEvent: TApplyForceAndTorqueEvent;
411

412
    // Read Only
413
    FVolume: Single;
414
    FMass: Single;
415
    FAppliedForce: TGLCoordinates;
416
    FAppliedTorque: TGLCoordinates;
417
    FAppliedOmega: TGLCoordinates;
418
    FAppliedVelocity: TGLCoordinates;
419

420
    function StoredDensity: Boolean;
421
    function StoredLinearDamping: Boolean;
422
    function StoredNullCollisionVolume: Boolean;
423
  protected
424
     
425
    procedure SetAutoSleep(const Value: Boolean);
426
    procedure SetLinearDamping(const Value: Single);
427
    procedure SetDensity(const Value: Single); virtual;
428
    procedure Initialize; override;
429
    procedure Finalize; override;
430
    procedure WriteToFiler(writer: TWriter); override;
431
    procedure ReadFromFiler(reader: TReader); override;
432
    procedure Loaded; override;
433
    procedure Render; override;
434

435
    // Events
436
    procedure NotifyCenterOfMassChange(Sender: TObject);
437
    procedure NotifyAngularDampingChange(Sender: TObject);
438
    procedure OnApplyForceAndTorqueEvent(const cbody: PNewtonBody;
439
      timestep: NGDFloat; threadIndex: Integer);
440
    procedure OnSetTransformEvent(const cbody: PNewtonBody;
441
      const cmatrix: PNGDFloat; threadIndex: Integer);
442

443
    // Callback
444
    class procedure NewtonApplyForceAndTorque(const body: PNewtonBody;
445
      timestep: NGDFloat; threadIndex: Integer); static; cdecl;
446
    class procedure NewtonSetTransform(const body: PNewtonBody;
447
      const matrix: PNGDFloat; threadIndex: Integer); static; cdecl;
448

449

450
  public
451
     
452
    constructor Create(AOwner: TGLXCollection); override;
453
    destructor Destroy; override;
454
    procedure AddImpulse(const veloc, pointposit: TVector);
455
    function GetOmega: TVector;
456
    procedure SetOmega(const Omega: TVector);
457
    function GetVelocity: TVector;
458
    procedure SetVelocity(const Velocity: TVector);
459
    class function FriendlyName: string; override;
460
    property CustomForceAndTorqueEvent
461
      : TApplyForceAndTorqueEvent read FCustomForceAndTorqueEvent write
462
      FCustomForceAndTorqueEvent;
463
    property Velocity: TVector read GetVelocity write SetVelocity;
464
    property Omega: TVector read GetOmega write SetOmega;
465
  published
466
     
467
    property Force: TGLCoordinates read FForce write FForce;
468
    property Torque: TGLCoordinates read FTorque write FTorque;
469
    property CenterOfMass
470
      : TGLCoordinates read FCenterOfMass write FCenterOfMass;
471
    property AutoSleep: Boolean read FAutoSleep write SetAutoSleep default True;
472
    property LinearDamping
473
      : Single read FLinearDamping write SetLinearDamping
474
      stored StoredLinearDamping;
475
    property AngularDamping
476
      : TGLCoordinates read FAngularDamping write FAngularDamping;
477
    property Density
478
      : Single read FDensity write SetDensity stored StoredDensity;
479
    property UseGravity
480
      : Boolean read FUseGravity write FUseGravity default True;
481
    property NullCollisionVolume
482
      : Single read FNullCollisionVolume write FNullCollisionVolume stored
483
      StoredNullCollisionVolume;
484

485
    // Read Only
486
    property AppliedOmega: TGLCoordinates read FAppliedOmega;
487
    property AppliedVelocity: TGLCoordinates read FAppliedVelocity;
488
    property AppliedForce: TGLCoordinates read FAppliedForce;
489
    property AppliedTorque: TGLCoordinates read FAppliedTorque;
490
    property Volume: Single read FVolume;
491
    property Mass: Single read FMass;
492
  end;
493

494
  TGLNGDStatic = class(TGLNGDBehaviour)
495
  private
496
     
497

498
  protected
499
     
500
    procedure Render; override;
501

502
  public
503
     
504
    class function FriendlyName: string; override;
505

506
  published
507
     
508
  end;
509

510
  TNGDSurfaceItem = class(TCollectionItem)
511
  private
512
    FDisplayName: string;
513
  protected
514
    function GetDisplayName: string; override;
515
    procedure SetDisplayName(const Value: string); override;
516

517
  published
518
    property DisplayName;
519
    property ID;
520
  end;
521

522
  TNGDSurfacePair = class(TCollectionItem)
523
  strict private
524
    FManager: TGLNGDManager;
525
    FNGDSurfaceItem1: TNGDSurfaceItem;
526
    FNGDSurfaceItem2: TNGDSurfaceItem;
527
    FAABBOverlapEvent: TAABBOverlapEvent;
528
    FContactProcessEvent: TContactProcessEvent;
529

530
    FSoftness: Single; // 0.1
531
    FElasticity: Single; // 0.4
532
    FCollidable: Boolean; // true
533
    FStaticFriction: Single; // 0.9
534
    FKineticFriction: Single; // 0.5
535
    FContinuousCollisionMode: Boolean; // False
536
    FThickness: Boolean; // False
537

538
    procedure SetCollidable(const Value: Boolean);
539
    procedure SetElasticity(const Value: Single);
540
    procedure SetKineticFriction(const Value: Single);
541
    procedure SetSoftness(const Value: Single);
542
    procedure SetStaticFriction(const Value: Single);
543
    procedure SetContinuousCollisionMode(const Value: Boolean);
544
    procedure SetThickness(const Value: Boolean);
545

546
    function StoredElasticity: Boolean;
547
    function StoredKineticFriction: Boolean;
548
    function StoredSoftness: Boolean;
549
    function StoredStaticFriction: Boolean;
550

551
  private
552
    // Callback
553
    class function NewtonAABBOverlap(const material: PNewtonMaterial;
554
      const body0: PNewtonBody; const body1: PNewtonBody;
555
      threadIndex: Integer): Integer; static; cdecl;
556
    class procedure NewtonContactsProcess(const contact: PNewtonJoint;
557
      timestep: NGDFloat; threadIndex: Integer); static; cdecl;
558

559
    // Event
560
    function OnNewtonAABBOverlapEvent(const cmaterial: PNewtonMaterial;
561
      const cbody0: PNewtonBody; const cbody1: PNewtonBody;
562
      threadIndex: Integer): Boolean;
563
    procedure OnNewtonContactsProcessEvent(const ccontact: PNewtonJoint;
564
      timestep: NGDFloat; threadIndex: Integer);
565

566
  public
567
    constructor Create(Collection: TCollection); override;
568
    procedure SetMaterialItems(const item1, item2: TNGDSurfaceItem);
569
    property NGDSurfaceItem1: TNGDSurfaceItem read FNGDSurfaceItem1;
570
    property NGDSurfaceItem2: TNGDSurfaceItem read FNGDSurfaceItem2;
571

572
  published
573
    property Softness: Single read FSoftness write SetSoftness stored
574
      StoredSoftness;
575
    property Elasticity: Single read FElasticity write SetElasticity stored
576
      StoredElasticity;
577
    property Collidable
578
      : Boolean read FCollidable write SetCollidable default True;
579
    property StaticFriction
580
      : Single read FStaticFriction write SetStaticFriction
581
      stored StoredStaticFriction;
582
    property KineticFriction
583
      : Single read FKineticFriction write SetKineticFriction stored
584
      StoredKineticFriction;
585
    property ContinuousCollisionMode
586
      : Boolean read FContinuousCollisionMode write
587
      SetContinuousCollisionMode default False;
588
    property Thickness
589
      : Boolean read FThickness write SetThickness default False;
590
    property ContactProcessEvent
591
      : TContactProcessEvent read FContactProcessEvent
592
      write FContactProcessEvent;
593
    property AABBOverlapEvent: TAABBOverlapEvent read FAABBOverlapEvent write
594
      FAABBOverlapEvent;
595
  end;
596

597
  TNGDJointPivot = class(TPersistent)
598
  private
599
    FManager: TGLNGDManager;
600
    FPivotPoint: TGLCoordinates;
601
    FOuter: TNGDJoint;
602
  public
603
    constructor Create(AOwner: TComponent; aOuter: TNGDJoint); virtual;
604
    destructor Destroy; override;
605
  published
606
    property PivotPoint: TGLCoordinates read FPivotPoint write FPivotPoint;
607
  end;
608

609
  TNGDJointPin = class(TNGDJointPivot)
610
  private
611
    FPinDirection: TGLCoordinates;
612

613
  public
614
    constructor Create(AOwner: TComponent; aOuter: TNGDJoint); override;
615
    destructor Destroy; override;
616

617
  published
618
    property PinDirection
619
      : TGLCoordinates read FPinDirection write FPinDirection;
620
  end;
621

622
  TNGDJointPin2 = class(TNGDJointPin)
623
  private
624
    FPinDirection2: TGLCoordinates;
625

626
  public
627
    constructor Create(AOwner: TComponent; aOuter: TNGDJoint); override;
628
    destructor Destroy; override;
629

630
  published
631
    property PinDirection2
632
      : TGLCoordinates read FPinDirection2 write FPinDirection2;
633
  end;
634

635
  TNGDJointBallAndSocket = class(TNGDJointPivot)
636
  private
637
    FConeAngle: Single; // 90
638
    FMinTwistAngle: Single; // -90
639
    FMaxTwistAngle: Single; // 90
640
    procedure SetConeAngle(const Value: Single);
641
    procedure SetMaxTwistAngle(const Value: Single);
642
    procedure SetMinTwistAngle(const Value: Single);
643
    function StoredMaxTwistAngle: Boolean;
644
    function StoredMinTwistAngle: Boolean;
645
    function StoredConeAngle: Boolean;
646

647
  public
648
    constructor Create(AOwner: TComponent; aOuter: TNGDJoint); override;
649

650
  published
651
    property ConeAngle: Single read FConeAngle write SetConeAngle stored
652
      StoredConeAngle;
653
    property MinTwistAngle
654
      : Single read FMinTwistAngle write SetMinTwistAngle
655
      stored StoredMinTwistAngle;
656
    property MaxTwistAngle
657
      : Single read FMaxTwistAngle write SetMaxTwistAngle
658
      stored StoredMaxTwistAngle;
659
  end;
660

661
  TNGDJointHinge = class(TNGDJointPin)
662
  private
663
    FMinAngle: Single; // -90
664
    FMaxAngle: Single; // 90
665
    procedure SetMaxAngle(const Value: Single);
666
    procedure SetMinAngle(const Value: Single);
667
    function StoredMaxAngle: Boolean;
668
    function StoredMinAngle: Boolean;
669

670
  public
671
    constructor Create(AOwner: TComponent; aOuter: TNGDJoint); override;
672

673
  published
674
    property MinAngle: Single read FMinAngle write SetMinAngle stored
675
      StoredMinAngle;
676
    property MaxAngle: Single read FMaxAngle write SetMaxAngle stored
677
      StoredMaxAngle;
678
  end;
679

680
  TNGDJointSlider = class(TNGDJointPin)
681
  private
682
    FMinDistance: Single; // -10
683
    FMaxDistance: Single; // 10
684
    procedure SetMaxDistance(const Value: Single);
685
    procedure SetMinDistance(const Value: Single);
686
    function StoredMaxDistance: Boolean;
687
    function StoredMinDistance: Boolean;
688

689
  public
690
    constructor Create(AOwner: TComponent; aOuter: TNGDJoint); override;
691

692
  published
693
    property MinDistance: Single read FMinDistance write SetMinDistance stored 
694
	   StoredMinDistance;
695
    property MaxDistance: Single read FMaxDistance write SetMaxDistance stored 
696
	   StoredMaxDistance;
697
  end;
698

699
  TNGDJointKinematicController = class(TPersistent)
700
  private
701
    FPickModeLinear: Boolean; // False
702
    FLinearFriction: Single; // 750
703
    FAngularFriction: Single; // 250
704
    function StoredAngularFriction: Boolean;
705
    function StoredLinearFriction: Boolean;
706

707
  public
708
    constructor Create();
709

710
  published
711
    property PickModeLinear
712
      : Boolean read FPickModeLinear write FPickModeLinear
713
      default False;
714
    property LinearFriction
715
      : Single read FLinearFriction write FLinearFriction stored
716
      StoredLinearFriction;
717
    property AngularFriction
718
      : Single read FAngularFriction write FAngularFriction stored
719
      StoredAngularFriction;
720
  end;
721

722
  TNGDJoint = class(TCollectionItem)
723

724
  private
725
    // Global
726
    FManager: TGLNGDManager;
727
    FParentObject: TGLBaseSceneObject;
728
    FJointType: TNGDNewtonJoints;
729
    FStiffness: Single; // 0.9
730

731
    // With Two object
732
    // Every joint except nj_UpVector and nj_KinematicController
733
    FChildObject: TGLBaseSceneObject;
734
    FCollisionState: Boolean; // False
735

736
    // With classic joint
737
    // nj_BallAndSocket, nj_Hinge, nj_Slider, nj_Corkscrew
738
    // nj_Universal, nj_UpVector
739
    FNewtonJoint: PNewtonJoint;
740

741
    // With CustomJoint
742
    // nj_CustomBallAndSocket, nj_CustomHinge, nj_CustomSlider
743
    // nj_KinematicController
744
    FNewtonUserJoint: PNewtonUserJoint;
745

746
    // nj_UpVector
747
    FUPVectorDirection: TGLCoordinates;
748

749
    FBallAndSocketOptions: TNGDJointPivot;
750
    FHingeOptions: TNGDJointPin;
751
    FSliderOptions: TNGDJointPin;
752
    FCorkscrewOptions: TNGDJointPin;
753
    FUniversalOptions: TNGDJointPin2;
754

755
    FCustomBallAndSocketOptions: TNGDJointBallAndSocket;
756
    FCustomHingeOptions: TNGDJointHinge;
757
    FCustomSliderOptions: TNGDJointSlider;
758
    FKinematicOptions: TNGDJointKinematicController;
759

760
    procedure SetJointType(const Value: TNGDNewtonJoints);
761
    procedure SetChildObject(const Value: TGLBaseSceneObject);
762
    procedure SetCollisionState(const Value: Boolean);
763
    procedure SetParentObject(const Value: TGLBaseSceneObject);
764
    procedure SetStiffness(const Value: Single);
765
    procedure Render;
766
    function StoredStiffness: Boolean;
767
    procedure DestroyNewtonData;
768
  public
769

770
    constructor Create(Collection: TCollection); override;
771
    destructor Destroy; override;
772
    procedure KinematicControllerPick(pickpoint: TVector;
773
      PickedActions: TNGDPickedActions);
774

775
  published
776
    property BallAndSocketOptions
777
      : TNGDJointPivot read FBallAndSocketOptions write
778
      FBallAndSocketOptions;
779
    property HingeOptions: TNGDJointPin read FHingeOptions write FHingeOptions;
780
    property SliderOptions
781
      : TNGDJointPin read FSliderOptions write FSliderOptions;
782
    property CorkscrewOptions
783
      : TNGDJointPin read FCorkscrewOptions write FCorkscrewOptions;
784
    property UniversalOptions
785
      : TNGDJointPin2 read FUniversalOptions write FUniversalOptions;
786
    property CustomBallAndSocketOptions
787
      : TNGDJointBallAndSocket read FCustomBallAndSocketOptions write
788
      FCustomBallAndSocketOptions;
789
    property CustomHingeOptions: TNGDJointHinge read FCustomHingeOptions write
790
      FCustomHingeOptions;
791
    property CustomSliderOptions
792
      : TNGDJointSlider read FCustomSliderOptions write
793
      FCustomSliderOptions;
794
    property KinematicControllerOptions
795
      : TNGDJointKinematicController read FKinematicOptions write
796
      FKinematicOptions;
797
    property JointType: TNGDNewtonJoints read FJointType write SetJointType;
798
    property ParentObject: TGLBaseSceneObject read FParentObject write
799
      SetParentObject;
800
    property ChildObject: TGLBaseSceneObject read FChildObject write
801
      SetChildObject;
802
    property CollisionState
803
      : Boolean read FCollisionState write SetCollisionState default False;
804
    property Stiffness: Single read FStiffness write SetStiffness stored
805
      StoredStiffness;
806
    property UPVectorDirection
807
      : TGLCoordinates read FUPVectorDirection write FUPVectorDirection;
808
  end;
809

810
  { Global function }
811
function GetNGDStatic(Obj: TGLBaseSceneObject): TGLNGDStatic;
812
function GetOrCreateNGDStatic(Obj: TGLBaseSceneObject): TGLNGDStatic;
813
function GetNGDDynamic(Obj: TGLBaseSceneObject): TGLNGDDynamic;
814
function GetOrCreateNGDDynamic(Obj: TGLBaseSceneObject): TGLNGDDynamic;
815

816
function GetBodyFromGLSceneObject(Obj: TGLBaseSceneObject): PNewtonBody;
817

818
implementation
819

820
const
821
  epsilon = 0.0000001; // 1E-07
822

823
  // GetNGDStatic
824
  //
825
function GetNGDStatic(Obj: TGLBaseSceneObject): TGLNGDStatic;
826
begin
827
  Result := TGLNGDStatic(Obj.Behaviours.GetByClass(TGLNGDStatic));
828
end;
829

830
// GetOrCreateNGDStatic
831
//
832
function GetOrCreateNGDStatic(Obj: TGLBaseSceneObject): TGLNGDStatic;
833
begin
834
  Result := TGLNGDStatic(Obj.GetOrCreateBehaviour(TGLNGDStatic));
835
end;
836

837
// GetNGDDynamic
838
//
839
function GetNGDDynamic(Obj: TGLBaseSceneObject): TGLNGDDynamic;
840
begin
841
  Result := TGLNGDDynamic(Obj.Behaviours.GetByClass(TGLNGDDynamic));
842
end;
843

844
// GetOrCreateNGDDynamic
845
//
846
function GetOrCreateNGDDynamic(Obj: TGLBaseSceneObject): TGLNGDDynamic;
847
begin
848
  Result := TGLNGDDynamic(Obj.GetOrCreateBehaviour(TGLNGDDynamic));
849
end;
850

851
function GetBodyFromGLSceneObject(Obj: TGLBaseSceneObject): PNewtonBody;
852
var
853
  Behaviour: TGLNGDBehaviour;
854
begin
855
  Behaviour := TGLNGDBehaviour(Obj.Behaviours.GetByClass(TGLNGDBehaviour));
856
  Assert(Behaviour <> nil, 'NGD Behaviour (static or dynamic) is missing for this object');
857
  Result := Behaviour.FNewtonBody;
858
end;
859

860
// ------------------------------------------------------------------
861
// ------------------------------------------------------------------
862
// ------------------------------------------------------------------
863

864
{ TNGDDebugOption }
865

866
constructor TNGDDebugOption.Create(AOwner: TComponent);
867
begin
868
  FManager := AOwner as TGLNGDManager;
869
  with FManager do
870
  begin
871
    FGeomColorDyn := TGLColor.CreateInitialized(self, clrGreen, NotifyChange);
872
    FGeomColorStat := TGLColor.CreateInitialized(self, clrRed, NotifyChange);
873
    FAABBColor := TGLColor.CreateInitialized(self, clrYellow, NotifyChange);
874
    FAABBColorSleep := TGLColor.CreateInitialized(self, clrOrange,
875
      NotifyChange);
876
    FCenterOfMassColor := TGLColor.CreateInitialized(self, clrPurple,
877
      NotifyChange);
878
    FContactColor := TGLColor.CreateInitialized(self, clrWhite, NotifyChange);
879
    FJointAxisColor := TGLColor.CreateInitialized(self, clrBlue, NotifyChange);
880
    FJointPivotColor := TGLColor.CreateInitialized(self, clrAquamarine,
881
      NotifyChange);
882

883
    FForceColor := TGLColor.CreateInitialized(self, clrBlack, NotifyChange);
884
    FAppliedForceColor := TGLColor.CreateInitialized(self, clrSilver,
885
      NotifyChange);
886
    FAppliedVelocityColor := TGLColor.CreateInitialized(self, clrLime,
887
      NotifyChange);
888

889
    FCustomColor := TGLColor.CreateInitialized(self, clrAqua, NotifyChange);
890
  end;
891
  FDotAxisSize := 1;
892
  FNGDManagerDebugs := [];
893

894
  FManager := AOwner as TGLNGDManager;
895
end;
896

897
destructor TNGDDebugOption.Destroy;
898
begin
899
  FGeomColorDyn.Free;
900
  FGeomColorStat.Free;
901
  FAABBColor.Free;
902
  FAABBColorSleep.Free;
903
  FCenterOfMassColor.Free;
904
  FContactColor.Free;
905
  FJointAxisColor.Free;
906
  FJointPivotColor.Free;
907
  FForceColor.Free;
908
  FAppliedForceColor.Free;
909
  FAppliedVelocityColor.Free;
910
  FCustomColor.Free;
911
  inherited;
912
end;
913

914
procedure TNGDDebugOption.SetDotAxisSize(const Value: Single);
915
begin
916
  FDotAxisSize := Value;
917
  FManager.NotifyChange(self);
918
end;
919

920
procedure TNGDDebugOption.SetNGDManagerDebugs(const Value: TNGDManagerDebugs);
921
begin
922
  FNGDManagerDebugs := Value;
923
  FManager.NotifyChange(self);
924
end;
925

926
function TNGDDebugOption.StoredDotAxis: Boolean;
927
begin
928
  Result := not SameValue(FDotAxisSize, 1, epsilon);
929
end;
930

931
{ TGLNGDManager }
932

933
procedure TGLNGDManager.AddNode(const Value: TVector);
934
begin
935
  if Assigned(FGLLines) then
936
  begin
937
    FGLLines.Nodes.AddNode(Value);
938

939
    with (FGLLines.Nodes.Last as TGLLinesNode) do
940
      Color := FCurrentColor;
941
  end;
942
end;
943

944
procedure TGLNGDManager.AddNode(const coords: TGLCustomCoordinates);
945
begin
946
  if Assigned(FGLLines) then
947
  begin
948
    FGLLines.Nodes.AddNode(coords); (FGLLines.Nodes.Last as TGLLinesNode)
949
    .Color := FCurrentColor;
950
  end;
951
end;
952

953
procedure TGLNGDManager.AddNode(const X, Y, Z: Single);
954
begin
955
  if Assigned(FGLLines) then
956
  begin
957
    FGLLines.Nodes.AddNode(X, Y, Z); (FGLLines.Nodes.Last as TGLLinesNode)
958
    .Color := FCurrentColor;
959
  end;
960
end;
961

962
procedure TGLNGDManager.AddNode(const Value: TAffineVector);
963
begin
964
  if Assigned(FGLLines) then
965
  begin
966
    FGLLines.Nodes.AddNode(Value); (FGLLines.Nodes.Last as TGLLinesNode)
967
    .Color := FCurrentColor;
968
  end;
969
end;
970

971
constructor TGLNGDManager.Create(AOwner: TComponent);
972
var
973
  minworld, maxworld: TVector;
974
begin
975
  inherited;
976
  FNGDBehaviours := TGLNGDBehaviourList.Create;
977
  FVisible := True;
978
  FVisibleAtRunTime := False;
979
  FSolverModel := smExact;
980
  FFrictionModel := fmExact;
981
  FMinimumFrameRate := 60;
982
  FWorldSizeMin := TGLCoordinates.CreateInitialized(self,
983
    VectorMake(-100, -100, -100, 0), csPoint);
984
  FWorldSizeMax := TGLCoordinates.CreateInitialized(self,
985
    VectorMake(100, 100, 100, 0), csPoint);
986

987
  // Using Events because we need to call API Function when
988
  // theses TGLCoordinates change.
989
  FWorldSizeMin.OnNotifyChange := NotifyWorldSizeChange;
990
  FWorldSizeMax.OnNotifyChange := NotifyWorldSizeChange;
991

992
  FThreadCount := 1;
993
  FGravity := TGLCoordinates3.CreateInitialized(self,
994
    VectorMake(0, -9.81, 0, 0), csVector);
995

996
  FNewtonWorld := NewtonCreate(nil, nil);
997
  FDllVersion := NewtonWorldGetVersion(FNewtonWorld);
998

999
  // This is to prevent body out the world at startTime
1000
  minworld := VectorMake(-1E50, -1E50, -1E50);
1001
  maxworld := VectorMake(1E50, 1E50, 1E50);
1002
  NewtonSetWorldSize(FNewtonWorld, @minworld, @maxworld);
1003

1004
  NewtonWorldSetUserData(FNewtonWorld, self);
1005

1006
  FNewtonSurfaceItem := TCollection.Create(TNGDSurfaceItem);
1007
  FNewtonSurfacePair := TOwnedCollection.Create(self, TNGDSurfacePair);
1008
  FNewtonJointGroup := TOwnedCollection.Create(self, TNGDJoint);
1009

1010
  FNGDDebugOption := TNGDDebugOption.Create(self);
1011

1012
  RegisterManager(self);
1013

1014
end;
1015

1016
destructor TGLNGDManager.Destroy;
1017
begin
1018
  // Destroy joint before body.
1019
  FreeAndNil(FNewtonJointGroup);
1020

1021
  // Unregister everything
1022
  while FNGDBehaviours.Count > 0 do
1023
    FNGDBehaviours[0].Manager := nil;
1024

1025
  // Clean up everything
1026
  FreeAndNil(FNGDBehaviours);
1027
  FreeAndNil(FWorldSizeMin);
1028
  FreeAndNil(FWorldSizeMax);
1029
  FreeAndNil(FGravity);
1030
  FreeAndNil(FNewtonSurfaceItem);
1031
  FreeAndNil(FNewtonSurfacePair);
1032
  FreeAndNil(FNGDDebugOption);
1033

1034
  NewtonDestroyAllBodies(FNewtonWorld);
1035
  NewtonMaterialDestroyAllGroupID(FNewtonWorld);
1036
  NewtonDestroy(FNewtonWorld);
1037
  FNewtonWorld := nil;
1038

1039
  DeregisterManager(self);
1040
  inherited;
1041
end;
1042

1043
procedure TGLNGDManager.Loaded;
1044
begin
1045
  inherited;
1046
  NotifyWorldSizeChange(self);
1047
  RebuildAllJoint(self);
1048
end;
1049

1050
function TGLNGDManager.GetBodyCount: Integer;
1051
begin
1052
  if (csDesigning in ComponentState) then
1053
    Result := FNGDBehaviours.Count
1054
  else
1055
    Result := NewtonWorldGetBodyCount(FNewtonWorld);
1056
end;
1057

1058
function TGLNGDManager.GetConstraintCount: Integer;
1059
begin
1060
  if (csDesigning in ComponentState) then
1061
    Result := FNewtonJointGroup.Count
1062
  else
1063
    // Constraint is the number of joint
1064
    Result := NewtonWorldGetConstraintCount(FNewtonWorld);
1065
end;
1066

1067
procedure TGLNGDManager.NotifyChange(Sender: TObject);
1068
var
1069
  I: Integer;
1070
begin
1071
  // This event is raise
1072
  // when debugOptions properties are edited,
1073
  // when a behavior is initialized/finalize,
1074
  // when joints are rebuilded, (runtime only)
1075
  // when visible and visibleAtRuntime are edited (designTime only),
1076
  // in manager.step, and in SetGLLines.
1077

1078
  // Here the manager call render method for bodies and joints in its lists
1079

1080
  if not Assigned(FGLLines) then
1081
    exit;
1082
  FGLLines.Nodes.Clear;
1083

1084
  if not Visible then
1085
    exit;
1086
  if not(csDesigning in ComponentState) then
1087
    if not VisibleAtRunTime then
1088
      exit;
1089

1090
  for I := 0 to FNGDBehaviours.Count - 1 do
1091
    FNGDBehaviours[I].Render;
1092

1093
  if mdShowJoint in FNGDDebugOption.NGDManagerDebugs then
1094
    for I := 0 to NewtonJoint.Count - 1 do //
1095
  (NewtonJoint.Items[I] as TNGDJoint)
1096
      .Render;
1097

1098
end;
1099

1100
procedure TGLNGDManager.SetFrictionModel(const Value: TNGDFrictionModels);
1101
begin
1102
  FFrictionModel := Value;
1103
  if not(csDesigning in ComponentState) then
1104
    NewtonSetFrictionModel(FNewtonWorld, Ord(FFrictionModel));
1105
end;
1106

1107
procedure TGLNGDManager.SetGLLines(const Value: TGLLines);
1108
begin
1109
  if Assigned(FGLLines) then
1110
    FGLLines.Nodes.Clear;
1111

1112
  FGLLines := Value;
1113

1114
  if Assigned(FGLLines) then
1115
  begin
1116
    FGLLines.SplineMode := lsmSegments;
1117
    FGLLines.NodesAspect := lnaInvisible;
1118
    FGLLines.Options := [loUseNodeColorForLines];
1119
    FGLLines.Pickable := False;
1120
    NotifyChange(self);
1121
  end;
1122
end;
1123

1124
procedure TGLNGDManager.SetMinimumFrameRate(const Value: Integer);
1125
begin
1126
  if (Value >= 60) and (Value <= 1000) then
1127
    FMinimumFrameRate := Value;
1128
  if not(csDesigning in ComponentState) then
1129
    NewtonSetMinimumFrameRate(FNewtonWorld, FMinimumFrameRate);
1130
end;
1131

1132
procedure TGLNGDManager.SetSolverModel(const Value: TNGDSolverModels);
1133
begin
1134
  FSolverModel := Value;
1135
  if not(csDesigning in ComponentState) then
1136
    NewtonSetSolverModel(FNewtonWorld, Ord(FSolverModel));
1137
end;
1138

1139
procedure TGLNGDManager.SetThreadCount(const Value: Integer);
1140
begin
1141
  if Value > 0 then
1142
    FThreadCount := Value;
1143
  NewtonSetThreadsCount(FNewtonWorld, FThreadCount);
1144
  FThreadCount := NewtonGetThreadsCount(FNewtonWorld);
1145
end;
1146

1147
procedure TGLNGDManager.SetVisible(const Value: Boolean);
1148
begin
1149
  FVisible := Value;
1150
  if (csDesigning in ComponentState) then
1151
    NotifyChange(self);
1152
end;
1153

1154
procedure TGLNGDManager.SetVisibleAtRunTime(const Value: Boolean);
1155
begin
1156
  FVisibleAtRunTime := Value;
1157
  if (csDesigning in ComponentState) then
1158
    NotifyChange(self);
1159
end;
1160

1161
procedure TGLNGDManager.NotifyWorldSizeChange(Sender: TObject);
1162
begin
1163
  if not(csDesigning in ComponentState) then
1164
    NewtonSetWorldSize(FNewtonWorld, @FWorldSizeMin.AsVector,
1165
      @FWorldSizeMax.AsVector);
1166
end;
1167

1168
procedure TGLNGDManager.RebuildAllJoint(Sender: TObject);
1169

1170
  procedure BuildBallAndSocket(Joint: TNGDJoint);
1171
  begin
1172
    with Joint do
1173
      if Assigned(FParentObject) and Assigned(FChildObject) then
1174
      begin
1175
        FNewtonJoint := NewtonConstraintCreateBall(FNewtonWorld,
1176
          @(FBallAndSocketOptions.FPivotPoint.AsVector),
1177
          GetBodyFromGLSceneObject(FChildObject),
1178
          GetBodyFromGLSceneObject(FParentObject));
1179
        NewtonJointSetCollisionState(FNewtonJoint, Ord(FCollisionState));
1180
        NewtonJointSetStiffness(FNewtonJoint, FStiffness);
1181
      end;
1182
  end;
1183

1184
  procedure BuildHinge(Joint: TNGDJoint);
1185
  begin
1186
    with Joint do
1187
      if Assigned(FParentObject) and Assigned(FChildObject) then
1188
      begin
1189
        FNewtonJoint := NewtonConstraintCreateHinge(FNewtonWorld,
1190
          @(FHingeOptions.FPivotPoint.AsVector),
1191
          @(FHingeOptions.FPinDirection.AsVector),
1192
          GetBodyFromGLSceneObject(FChildObject),
1193
          GetBodyFromGLSceneObject(FParentObject));
1194
        NewtonJointSetCollisionState(FNewtonJoint, Ord(FCollisionState));
1195
        NewtonJointSetStiffness(FNewtonJoint, FStiffness);
1196
      end;
1197
  end;
1198

1199
  procedure BuildSlider(Joint: TNGDJoint);
1200
  begin
1201
    with Joint do
1202
      if Assigned(FParentObject) and Assigned(FChildObject) then
1203
      begin
1204
        FNewtonJoint := NewtonConstraintCreateSlider(FNewtonWorld,
1205
          @(FSliderOptions.FPivotPoint.AsVector),
1206
          @(FSliderOptions.FPinDirection.AsVector),
1207
          GetBodyFromGLSceneObject(FChildObject),
1208
          GetBodyFromGLSceneObject(FParentObject));
1209
        NewtonJointSetCollisionState(FNewtonJoint, Ord(FCollisionState));
1210
        NewtonJointSetStiffness(FNewtonJoint, FStiffness);
1211
      end;
1212
  end;
1213

1214
  procedure BuildCorkscrew(Joint: TNGDJoint);
1215
  begin
1216
    with Joint do
1217
      if Assigned(FParentObject) and Assigned(FChildObject) then
1218
      begin
1219
        FNewtonJoint := NewtonConstraintCreateCorkscrew(FNewtonWorld,
1220
          @(FCorkscrewOptions.FPivotPoint.AsVector),
1221
          @(FCorkscrewOptions.FPinDirection.AsVector),
1222
          GetBodyFromGLSceneObject(FChildObject),
1223
          GetBodyFromGLSceneObject(FParentObject));
1224
        NewtonJointSetCollisionState(FNewtonJoint, Ord(FCollisionState));
1225
        NewtonJointSetStiffness(FNewtonJoint, FStiffness);
1226
      end;
1227
  end;
1228

1229
  procedure BuildUniversal(Joint: TNGDJoint);
1230
  begin
1231
    with Joint do
1232
      if Assigned(FParentObject) and Assigned(FChildObject) then
1233
      begin
1234
        FNewtonJoint := NewtonConstraintCreateUniversal(FNewtonWorld,
1235
          @(FUniversalOptions.FPivotPoint.AsVector),
1236
          @(FUniversalOptions.FPinDirection.AsVector),
1237
          @(FUniversalOptions.FPinDirection2.AsVector),
1238
          GetBodyFromGLSceneObject(FChildObject),
1239
          GetBodyFromGLSceneObject(FParentObject));
1240
        NewtonJointSetCollisionState(FNewtonJoint, Ord(FCollisionState));
1241
        NewtonJointSetStiffness(FNewtonJoint, FStiffness);
1242
      end;
1243
  end;
1244

1245
  procedure BuildCustomBallAndSocket(Joint: TNGDJoint);
1246
  var
1247
    pinAndPivot: TMatrix;
1248
  begin
1249
    with Joint do
1250
      if Assigned(FParentObject) and Assigned(FChildObject) then
1251
      begin
1252
        pinAndPivot := IdentityHmgMatrix;
1253
        pinAndPivot.V[3] := FCustomBallAndSocketOptions.FPivotPoint.AsVector;
1254
        FNewtonUserJoint := CreateCustomBallAndSocket(@pinAndPivot,
1255
          GetBodyFromGLSceneObject(FChildObject),
1256
          GetBodyFromGLSceneObject(FParentObject));
1257
        BallAndSocketSetConeAngle(FNewtonUserJoint,
1258
          GLVectorGeometry.DegToRad(FCustomBallAndSocketOptions.FConeAngle));
1259
        BallAndSocketSetTwistAngle(FNewtonUserJoint,
1260
          GLVectorGeometry.DegToRad(FCustomBallAndSocketOptions.FMinTwistAngle),
1261
          GLVectorGeometry.DegToRad(FCustomBallAndSocketOptions.FMaxTwistAngle));
1262
        CustomSetBodiesCollisionState(FNewtonUserJoint, Ord(FCollisionState));
1263
        NewtonJointSetStiffness(CustomGetNewtonJoint(FNewtonUserJoint),
1264
          FStiffness);
1265
      end;
1266
  end;
1267

1268
  procedure BuildCustomHinge(Joint: TNGDJoint);
1269
  var
1270
    pinAndPivot: TMatrix;
1271
    bso: TGLBaseSceneObject;
1272
  begin
1273
    { Newton wait from FPinAndPivotMatrix a structure like that:
1274
      First row: the pin direction
1275
      Second and third rows are set to create an orthogonal matrix
1276
      Fourth: The pivot position
1277

1278
      In glscene, the GLBaseSceneObjects direction is the third row,
1279
      because the first row is the right vector (second row is up vector). }
1280
    with Joint do
1281
      if Assigned(FParentObject) and Assigned(FChildObject) then
1282
      begin
1283
        bso := TGLBaseSceneObject.Create(FManager);
1284
        bso.AbsolutePosition := FCustomHingeOptions.FPivotPoint.AsVector;
1285
        bso.AbsoluteDirection := FCustomHingeOptions.FPinDirection.AsVector;
1286
        pinAndPivot := bso.AbsoluteMatrix;
1287
        pinAndPivot.V[0] := bso.AbsoluteMatrix.V[2];
1288
        pinAndPivot.V[2] := bso.AbsoluteMatrix.V[0];
1289
        bso.Free;
1290

1291
        FNewtonUserJoint := CreateCustomHinge(@pinAndPivot,
1292
          GetBodyFromGLSceneObject(FChildObject),
1293
          GetBodyFromGLSceneObject(FParentObject));
1294
        HingeEnableLimits(FNewtonUserJoint, 1);
1295
        HingeSetLimits(FNewtonUserJoint,
1296
          GLVectorGeometry.DegToRad(FCustomHingeOptions.FMinAngle),
1297
          GLVectorGeometry.DegToRad(FCustomHingeOptions.FMaxAngle));
1298
        CustomSetBodiesCollisionState(FNewtonUserJoint, Ord(FCollisionState));
1299
        NewtonJointSetStiffness(CustomGetNewtonJoint(FNewtonUserJoint),
1300
          FStiffness);
1301
        CustomSetUserData(FNewtonUserJoint, CustomHingeOptions);
1302
      end;
1303
  end;
1304

1305
  procedure BuildCustomSlider(Joint: TNGDJoint);
1306
  var
1307
    pinAndPivot: TMatrix;
1308
    bso: TGLBaseSceneObject;
1309

1310
  begin
1311
    { Newton wait from FPinAndPivotMatrix a structure like that:
1312
      First row: the pin direction
1313
      Second and third rows are set to create an orthogonal matrix
1314
      Fourth: The pivot position
1315

1316
      In glscene, the GLBaseSceneObjects direction is the third row,
1317
      because the first row is the right vector (second row is up vector). }
1318
    with Joint do
1319
      if Assigned(FParentObject) and Assigned(FChildObject) then
1320
      begin
1321

1322
        bso := TGLBaseSceneObject.Create(FManager);
1323
        bso.AbsolutePosition := FCustomSliderOptions.FPivotPoint.AsVector;
1324
        bso.AbsoluteDirection := FCustomSliderOptions.FPinDirection.AsVector;
1325
        pinAndPivot := bso.AbsoluteMatrix;
1326
        pinAndPivot.V[0] := bso.AbsoluteMatrix.V[2];
1327
        pinAndPivot.V[2] := bso.AbsoluteMatrix.V[0];
1328
        bso.Free;
1329

1330
        FNewtonUserJoint := CreateCustomSlider(@pinAndPivot, GetBodyFromGLSceneObject(FChildObject), GetBodyFromGLSceneObject(FParentObject));
1331
        SliderEnableLimits(FNewtonUserJoint, 1);
1332
        SliderSetLimits(FNewtonUserJoint, FCustomSliderOptions.FMinDistance, FCustomSliderOptions.FMaxDistance);
1333
        NewtonJointSetStiffness(CustomGetNewtonJoint(FNewtonUserJoint),0);
1334

1335
        CustomSetBodiesCollisionState(FNewtonUserJoint, Ord(FCollisionState));
1336
        CustomSetUserData(FNewtonUserJoint, CustomSliderOptions);
1337
      end;
1338
  end;
1339

1340
  procedure BuildUpVector(Joint: TNGDJoint);
1341
  begin
1342
    with Joint do
1343
      if Assigned(FParentObject) then
1344
      begin
1345
        FNewtonJoint := NewtonConstraintCreateUpVector(FNewtonWorld,
1346
          @FUPVectorDirection.AsVector,
1347
          GetBodyFromGLSceneObject(FParentObject));
1348
      end;
1349
  end;
1350

1351
  procedure BuildKinematicController(Joint: TNGDJoint);
1352
  begin
1353
    // do nothing
1354
  end;
1355

1356
  procedure BuildOneJoint(Joint: TNGDJoint);
1357
  begin
1358
    case Joint.FJointType of
1359
      nj_BallAndSocket:
1360
        begin
1361
          Joint.DestroyNewtonData;
1362
          BuildBallAndSocket(Joint);
1363
        end;
1364

1365
      nj_Hinge:
1366
        begin
1367
          Joint.DestroyNewtonData;
1368
          BuildHinge(Joint);
1369
        end;
1370

1371
      nj_Slider:
1372
        begin
1373
          Joint.DestroyNewtonData;
1374
          BuildSlider(Joint);
1375
        end;
1376

1377
      nj_Corkscrew:
1378
        begin
1379
          Joint.DestroyNewtonData;
1380
          BuildCorkscrew(Joint);
1381
        end;
1382

1383
      nj_Universal:
1384
        begin
1385
          Joint.DestroyNewtonData;
1386
          BuildUniversal(Joint);
1387
        end;
1388

1389
      nj_CustomBallAndSocket:
1390
        begin
1391
          Joint.DestroyNewtonData;
1392
          BuildCustomBallAndSocket(Joint);
1393
        end;
1394

1395
      nj_CustomHinge:
1396
        begin
1397
          Joint.DestroyNewtonData;
1398
          BuildCustomHinge(Joint);
1399
        end;
1400

1401
      nj_CustomSlider:
1402
        begin
1403
          Joint.DestroyNewtonData;
1404
          BuildCustomSlider(Joint);
1405
        end;
1406

1407
      nj_UpVector:
1408
        begin
1409
          Joint.DestroyNewtonData;
1410
          BuildUpVector(Joint);
1411
        end;
1412

1413
      nj_KinematicController:
1414
        begin
1415
          // DestroyJoint(Joint);
1416
          // BuildKinematicController(Joint);
1417
        end;
1418
    end;
1419
  end;
1420

1421
var
1422
  i: Integer;
1423
begin
1424

1425
  if not(csDesigning in ComponentState) and not(csLoading in ComponentState)
1426
    then
1427
  begin
1428
    if Sender is TGLNGDManager then
1429
      for i := 0 to NewtonJoint.Count - 1 do
1430
        BuildOneJoint(NewtonJoint.Items[i] as TNGDJoint);
1431

1432
    if (Sender is TNGDJoint) then
1433
      BuildOneJoint((Sender as TNGDJoint));
1434

1435
    if Sender is TGLCoordinates then
1436
      BuildOneJoint(((Sender as TGLCoordinates).Owner as TNGDJoint));
1437

1438
    NotifyChange(self);
1439
  end;
1440

1441
end;
1442

1443
procedure TGLNGDManager.RebuildAllMaterial;
1444

1445
  procedure BuildMaterialPair;
1446
  var
1447
    I, ID0, ID1: Integer;
1448
  begin
1449
    for I := 0 to FNewtonSurfacePair.Count - 1 do
1450
      with (FNewtonSurfacePair.Items[I] as TNGDSurfacePair) do
1451
      begin
1452
        if Assigned(NGDSurfaceItem1) and Assigned(NGDSurfaceItem2) then
1453
        begin
1454
          ID0 := NGDSurfaceItem1.ID;
1455
          ID1 := NGDSurfaceItem2.ID;
1456

1457
          NewtonMaterialSetContinuousCollisionMode(FNewtonWorld, ID0, ID1,
1458
            Ord(ContinuousCollisionMode));
1459
          if Thickness then
1460
            NewtonMaterialSetSurfaceThickness(FNewtonWorld, ID0, ID1, 1);
1461
          NewtonMaterialSetDefaultSoftness(FNewtonWorld, ID0, ID1, Softness);
1462
          NewtonMaterialSetDefaultElasticity(FNewtonWorld, ID0, ID1,
1463
            Elasticity);
1464
          NewtonMaterialSetDefaultCollidable(FNewtonWorld, ID0, ID1,
1465
            Ord(Collidable));
1466
          NewtonMaterialSetDefaultFriction(FNewtonWorld, ID0, ID1,
1467
            StaticFriction, KineticFriction);
1468

1469
          NewtonMaterialSetCollisionCallback(FNewtonWorld, ID0, ID1,
1470
            FNewtonSurfacePair.Items[I], @TNGDSurfacePair.NewtonAABBOverlap,
1471
            @TNGDSurfacePair.NewtonContactsProcess);
1472
        end;
1473
      end;
1474
  end;
1475

1476
var
1477
  I: Integer;
1478
  maxID: Integer;
1479
begin
1480
  maxID := 0;
1481
  if not(csDesigning in ComponentState) then
1482
  begin
1483
    // Destroy newton materials
1484
    NewtonMaterialDestroyAllGroupID(FNewtonWorld);
1485

1486
    // Create materialID
1487
    for I := 0 to FNewtonSurfaceItem.Count - 1 do
1488
      maxID := MaxInteger((FNewtonSurfaceItem.Items[I] as TNGDSurfaceItem).ID,
1489
        maxID);
1490
    for I := 0 to maxID - 1 do
1491
      NewtonMaterialCreateGroupID(FNewtonWorld);
1492

1493
    // Assigned matID to bodies
1494
    for I := 0 to FNGDBehaviours.Count - 1 do
1495
      with FNGDBehaviours[I] do
1496
        if Assigned(FNGDSurfaceItem) then
1497
          NewtonBodySetMaterialGroupID(FNewtonBody, FNGDSurfaceItem.ID)
1498
        else
1499
          NewtonBodySetMaterialGroupID(FNewtonBody, 0);
1500

1501
    // Set values to newton material pair :callback userdata friction...
1502
    BuildMaterialPair;
1503
  end;
1504
end;
1505

1506
procedure TGLNGDManager.Step(deltatime: Single);
1507
begin
1508
  if not(csDesigning in ComponentState) then
1509
    NewtonUpdate(FNewtonWorld, deltatime);
1510

1511
  NotifyChange(self);
1512
end;
1513

1514
{ TGLNGDBehaviour }
1515

1516
constructor TGLNGDBehaviour.Create(AOwner: TGLXCollection);
1517
begin
1518
  inherited;
1519
  FInitialized := False;
1520
  FOwnerBaseSceneObject := OwnerBaseSceneObject;
1521

1522
  FContinuousCollisionMode := False;
1523
  FNewtonBody := nil;
1524
  FCollision := nil;
1525

1526
  FNGDNewtonCollisions := nc_Primitive;
1527

1528
  FCollisionIteratorEvent := OnCollisionIteratorEvent;
1529

1530
  FTreeCollisionOptimize := True;
1531
  FConvexCollisionTolerance := 0.01;
1532
  FFileCollision := '';
1533
  name := 'NGD Static';
1534
end;
1535

1536
destructor TGLNGDBehaviour.Destroy;
1537
begin
1538
  if Assigned(FManager) then
1539
    Manager := nil;  // This will call finalize
1540
  inherited;
1541
end;
1542

1543
procedure TGLNGDBehaviour.Finalize;
1544
var
1545
  i: integer;
1546
begin
1547
  FInitialized := False;
1548

1549
  if Assigned(FManager) then
1550
  begin
1551

1552
    if Assigned(FManager.NewtonJoint) then
1553
    for i := FManager.NewtonJoint.Count-1 downto 0 do
1554
    begin
1555
      if ((FManager.NewtonJoint.Items[i] as TNGDJoint).ParentObject = FOwnerBaseSceneObject)
1556
      or ((FManager.NewtonJoint.Items[i] as TNGDJoint).ChildObject = FOwnerBaseSceneObject) then
1557
      begin
1558
        FManager.NewtonJoint.Items[i].Free;
1559
      end;
1560
    end;
1561

1562
    NewtonDestroyBody(FManager.FNewtonWorld, FNewtonBody);
1563
    FNewtonBody := nil;
1564
    FCollision := nil;
1565
  end;
1566
end;
1567

1568
function TGLNGDBehaviour.GetBBoxCollision: PNewtonCollision;
1569
var
1570
  vc: array [0 .. 7] of TVector;
1571
  I: Integer;
1572
begin
1573
  for I := 0 to 8 - 1 do
1574
    vc[I] := AABBToBB(FOwnerBaseSceneObject.AxisAlignedBoundingBoxEx).BBox[I];
1575
  Result := NewtonCreateConvexHull(FManager.FNewtonWorld, 8, @vc[0],
1576
    SizeOf(TVector), 0.01, 0, nil);
1577
end;
1578

1579
function TGLNGDBehaviour.GetBSphereCollision: PNewtonCollision;
1580
var
1581
  boundingSphere: TBSphere;
1582
  collisionOffsetMatrix: TMatrix;
1583
begin
1584
  AABBToBSphere(FOwnerBaseSceneObject.AxisAlignedBoundingBoxEx, boundingSphere);
1585

1586
  collisionOffsetMatrix := IdentityHmgMatrix;
1587
  collisionOffsetMatrix.V[3] := VectorMake(boundingSphere.Center, 1);
1588
  Result := NewtonCreateSphere(FManager.FNewtonWorld, boundingSphere.Radius,
1589
    boundingSphere.Radius, boundingSphere.Radius, 0, @collisionOffsetMatrix);
1590
end;
1591

1592
function TGLNGDBehaviour.GetConvexCollision: PNewtonCollision;
1593
var
1594
  I, J: Integer;
1595
  vertexArray: array of TVertex;
1596
begin
1597
  if FOwnerBaseSceneObject is TGLBaseMesh then
1598
  begin
1599
    with (FOwnerBaseSceneObject as TGLBaseMesh) do
1600
    begin
1601

1602
      for I := 0 to MeshObjects.Count - 1 do
1603
        for J := 0 to MeshObjects[I].Vertices.Count - 1 do
1604
        begin
1605
          SetLength(vertexArray, Length(vertexArray) + 1);
1606
          vertexArray[Length(vertexArray) - 1] := MeshObjects[I].Vertices[J];
1607
        end;
1608

1609
      if Length(vertexArray) > 0 then
1610
        Result := NewtonCreateConvexHull(FManager.FNewtonWorld,
1611
          Length(vertexArray), @vertexArray[0], SizeOf(TVertex),
1612
          FConvexCollisionTolerance, 0, nil)
1613
      else
1614
        Result := GetNullCollision;
1615

1616
    end;
1617
  end
1618
  else
1619
    Result := GetNullCollision;
1620
end;
1621

1622
function TGLNGDBehaviour.GetHeightFieldCollision: PNewtonCollision;
1623
var
1624
  I: Integer;
1625
  attributeMap: array of ShortInt;
1626
begin
1627
  SetLength(attributeMap, Length(FHeightFieldOptions.heightArray));
1628
  for I := 0 to Length(FHeightFieldOptions.heightArray) - 1 do
1629
    attributeMap[I] := 0;
1630

1631
  Result := NewtonCreateHeightFieldCollision(FManager.FNewtonWorld,
1632
    FHeightFieldOptions.width, FHeightFieldOptions.depth,
1633
    Ord(FHeightFieldOptions.gridDiagonals),
1634
    PUnsigned_short(FHeightFieldOptions.heightArray), P2Char(attributeMap),
1635
    FHeightFieldOptions.widthDepthScale, FHeightFieldOptions.heightScale, 0);
1636
end;
1637

1638
function TGLNGDBehaviour.GetMeshCollision: PNewtonCollision;
1639
var
1640
  collisionArray: array of PNewtonCollision;
1641
  I, J: Integer;
1642
  vertexArray: array of TVertex;
1643
begin
1644
  if FOwnerBaseSceneObject is TGLBaseMesh then
1645
  begin
1646
    with (FOwnerBaseSceneObject as TGLBaseMesh) do
1647
    begin
1648

1649
      // Iterate trough mesh of GLobject
1650
      for I := 0 to MeshObjects.Count - 1 do
1651
      begin
1652
        // Iterate trough vertices of mesh
1653
        for J := 0 to MeshObjects[I].Vertices.Count - 1 do
1654
        begin
1655
          SetLength(vertexArray, Length(vertexArray) + 1);
1656
          vertexArray[Length(vertexArray) - 1] := MeshObjects[I].Vertices[J];
1657
        end;
1658

1659
        if Length(vertexArray) > 3 then
1660
        begin
1661
          SetLength(collisionArray, Length(collisionArray) + 1);
1662

1663
          collisionArray[Length(collisionArray) - 1] := NewtonCreateConvexHull
1664
            (FManager.FNewtonWorld, Length(vertexArray), @vertexArray[0],
1665
            SizeOf(TVertex), FConvexCollisionTolerance, 0, nil);
1666

1667
          // Remove last collision if the newton function was not successful
1668
          if collisionArray[Length(collisionArray) - 1] = nil then
1669
            SetLength(collisionArray, Length(collisionArray) - 1);
1670

1671
        end;
1672
        SetLength(vertexArray, 0);
1673
      end;
1674

1675
      if Length(collisionArray) > 0 then
1676
        Result := NewtonCreateCompoundCollision(FManager.FNewtonWorld,
1677
          Length(collisionArray), @collisionArray[0], 0)
1678
      else
1679
        Result := GetNullCollision;
1680

1681
    end;
1682
  end
1683
  else
1684
    Result := GetNullCollision;
1685

1686
end;
1687

1688

1689
function TGLNGDBehaviour.GetNewtonBodyMatrix: TMatrix;
1690
begin
1691
  if Assigned(FManager) then
1692
    NewtonBodyGetmatrix(FNewtonBody, @FNewtonBodyMatrix);
1693
  Result := FNewtonBodyMatrix;
1694
end;
1695

1696
function TGLNGDBehaviour.GetNewtonBodyAABB: TAABB;
1697
begin
1698
  if Assigned(FManager) then
1699
    NewtonBodyGetAABB(FNewtonBody, @(Result.min), @(Result.max));
1700
end;
1701

1702
function TGLNGDBehaviour.GetNGDFileCollision: PNewtonCollision;
1703
var
1704
  MyFile: TFileStream;
1705
begin
1706

1707
  if FileExists(FFileCollision) then
1708
  begin
1709
    MyFile := TFileStream.Create(FFileCollision, fmOpenRead);
1710

1711
    Result := NewtonCreateCollisionFromSerialization(FManager.FNewtonWorld,
1712
      @TGLNGDBehaviour.NewtonDeserialize, Pointer(MyFile));
1713

1714
    MyFile.Free;
1715
  end
1716
  else
1717
    Result := NewtonCreateNull(FManager.FNewtonWorld);
1718

1719
end;
1720

1721
function TGLNGDBehaviour.GetNullCollision: PNewtonCollision;
1722
begin
1723
  Result := NewtonCreateNull(FManager.FNewtonWorld);
1724
end;
1725

1726
function TGLNGDBehaviour.GetPrimitiveCollision: PNewtonCollision;
1727
var
1728
  collisionOffsetMatrix: TMatrix; // For cone capsule and cylinder
1729
begin
1730
  collisionOffsetMatrix := IdentityHmgMatrix;
1731

1732
  if (FOwnerBaseSceneObject is TGLCube) then
1733
  begin
1734
    with (FOwnerBaseSceneObject as TGLCube) do
1735
      Result := NewtonCreateBox(FManager.FNewtonWorld, CubeWidth, CubeHeight,
1736
        CubeDepth, 0, @collisionOffsetMatrix);
1737
  end
1738

1739
  else if (FOwnerBaseSceneObject is TGLSphere) then
1740
  begin
1741
    with (FOwnerBaseSceneObject as TGLSphere) do
1742
      Result := NewtonCreateSphere(FManager.FNewtonWorld, Radius, Radius,
1743
        Radius, 0, @collisionOffsetMatrix);
1744
  end
1745

1746
  else if (FOwnerBaseSceneObject is TGLCone) then
1747
  begin
1748
    collisionOffsetMatrix := MatrixMultiply(collisionOffsetMatrix,
1749
      CreateRotationMatrixZ(Pi / 2.0));
1750
    with (FOwnerBaseSceneObject as TGLCone) do
1751
      Result := NewtonCreateCone(FManager.FNewtonWorld, BottomRadius, Height,
1752
        0, @collisionOffsetMatrix);
1753
  end
1754

1755
  else if (FOwnerBaseSceneObject is TGLCapsule) then
1756
  begin
1757
    collisionOffsetMatrix := MatrixMultiply(collisionOffsetMatrix,
1758
      CreateRotationMatrixY(Pi / 2.0));
1759
    with (FOwnerBaseSceneObject as TGLCapsule) do
1760
      // Use Cylinder shape for buoyancy
1761
      Result := NewtonCreateCapsule(FManager.FNewtonWorld, Radius,
1762
        Height + 2 * Radius, 0, @collisionOffsetMatrix);
1763
  end
1764

1765
  else if (FOwnerBaseSceneObject is TGLCylinder) then
1766
  begin
1767
    collisionOffsetMatrix := MatrixMultiply(collisionOffsetMatrix,
1768
      CreateRotationMatrixZ(Pi / 2.0));
1769
    with (FOwnerBaseSceneObject as TGLCylinder) do
1770
      Result := NewtonCreateCylinder(FManager.FNewtonWorld, BottomRadius,
1771
        Height, 0, @collisionOffsetMatrix);
1772
  end
1773
  else
1774
    Result := GetNullCollision;
1775
end;
1776

1777
function TGLNGDBehaviour.GetTreeCollision: PNewtonCollision;
1778
var
1779
  meshIndex, triangleIndex: Integer;
1780
  triangleList: TAffineVectorList;
1781
  v: array [0 .. 2] of TAffineVector;
1782
begin
1783

1784
  if FOwnerBaseSceneObject is TGLBaseMesh then
1785
  begin
1786
    with (FOwnerBaseSceneObject as TGLBaseMesh) do
1787
    begin
1788
      Result := NewtonCreateTreeCollision(FManager.FNewtonWorld, 0);
1789
      NewtonTreeCollisionBeginBuild(Result);
1790

1791
      for meshIndex := 0 to MeshObjects.Count - 1 do
1792
      begin
1793
        triangleList := MeshObjects[meshIndex].ExtractTriangles;
1794
        for triangleIndex := 0 to triangleList.Count - 1 do
1795
        begin
1796
          if triangleIndex mod 3 = 0 then
1797
          begin
1798
            v[0] := triangleList.Items[triangleIndex];
1799
            // ScaleVector(v[0], FOwnerBaseSceneObject.Scale.X);
1800
            v[1] := triangleList.Items[triangleIndex + 1];
1801
            // ScaleVector(v[1], FOwnerBaseSceneObject.Scale.Y);
1802
            v[2] := triangleList.Items[triangleIndex + 2];
1803
            // ScaleVector(v[2], FOwnerBaseSceneObject.Scale.Z);
1804
            NewtonTreeCollisionAddFace(Result, 3, @(v), SizeOf(TAffineVector),
1805
              1);
1806
          end;
1807
        end;
1808
        triangleList.Free;
1809
      end;
1810
      NewtonTreeCollisionEndBuild(Result, Ord(FTreeCollisionOptimize));
1811
    end;
1812
  end
1813
  else
1814
    Result := GetNullCollision;
1815

1816
end;
1817

1818
procedure TGLNGDBehaviour.Initialize;
1819
begin
1820
  FInitialized := True;
1821

1822
  if Assigned(FManager) then
1823
  begin
1824
    // Create NewtonBody with null collision
1825
    FCollision := NewtonCreateNull(FManager.FNewtonWorld);
1826
    FNewtonBodyMatrix := FOwnerBaseSceneObject.AbsoluteMatrix;
1827
    FNewtonBody := NewtonCreateBody(FManager.FNewtonWorld, FCollision,
1828
      @FNewtonBodyMatrix);
1829

1830
    // Release NewtonCollision
1831
    NewtonReleaseCollision(FManager.FNewtonWorld, FCollision);
1832

1833
    // Set Link between glscene and newton
1834
    NewtonBodySetUserdata(FNewtonBody, self);
1835

1836
    // Set position and orientation
1837
    SetNewtonBodyMatrix(FOwnerBaseSceneObject.AbsoluteMatrix);
1838

1839
    // Set Collision
1840
    UpdCollision;
1841

1842
  end;
1843
end;
1844

1845
procedure TGLNGDBehaviour.Loaded;
1846
var
1847
  mng: TComponent;
1848
begin
1849
  inherited;
1850
  if FManagerName <> '' then
1851
  begin
1852
    mng := FindManager(TGLNGDManager, FManagerName);
1853
    if Assigned(mng) then
1854
      Manager := TGLNGDManager(mng);
1855
    FManagerName := '';
1856
  end;
1857

1858
  if Assigned(FManager) then
1859
  begin
1860
    SetContinuousCollisionMode(FContinuousCollisionMode);
1861
  end;
1862
end;
1863

1864
class procedure TGLNGDBehaviour.NewtonCollisionIterator
1865
  (const userData: Pointer; vertexCount: Integer; const faceArray: PNGDFloat;
1866
  faceId: Integer)cdecl; static;
1867
begin
1868
  TGLNGDBehaviour(userData).FCollisionIteratorEvent(userData, vertexCount,
1869
    faceArray, faceId);
1870
end;
1871

1872
// Serializes are called by NGDBehaviour to save and load collision in file
1873
// It's better to save/load big collisions [over 50000 polygones] to reduce
1874
// loading time
1875
class procedure TGLNGDBehaviour.NewtonDeserialize(serializeHandle,
1876
  buffer: Pointer; size: Cardinal)cdecl; static;
1877
begin
1878
  TFileStream(serializeHandle).read(buffer^, size);
1879
end;
1880

1881
class procedure TGLNGDBehaviour.NewtonSerialize(serializeHandle: Pointer;
1882
  const buffer: Pointer; size: Cardinal)cdecl; static;
1883

1884
begin
1885
  TFileStream(serializeHandle).write(buffer^, size);
1886
end;
1887

1888
procedure TGLNGDBehaviour.OnCollisionIteratorEvent(const userData: Pointer;
1889
  vertexCount: Integer; const cfaceArray: PNGDFloat; faceId: Integer);
1890
var
1891
  I: Integer;
1892
  v0, v1: array [0 .. 2] of Single;
1893
  vA: array of Single;
1894
begin
1895
  // This algorithme draw Collision Shape for Debuggin.
1896
  // Taken to Sascha Willems in SDLNewton-Demo at
1897
  // http://www.saschawillems.de/?page_id=82
1898

1899
  // Leave if there is no or to much vertex
1900
  if (vertexCount = 0) then
1901
    exit;
1902

1903
  SetLength(vA, vertexCount * 3);
1904
  Move(cfaceArray^, vA[0], vertexCount * 3 * SizeOf(Single));
1905
  v0[0] := vA[(vertexCount - 1) * 3];
1906
  v0[1] := vA[(vertexCount - 1) * 3 + 1];
1907
  v0[2] := vA[(vertexCount - 1) * 3 + 2];
1908
  for I := 0 to vertexCount - 1 do
1909
  begin
1910
    v1[0] := vA[I * 3];
1911
    v1[1] := vA[I * 3 + 1];
1912
    v1[2] := vA[I * 3 + 2];
1913
    FManager.AddNode(v0[0], v0[1], v0[2]);
1914
    FManager.AddNode(v1[0], v1[1], v1[2]);
1915
    v0 := v1;
1916
  end;
1917
end;
1918

1919
procedure TGLNGDBehaviour.Reinitialize;
1920
begin
1921
  if Initialized then
1922
  begin
1923
    // Set Appropriate NewtonCollision
1924
    UpdCollision();
1925
    // Set position and orientation
1926
    SetNewtonBodyMatrix(FOwnerBaseSceneObject.AbsoluteMatrix);
1927
  end;
1928
  Loaded;
1929
end;
1930

1931
procedure TGLNGDBehaviour.Render;
1932
var
1933
  M: TMatrix;
1934
begin
1935
  // Rebuild collision in design time
1936
  if (csDesigning in FOwnerBaseSceneObject.ComponentState) then
1937
    Reinitialize;
1938

1939
  if self is TGLNGDDynamic then
1940
    FManager.FCurrentColor := FManager.DebugOption.GeomColorDyn
1941
  else
1942
    FManager.FCurrentColor := FManager.DebugOption.GeomColorStat;
1943

1944
  M := FOwnerBaseSceneObject.AbsoluteMatrix;
1945

1946
  if mdShowGeometry in FManager.DebugOption.NGDManagerDebugs then
1947
    NewtonCollisionForEachPolygonDo(FCollision, @M,
1948
      @TGLNGDBehaviour.NewtonCollisionIterator, self);
1949
end;
1950

1951
// In this procedure, we assign collision to body
1952
// [Because when initialised, the collision for body is type NULL]
1953
procedure TGLNGDBehaviour.UpdCollision;
1954
var
1955
  collisionInfoRecord: TNewtonCollisionInfoRecord;
1956
begin
1957

1958
  case FNGDNewtonCollisions of
1959
    nc_Primitive:
1960
      FCollision := GetPrimitiveCollision;
1961
    nc_Convex:
1962
      FCollision := GetConvexCollision;
1963
    nc_BBox:
1964
      FCollision := GetBBoxCollision;
1965
    nc_BSphere:
1966
      FCollision := GetBSphereCollision;
1967
    nc_Tree:
1968
      FCollision := GetTreeCollision;
1969
    nc_Mesh:
1970
      FCollision := GetMeshCollision;
1971
    nc_Null:
1972
      FCollision := GetNullCollision;
1973
    nc_HeightField:
1974
      FCollision := GetHeightFieldCollision;
1975
    nc_NGDFile:
1976
      FCollision := GetNGDFileCollision;
1977
  end;
1978

1979
  if Assigned(FCollision) then
1980
  begin
1981
    NewtonBodySetCollision(FNewtonBody, FCollision);
1982

1983
    // The API Ask for releasing Collision to avoid memory leak
1984
    NewtonCollisionGetInfo(FCollision, @collisionInfoRecord);
1985
    if collisionInfoRecord.m_referenceCount > 2 then
1986
      NewtonReleaseCollision(FManager.FNewtonWorld, FCollision);
1987
  end;
1988

1989
end;
1990

1991
procedure TGLNGDBehaviour.SetContinuousCollisionMode(const Value: Boolean);
1992
begin
1993
  // for continue collision to be active the continue collision mode must on
1994
  // the material pair of the colliding bodies as well as on at
1995
  // least one of the two colliding bodies.
1996
  // see NewtonBodySetContinuousCollisionMode
1997
  // see NewtonMaterialSetContinuousCollisionMode
1998
  FContinuousCollisionMode := Value;
1999
  if not(csDesigning in FOwnerBaseSceneObject.ComponentState) then
2000
    if Assigned(FManager) then
2001
      NewtonBodySetContinuousCollisionMode(FNewtonBody, Ord(Value));
2002
end;
2003

2004
procedure TGLNGDBehaviour.SetHeightFieldOptions(const Value: THeightField);
2005
begin
2006
  FHeightFieldOptions := Value;
2007
  Reinitialize;
2008
end;
2009

2010
procedure TGLNGDBehaviour.SetManager(Value: TGLNGDManager);
2011
begin
2012
  if FManager <> Value then
2013
  begin
2014
    if Assigned(FManager) then
2015
    begin
2016
      if Initialized then
2017
        Finalize;
2018
      FManager.FNGDBehaviours.Remove(self);
2019
      // FManager.NotifyChange(self);
2020
    end;
2021
    FManager := Value;
2022
    if Assigned(FManager) then
2023
    begin
2024
      Initialize;
2025
      FManager.FNGDBehaviours.Add(self);
2026
      FManager.NotifyChange(self);
2027
    end;
2028
  end;
2029
end;
2030

2031
procedure TGLNGDBehaviour.SetNewtonBodyMatrix(const Value: TMatrix);
2032
begin
2033
  FNewtonBodyMatrix := Value;
2034
  if Assigned(FManager) then
2035
    NewtonBodySetmatrix(FNewtonBody, @FNewtonBodyMatrix);
2036
end;
2037

2038
procedure TGLNGDBehaviour.SetNGDNewtonCollisions
2039
  (const Value: TNGDNewtonCollisions);
2040
begin
2041
  FNGDNewtonCollisions := Value;
2042
  if Assigned(FManager) then
2043
    UpdCollision;
2044
end;
2045

2046
procedure TGLNGDBehaviour.SetNGDSurfaceItem(const Value: TNGDSurfaceItem);
2047
begin
2048
  FNGDSurfaceItem := Value;
2049
  FManager.RebuildAllMaterial;
2050
end;
2051

2052
function TGLNGDBehaviour.StoredTolerance: Boolean;
2053
begin
2054
  Result := not SameValue(FConvexCollisionTolerance, 0.01, epsilon);
2055
end;
2056

2057
class function TGLNGDBehaviour.UniqueItem: Boolean;
2058
begin
2059
  Result := True;
2060
end;
2061

2062
procedure TGLNGDBehaviour.ReadFromFiler(reader: TReader);
2063
var
2064
  version: Integer;
2065
begin
2066
  inherited;
2067
  with reader do
2068
  begin
2069
    version := ReadInteger; // read data version
2070
    Assert(version <= 1); // Archive version
2071

2072
    FManagerName := ReadString;
2073
    FContinuousCollisionMode := ReadBoolean;
2074
    read(FNGDNewtonCollisions, SizeOf(TNGDNewtonCollisions));
2075
    FTreeCollisionOptimize := ReadBoolean;
2076
    if version <= 0 then
2077
      FConvexCollisionTolerance := ReadSingle
2078
    else
2079
      FConvexCollisionTolerance := ReadFloat;
2080
    FFileCollision := ReadString;
2081
  end;
2082
end;
2083

2084
procedure TGLNGDBehaviour.WriteToFiler(writer: TWriter);
2085
begin
2086
  inherited;
2087
  with writer do
2088
  begin
2089
    WriteInteger(1); // Archive version
2090
    if Assigned(FManager) then
2091
      WriteString(FManager.GetNamePath)
2092
    else
2093
      WriteString('');
2094
    WriteBoolean(FContinuousCollisionMode);
2095
    write(FNGDNewtonCollisions, SizeOf(TNGDNewtonCollisions));
2096
    WriteBoolean(FTreeCollisionOptimize);
2097
    WriteFloat(FConvexCollisionTolerance);
2098
    WriteString(FFileCollision);
2099
  end;
2100
end;
2101

2102
procedure TGLNGDBehaviour.Serialize(filename: string);
2103
var
2104
  MyFile: TFileStream;
2105
begin
2106
  MyFile := TFileStream.Create(filename, fmCreate or fmOpenReadWrite);
2107

2108
  NewtonCollisionSerialize(FManager.FNewtonWorld, FCollision,
2109
    @TGLNGDBehaviour.NewtonSerialize, Pointer(MyFile));
2110

2111
  MyFile.Free;
2112
end;
2113

2114
procedure TGLNGDBehaviour.DeSerialize(filename: string);
2115
var
2116
  MyFile: TFileStream;
2117
  collisionInfoRecord: TNewtonCollisionInfoRecord;
2118
begin
2119
  MyFile := TFileStream.Create(filename, fmOpenRead);
2120

2121
  FCollision := NewtonCreateCollisionFromSerialization(FManager.FNewtonWorld,
2122
    @TGLNGDBehaviour.NewtonDeserialize, Pointer(MyFile));
2123

2124
  // SetCollision;
2125
  NewtonBodySetCollision(FNewtonBody, FCollision);
2126

2127
  // Release collision
2128
  NewtonCollisionGetInfo(FCollision, @collisionInfoRecord);
2129
  if collisionInfoRecord.m_referenceCount > 2 then
2130
    NewtonReleaseCollision(FManager.FNewtonWorld, FCollision);
2131

2132
  MyFile.Free;
2133
end;
2134

2135
{ TGLNGDDynamic }
2136

2137
procedure TGLNGDDynamic.AddImpulse(const veloc, pointposit: TVector);
2138
begin
2139
  if Assigned(FNewtonBody) then
2140
    NewtonBodyAddImpulse(FNewtonBody, @veloc, @pointposit);
2141
end;
2142

2143
constructor TGLNGDDynamic.Create(AOwner: TGLXCollection);
2144
begin
2145
  inherited;
2146
  FAutoSleep := True;
2147
  FLinearDamping := 0.1;
2148
  FAngularDamping := TGLCoordinates.CreateInitialized(self,
2149
    VectorMake(0.1, 0.1, 0.1, 0), csPoint);
2150
  FAngularDamping.OnNotifyChange := NotifyAngularDampingChange;
2151
  FDensity := 1;
2152
  FVolume := 1;
2153
  FForce := TGLCoordinates.CreateInitialized(self, NullHmgVector, csVector);
2154
  FTorque := TGLCoordinates.CreateInitialized(self, NullHmgVector, csVector);
2155
  FCenterOfMass := TGLCoordinates.CreateInitialized(self, NullHmgVector,
2156
    csPoint);
2157
  FCenterOfMass.OnNotifyChange := NotifyCenterOfMassChange;
2158
  FAABBmin := TGLCoordinates.CreateInitialized(self, NullHmgVector, csPoint);
2159
  FAABBmax := TGLCoordinates.CreateInitialized(self, NullHmgVector, csPoint);
2160
  FAppliedOmega := TGLCoordinates.CreateInitialized(self, NullHmgVector,
2161
    csVector);
2162
  FAppliedVelocity := TGLCoordinates.CreateInitialized(self, NullHmgVector,
2163
    csVector);
2164
  FAppliedForce := TGLCoordinates.CreateInitialized(self, NullHmgVector,
2165
    csVector);
2166
  FAppliedTorque := TGLCoordinates.CreateInitialized(self, NullHmgVector,
2167
    csVector);
2168
  FUseGravity := True;
2169
  FNullCollisionVolume := 0;
2170

2171
  FApplyForceAndTorqueEvent := OnApplyForceAndTorqueEvent;
2172
  FSetTransformEvent := OnSetTransformEvent;
2173
  name := 'NGD Dynamic'
2174
end;
2175

2176
destructor TGLNGDDynamic.Destroy;
2177
begin
2178
  // Clean up everything
2179
  FAngularDamping.Free;
2180
  FForce.Free;
2181
  FTorque.Free;
2182
  FCenterOfMass.Free;
2183
  FAABBmin.Free;
2184
  FAABBmax.Free;
2185
  FAppliedForce.Free;
2186
  FAppliedTorque.Free;
2187
  FAppliedVelocity.Free;
2188
  FAppliedOmega.Free;
2189
  inherited;
2190
end;
2191

2192
procedure TGLNGDDynamic.Finalize;
2193
begin
2194
  if not(csDesigning in FOwnerBaseSceneObject.ComponentState) then
2195
    if Assigned(FManager) then
2196
    begin
2197
      // Removing Callback
2198
      NewtonBodySetForceAndTorqueCallback(FNewtonBody, nil);
2199
      NewtonBodySetTransformCallback(FNewtonBody, nil);
2200
    end;
2201
  inherited;
2202
end;
2203

2204
class function TGLNGDDynamic.FriendlyName: string;
2205
begin
2206
  Result := 'NGD Dynamic';
2207
end;
2208

2209

2210
procedure TGLNGDDynamic.Initialize;
2211
begin
2212
  inherited;
2213
  if not(csDesigning in FOwnerBaseSceneObject.ComponentState) then
2214
    if Assigned(FManager) then
2215
    begin
2216
      // Set Density, Mass and inertie matrix
2217
      SetDensity(FDensity);
2218

2219
      // Set Callback
2220
      NewtonBodySetForceAndTorqueCallback(FNewtonBody,
2221
        @TGLNGDDynamic.NewtonApplyForceAndTorque);
2222
      NewtonBodySetTransformCallback(FNewtonBody,
2223
        @TGLNGDDynamic.NewtonSetTransform);
2224
    end;
2225
end;
2226

2227
procedure TGLNGDDynamic.Render;
2228

2229
  procedure DrawAABB(min, max: TGLCoordinates3);
2230
  begin
2231

2232
    {
2233
      //    H________G
2234
      //   /.       /|
2235
      //  / .      / |
2236
      // D__._____C  |
2237
      // |  .     |  |
2238
      // | E.-----|--F
2239
      // | .      | /
2240
      // |.       |/
2241
      // A________B
2242
      }
2243
    // Back
2244
    FManager.AddNode(min.X, min.Y, min.Z); // E
2245
    FManager.AddNode(max.X, min.Y, min.Z); // F
2246

2247
    FManager.AddNode(max.X, min.Y, min.Z); // F
2248
    FManager.AddNode(max.X, max.Y, min.Z); // G
2249

2250
    FManager.AddNode(max.X, max.Y, min.Z); // G
2251
    FManager.AddNode(min.X, max.Y, min.Z); // H
2252

2253
    FManager.AddNode(min.X, max.Y, min.Z); // H
2254
    FManager.AddNode(min.X, min.Y, min.Z); // E
2255

2256
    // Front
2257
    FManager.AddNode(min.X, min.Y, max.Z); // A
2258
    FManager.AddNode(max.X, min.Y, max.Z); // B
2259

2260
    FManager.AddNode(max.X, min.Y, max.Z); // B
2261
    FManager.AddNode(max.X, max.Y, max.Z); // C
2262

2263
    FManager.AddNode(max.X, max.Y, max.Z); // C
2264
    FManager.AddNode(min.X, max.Y, max.Z); // D
2265

2266
    FManager.AddNode(min.X, max.Y, max.Z); // D
2267
    FManager.AddNode(min.X, min.Y, max.Z); // A
2268

2269
    // Edges
2270
    FManager.AddNode(min.X, min.Y, max.Z); // A
2271
    FManager.AddNode(min.X, min.Y, min.Z); // E
2272

2273
    FManager.AddNode(max.X, min.Y, max.Z); // B
2274
    FManager.AddNode(max.X, min.Y, min.Z); // F
2275

2276
    FManager.AddNode(max.X, max.Y, max.Z); // C
2277
    FManager.AddNode(max.X, max.Y, min.Z); // G
2278

2279
    FManager.AddNode(min.X, max.Y, max.Z); // D
2280
    FManager.AddNode(min.X, max.Y, min.Z); // H
2281
  end;
2282

2283
  procedure DrawContact;
2284
  var
2285
    cnt: PNewtonJoint;
2286
    thisContact: PNewtonJoint;
2287
    material: PNewtonMaterial;
2288
    pos, nor: TVector;
2289
  begin
2290
    FManager.FCurrentColor := FManager.DebugOption.ContactColor;
2291
    cnt := NewtonBodyGetFirstContactJoint(FNewtonBody);
2292
    while cnt <> nil do
2293
    begin
2294
      thisContact := NewtonContactJointGetFirstContact(cnt);
2295
      while thisContact <> nil do
2296
      begin
2297
        material := NewtonContactGetMaterial(thisContact);
2298
        NewtonMaterialGetContactPositionAndNormal(material, FNewtonBody, @pos, @nor);
2299

2300
        FManager.AddNode(pos);
2301
        nor := VectorAdd(pos, nor);
2302
        FManager.AddNode(nor);
2303

2304
        thisContact := NewtonContactJointGetNextContact(cnt, thisContact);
2305
      end;
2306
      cnt := NewtonBodyGetNextContactJoint(FNewtonBody, cnt);
2307
    end;
2308
  end;
2309

2310
  function GetAbsCom(): TVector;
2311
  var
2312
    M: TMatrix;
2313
  begin
2314
    NewtonBodyGetCentreOfMass(FNewtonBody, @Result);
2315
    M := IdentityHmgMatrix;
2316
    M.V[3] := Result;
2317
    M.V[3].V[3] := 1;
2318
    M := MatrixMultiply(M, FOwnerBaseSceneObject.AbsoluteMatrix);
2319
    Result := M.V[3];
2320
  end;
2321

2322
  procedure DrawForce;
2323
  var
2324
    pos: TVector;
2325
    nor: TVector;
2326
  begin
2327
    pos := GetAbsCom;
2328

2329
    if mdShowForce in FManager.DebugOption.NGDManagerDebugs then
2330
    begin
2331
      FManager.FCurrentColor := FManager.DebugOption.ForceColor;
2332
      nor := VectorAdd(pos, FForce.AsVector);
2333
      FManager.AddNode(pos);
2334
      FManager.AddNode(nor);
2335
    end;
2336

2337
    if mdShowAppliedForce in FManager.DebugOption.NGDManagerDebugs then
2338
    begin
2339
      FManager.FCurrentColor := FManager.DebugOption.AppliedForceColor;
2340
      nor := VectorAdd(pos, FAppliedForce.AsVector);
2341
      FManager.AddNode(pos);
2342
      FManager.AddNode(nor);
2343

2344
    end;
2345

2346
    if mdShowAppliedVelocity in FManager.DebugOption.NGDManagerDebugs then
2347
    begin
2348
      FManager.FCurrentColor := FManager.DebugOption.AppliedVelocityColor;
2349
      nor := VectorAdd(pos, FAppliedVelocity.AsVector);
2350
      FManager.AddNode(pos);
2351
      FManager.AddNode(nor);
2352
    end;
2353

2354
  end;
2355

2356
  procedure DrawCoM;
2357
  var
2358
    com: TVector;
2359
    size: Single;
2360
  begin
2361
    FManager.FCurrentColor := FManager.DebugOption.CenterOfMassColor;
2362
    size := FManager.DebugOption.DotAxisSize;
2363
    com := GetAbsCom;
2364
    FManager.AddNode(VectorAdd(com, VectorMake(0, 0, size)));
2365
    FManager.AddNode(VectorAdd(com, VectorMake(0, 0, -size)));
2366
    FManager.AddNode(VectorAdd(com, VectorMake(0, size, 0)));
2367
    FManager.AddNode(VectorAdd(com, VectorMake(0, -size, 0)));
2368
    FManager.AddNode(VectorAdd(com, VectorMake(size, 0, 0)));
2369
    FManager.AddNode(VectorAdd(com, VectorMake(-size, 0, 0)));
2370
  end;
2371

2372
begin
2373
  inherited;
2374

2375
  // Move/Rotate NewtonObject if matrix are not equal in design time.
2376
  if (csDesigning in FOwnerBaseSceneObject.ComponentState) then
2377
    if not MatrixEquals(NewtonBodyMatrix, FOwnerBaseSceneObject.AbsoluteMatrix)
2378
      then
2379
      SetNewtonBodyMatrix(FOwnerBaseSceneObject.AbsoluteMatrix);
2380

2381
  NewtonBodyGetAABB(FNewtonBody, @(FAABBmin.AsVector), @(FAABBmax.AsVector));
2382

2383
  if NewtonBodyGetSleepState(FNewtonBody) = 1 then
2384
    FManager.FCurrentColor := FManager.DebugOption.AABBColorSleep
2385
  else
2386
    FManager.FCurrentColor := FManager.DebugOption.AABBColor;
2387

2388
  if mdShowAABB in FManager.DebugOption.NGDManagerDebugs then
2389
    DrawAABB(FAABBmin, FAABBmax);
2390

2391
  if mdShowContact in FManager.DebugOption.NGDManagerDebugs then
2392
    DrawContact;
2393

2394
  DrawForce; // Draw Force, AppliedForce and AppliedVelocity
2395

2396
  if mdShowCenterOfMass in FManager.DebugOption.NGDManagerDebugs then
2397
    DrawCoM;
2398
end;
2399

2400
procedure TGLNGDDynamic.SetAutoSleep(const Value: Boolean);
2401
begin
2402
  FAutoSleep := Value;
2403
  if not(csDesigning in FOwnerBaseSceneObject.ComponentState) then
2404
    if Assigned(FManager) then
2405
      NewtonBodySetAutoSleep(FNewtonBody, Ord(FAutoSleep));
2406
end;
2407

2408
procedure TGLNGDDynamic.SetDensity(const Value: Single);
2409
var
2410
  inertia: TVector;
2411
  origin: TVector;
2412
begin
2413
  if Assigned(FManager) then
2414
    if Value >= 0 then
2415
    begin
2416
      FDensity := Value;
2417

2418
      FVolume := NewtonConvexCollisionCalculateVolume(FCollision);
2419
      NewtonConvexCollisionCalculateInertialMatrix(FCollision, @inertia,
2420
        @origin);
2421

2422
      if IsZero(FVolume, epsilon) then
2423
      begin
2424
        FVolume := FNullCollisionVolume;
2425
        inertia := VectorMake(FNullCollisionVolume, FNullCollisionVolume,
2426
          FNullCollisionVolume, 0);
2427
      end;
2428

2429
      FMass := FVolume * FDensity;
2430

2431
      if not(csDesigning in FOwnerBaseSceneObject.ComponentState) then
2432
        NewtonBodySetMassMatrix(FNewtonBody, FMass, FMass * inertia.V[0],
2433
          FMass * inertia.V[1], FMass * inertia.V[2]);
2434

2435
      FCenterOfMass.AsVector := origin;
2436
    end;
2437
end;
2438

2439
procedure TGLNGDDynamic.SetLinearDamping(const Value: Single);
2440
begin
2441
  if (Value >= 0) and (Value <= 1) then
2442
    FLinearDamping := Value;
2443
  if not(csDesigning in FOwnerBaseSceneObject.ComponentState) then
2444
    if Assigned(FManager) then
2445
      NewtonBodySetLinearDamping(FNewtonBody, FLinearDamping);
2446
end;
2447

2448
function TGLNGDDynamic.GetOmega: TVector;
2449
begin
2450
  NewtonBodyGetOmega(FNewtonBody, @Result);
2451
end;
2452

2453
procedure TGLNGDDynamic.SetOmega(const Omega: TVector);
2454
begin
2455
  NewtonBodySetOmega(FNewtonBody, @Omega);
2456
end;
2457

2458
function TGLNGDDynamic.GetVelocity: TVector;
2459
begin
2460
  NewtonBodyGetVelocity(FNewtonBody, @Result);
2461
end;
2462

2463
procedure TGLNGDDynamic.SetVelocity(const Velocity: TVector);
2464
begin
2465
  NewtonBodySetVelocity(FNewtonBody, @Velocity);
2466
end;
2467

2468
function TGLNGDDynamic.StoredDensity: Boolean;
2469
begin
2470
  Result := not SameValue(FDensity, 1, epsilon);
2471
end;
2472

2473
function TGLNGDDynamic.StoredLinearDamping: Boolean;
2474
begin
2475
  Result := not SameValue(FLinearDamping, 0.1, epsilon);
2476
end;
2477

2478
function TGLNGDDynamic.StoredNullCollisionVolume: Boolean;
2479
begin
2480
  Result := not SameValue(FNullCollisionVolume, 0, epsilon);
2481
end;
2482

2483
// WriteToFiler
2484
//
2485
procedure TGLNGDDynamic.WriteToFiler(writer: TWriter);
2486
begin
2487
  inherited;
2488
  with writer do
2489
  begin
2490
    WriteInteger(1); // Archive version
2491
    WriteBoolean(FAutoSleep);
2492
    WriteFloat(FLinearDamping);
2493
    WriteFloat(FDensity);
2494
    WriteBoolean(FUseGravity);
2495
    WriteFloat(FNullCollisionVolume);
2496
  end;
2497
  FForce.WriteToFiler(writer);
2498
  FTorque.WriteToFiler(writer);
2499
  FCenterOfMass.WriteToFiler(writer);
2500
  FAngularDamping.WriteToFiler(writer);
2501
end;
2502

2503
// ReadFromFiler
2504
//
2505
procedure TGLNGDDynamic.ReadFromFiler(reader: TReader);
2506
var
2507
  version: Integer;
2508
begin
2509
  inherited;
2510
  with reader do
2511
  begin
2512
    version := ReadInteger; // read data version
2513
    Assert(version <= 1); // Archive version
2514

2515
    FAutoSleep := ReadBoolean;
2516
    if version <= 0 then
2517
      FLinearDamping := ReadSingle
2518
    else
2519
      FLinearDamping := ReadFloat;
2520
    if version <= 0 then
2521
      FDensity := ReadSingle
2522
    else
2523
      FDensity := ReadFloat;
2524

2525
    // if Version >= 1 then
2526
    FUseGravity := ReadBoolean;
2527

2528
    if version <= 0 then
2529
      FNullCollisionVolume := ReadSingle
2530
    else
2531
      FNullCollisionVolume := ReadFloat;
2532

2533
  end;
2534
  FForce.ReadFromFiler(reader);
2535
  FTorque.ReadFromFiler(reader);
2536
  FCenterOfMass.ReadFromFiler(reader);
2537
  FAngularDamping.ReadFromFiler(reader);
2538
end;
2539

2540
procedure TGLNGDDynamic.Loaded;
2541
begin
2542
  inherited;
2543
  if Assigned(FManager) then
2544
  begin
2545
    SetAutoSleep(FAutoSleep);
2546
    SetLinearDamping(FLinearDamping);
2547
    SetDensity(FDensity);
2548
    NotifyCenterOfMassChange(self);
2549
    NotifyAngularDampingChange(self);
2550
  end;
2551
end;
2552

2553
class procedure TGLNGDDynamic.NewtonApplyForceAndTorque
2554
  (const body: PNewtonBody; timestep: NGDFloat; threadIndex: Integer); cdecl; static;
2555
begin
2556
  TGLNGDDynamic(NewtonBodyGetUserData(body)).FApplyForceAndTorqueEvent(body,
2557
    timestep, threadIndex);
2558
end;
2559

2560
class procedure TGLNGDDynamic.NewtonSetTransform(const body: PNewtonBody;
2561
  const matrix: PNGDFloat; threadIndex: Integer); cdecl; static;
2562
begin
2563
  TGLNGDDynamic(NewtonBodyGetUserData(body)).FSetTransformEvent(body, matrix,
2564
    threadIndex);
2565
end;
2566

2567
procedure TGLNGDDynamic.NotifyAngularDampingChange(Sender: TObject);
2568
begin
2569
  FAngularDamping.OnNotifyChange := nil;
2570
  if (FAngularDamping.X >= 0) and (FAngularDamping.X <= 1) and
2571
    (FAngularDamping.Y >= 0) and (FAngularDamping.Y <= 1) and
2572
    (FAngularDamping.Z >= 0) and (FAngularDamping.Z <= 1) then
2573
    if Assigned(FManager) then
2574
      NewtonBodySetAngularDamping(FNewtonBody, @(FAngularDamping.AsVector));
2575
  FAngularDamping.OnNotifyChange := NotifyAngularDampingChange;
2576
end;
2577

2578
procedure TGLNGDDynamic.NotifyCenterOfMassChange(Sender: TObject);
2579
begin
2580
  FCenterOfMass.OnNotifyChange := nil;
2581
  if Assigned(FManager) then
2582
    NewtonBodySetCentreOfMass(FNewtonBody, @(FCenterOfMass.AsVector));
2583
  FCenterOfMass.OnNotifyChange := NotifyCenterOfMassChange;
2584
end;
2585

2586
procedure TGLNGDDynamic.OnApplyForceAndTorqueEvent(const cbody: PNewtonBody;
2587
  timestep: NGDFloat; threadIndex: Integer);
2588
var
2589
  worldGravity: TVector;
2590
begin
2591

2592
  // Read Only: We get the force and torque resulting from every interaction on this body
2593
  NewtonBodyGetForce(cbody, @(FAppliedForce.AsVector));
2594
  NewtonBodyGetTorque(cbody, @(FAppliedTorque.AsVector));
2595

2596
  NewtonBodyGetVelocity(cbody, @(FAppliedVelocity.AsVector));
2597
  NewtonBodyGetOmega(cbody, @(FAppliedOmega.AsVector));
2598

2599
  // Raise Custom event
2600
  if Assigned(FCustomForceAndTorqueEvent) then
2601
    FCustomForceAndTorqueEvent(cbody, timestep, threadIndex)
2602
  else
2603
  begin
2604
    NewtonBodySetForce(cbody, @(Force.AsVector));
2605
    NewtonBodySetTorque(cbody, @(Torque.AsVector));
2606

2607
    // Add Gravity from World
2608
    if FUseGravity then
2609
    begin
2610
      worldGravity := VectorScale(FManager.Gravity.AsVector, FMass);
2611
      NewtonBodyAddForce(cbody, @(worldGravity));
2612
    end;
2613
  end;
2614

2615
end;
2616

2617
procedure TGLNGDDynamic.OnSetTransformEvent(const cbody: PNewtonBody;
2618
  const cmatrix: PNGDFloat; threadIndex: Integer);
2619
var
2620
  epsi: Single;
2621
begin
2622
  // The Newton API does not support scale [scale modifie value in matrix],
2623
  // so this line reset scale of the glsceneObject to (1,1,1)
2624
  // to avoid crashing the application
2625
  epsi := 0.0001;
2626
  with FOwnerBaseSceneObject do
2627
    if not SameValue(Scale.X, 1.0, epsi) or not SameValue(Scale.Y, 1.0, epsi)
2628
      or not SameValue(Scale.Z, 1.0, epsi) then
2629
    begin
2630
      Scale.SetVector(1, 1, 1);
2631
      SetNewtonBodyMatrix(AbsoluteMatrix);
2632
    end
2633
    else
2634
      // Make the Position and orientation of the glscene-Object relative to the
2635
      // NewtonBody position and orientation.
2636
      FOwnerBaseSceneObject.AbsoluteMatrix := pMatrix(cmatrix)^;
2637
end;
2638

2639
{ TGLNGDStatic }
2640

2641
procedure TGLNGDStatic.Render;
2642
begin
2643
  inherited;
2644
  // Move/Rotate NewtonObject if matrix are not equal in run time.
2645
  if not MatrixEquals(NewtonBodyMatrix, FOwnerBaseSceneObject.AbsoluteMatrix)
2646
    then
2647
    SetNewtonBodyMatrix(FOwnerBaseSceneObject.AbsoluteMatrix);
2648

2649
end;
2650

2651
class function TGLNGDStatic.FriendlyName: string;
2652
begin
2653
  Result := 'NGD Static';
2654
end;
2655

2656
{ TNGDSurfaceItem }
2657

2658
function TNGDSurfaceItem.GetDisplayName: string;
2659
begin
2660
  if FDisplayName = '' then
2661
    FDisplayName := 'Iron';
2662
  Result := FDisplayName;
2663
end;
2664

2665
procedure TNGDSurfaceItem.SetDisplayName(const Value: string);
2666
begin
2667
  inherited;
2668
  FDisplayName := Value;
2669
end;
2670

2671
{ TNGDSurfacePair }
2672

2673
constructor TNGDSurfacePair.Create(Collection: TCollection);
2674
begin
2675
  inherited;
2676
  FSoftness := 0.1;
2677
  FElasticity := 0.4;
2678
  FCollidable := True;
2679
  FStaticFriction := 0.9;
2680
  FKineticFriction := 0.5;
2681
  FContinuousCollisionMode := False;
2682
  FThickness := False;
2683

2684
  FAABBOverlapEvent := OnNewtonAABBOverlapEvent;
2685
  FContactProcessEvent := OnNewtonContactsProcessEvent;
2686
  FManager := TGLNGDManager(Collection.Owner);
2687
  FManager.RebuildAllMaterial;
2688
end;
2689

2690
class function TNGDSurfacePair.NewtonAABBOverlap
2691
  (const material: PNewtonMaterial;
2692
  const body0, body1: PNewtonBody; threadIndex: Integer): Integer; cdecl; static;
2693
begin
2694
  Result := Ord(TNGDSurfacePair(NewtonMaterialGetMaterialPairUserData(material))
2695
      .FAABBOverlapEvent(material, body0, body1, threadIndex));
2696
end;
2697

2698
class procedure TNGDSurfacePair.NewtonContactsProcess
2699
  (const contact: PNewtonJoint; timestep: NGDFloat; threadIndex: Integer); cdecl; static;
2700
begin
2701
  TNGDSurfacePair(NewtonMaterialGetMaterialPairUserData
2702
   (NewtonContactGetMaterial
2703
     (NewtonContactJointGetFirstContact(contact)))).FContactProcessEvent
2704
	    (contact, timestep, threadIndex);
2705
end;
2706

2707
function TNGDSurfacePair.OnNewtonAABBOverlapEvent
2708
  (const cmaterial: PNewtonMaterial; const cbody0, cbody1: PNewtonBody;
2709
  threadIndex: Integer): Boolean;
2710
begin
2711
  Result := True;
2712
end;
2713

2714
procedure TNGDSurfacePair.OnNewtonContactsProcessEvent
2715
  (const ccontact: PNewtonJoint; timestep: NGDFloat; threadIndex: Integer);
2716
begin
2717

2718
end;
2719

2720
procedure TNGDSurfacePair.SetCollidable(const Value: Boolean);
2721
begin
2722
  FCollidable := Value;
2723
  FManager.RebuildAllMaterial;
2724
end;
2725

2726
procedure TNGDSurfacePair.SetContinuousCollisionMode(const Value: Boolean);
2727
begin
2728
  FContinuousCollisionMode := Value;
2729
  FManager.RebuildAllMaterial;
2730
end;
2731

2732
procedure TNGDSurfacePair.SetElasticity(const Value: Single);
2733
begin
2734
  if (Value >= 0) then
2735
    FElasticity := Value;
2736
  FManager.RebuildAllMaterial;
2737
end;
2738

2739
procedure TNGDSurfacePair.SetKineticFriction(const Value: Single);
2740
begin
2741
  if (Value >= 0) and (Value <= 1) then
2742
    FKineticFriction := Value;
2743
  FManager.RebuildAllMaterial;
2744
end;
2745

2746
procedure TNGDSurfacePair.SetMaterialItems(const item1, item2: TNGDSurfaceItem);
2747
begin
2748
  FNGDSurfaceItem1 := item1;
2749
  FNGDSurfaceItem2 := item2;
2750
  FManager.RebuildAllMaterial;
2751
end;
2752

2753
procedure TNGDSurfacePair.SetSoftness(const Value: Single);
2754
begin
2755
  if (Value >= 0) and (Value <= 1) then
2756
    FSoftness := Value;
2757
  FManager.RebuildAllMaterial;
2758
end;
2759

2760
procedure TNGDSurfacePair.SetStaticFriction(const Value: Single);
2761
begin
2762
  if (Value >= 0) and (Value <= 1) then
2763
    FStaticFriction := Value;
2764
  FManager.RebuildAllMaterial;
2765
end;
2766

2767
procedure TNGDSurfacePair.SetThickness(const Value: Boolean);
2768
begin
2769
  FThickness := Value;
2770
  FManager.RebuildAllMaterial;
2771
end;
2772

2773
function TNGDSurfacePair.StoredElasticity: Boolean;
2774
begin
2775
  Result := not SameValue(FElasticity, 0.4, epsilon);
2776
end;
2777

2778
function TNGDSurfacePair.StoredKineticFriction: Boolean;
2779
begin
2780
  Result := not SameValue(FKineticFriction, 0.5, epsilon);
2781
end;
2782

2783
function TNGDSurfacePair.StoredSoftness: Boolean;
2784
begin
2785
  Result := not SameValue(FSoftness, 0.1, epsilon);
2786
end;
2787

2788
function TNGDSurfacePair.StoredStaticFriction: Boolean;
2789
begin
2790
  Result := not SameValue(FStaticFriction, 0.9, epsilon);
2791
end;
2792

2793
{ TNGDJoint }
2794

2795
constructor TNGDJoint.Create(Collection: TCollection);
2796
begin
2797
  inherited;
2798
  FCollisionState := False;
2799
  FStiffness := 0.9;
2800
  FNewtonJoint := nil;
2801
  FNewtonUserJoint := nil;
2802
  FParentObject := nil;
2803
  FChildObject := nil;
2804

2805
  FManager := TGLNGDManager(Collection.Owner);
2806

2807
  FBallAndSocketOptions := TNGDJointPivot.Create(FManager, self);
2808
  FHingeOptions := TNGDJointPin.Create(FManager, self);
2809
  FSliderOptions := TNGDJointPin.Create(FManager, self);
2810
  FCorkscrewOptions := TNGDJointPin.Create(FManager, self);
2811
  FUniversalOptions := TNGDJointPin2.Create(FManager, self);
2812

2813
  FCustomBallAndSocketOptions := TNGDJointBallAndSocket.Create(FManager, self);
2814
  FCustomHingeOptions := TNGDJointHinge.Create(FManager, self);
2815
  FCustomSliderOptions := TNGDJointSlider.Create(FManager, self);
2816
  FKinematicOptions := TNGDJointKinematicController.Create;
2817

2818
  FUPVectorDirection := TGLCoordinates.CreateInitialized(self, YHmgVector,
2819
    csVector);
2820
  FUPVectorDirection.OnNotifyChange := FManager.RebuildAllJoint;
2821
end;
2822

2823
destructor TNGDJoint.Destroy;
2824
begin
2825
  DestroyNewtonData;
2826

2827
  FParentObject := nil;
2828
  FChildObject := nil;
2829

2830
  // Free options
2831
  FBallAndSocketOptions.Free;
2832
  FHingeOptions.Free;
2833
  FSliderOptions.Free;
2834
  FCorkscrewOptions.Free;
2835
  FUniversalOptions.Free;
2836

2837
  FCustomBallAndSocketOptions.Free;
2838
  FCustomHingeOptions.Free;
2839
  FCustomSliderOptions.Free;
2840
  FKinematicOptions.Free;
2841
  FUPVectorDirection.Free;
2842
  inherited;
2843
end;
2844

2845
procedure TNGDJoint.DestroyNewtonData;
2846
begin
2847
  if FNewtonJoint <> nil then
2848
  begin
2849
    Assert((FManager <> nil) and (FManager.FNewtonWorld <> nil));
2850
    NewtonDestroyJoint(FManager.FNewtonWorld, FNewtonJoint);
2851
    FNewtonJoint := nil;
2852
  end;
2853
  if FNewtonUserJoint <> nil then
2854
  begin
2855
    CustomDestroyJoint(FNewtonUserJoint);
2856
    FNewtonUserJoint := nil;
2857
  end;
2858
end;
2859

2860
procedure TNGDJoint.KinematicControllerPick(pickpoint: TVector;
2861
  PickedActions: TNGDPickedActions);
2862
begin
2863
  if FJointType = nj_KinematicController then
2864
    if Assigned(FParentObject) then
2865
    begin
2866
      // Create the joint
2867
      if PickedActions = paAttach then
2868
      begin
2869
        if not Assigned(FNewtonUserJoint) then
2870
          if Assigned(GetNGDDynamic(FParentObject).FNewtonBody) then
2871
            FNewtonUserJoint := CreateCustomKinematicController
2872
              (GetNGDDynamic(FParentObject).FNewtonBody, @pickpoint);
2873
      end;
2874

2875
      // Change the TargetPoint
2876
      if (PickedActions = paMove) or (PickedActions = paAttach) then
2877
      begin
2878
        if Assigned(FNewtonUserJoint) then
2879
        begin
2880
          CustomKinematicControllerSetPickMode(FNewtonUserJoint,
2881
            Ord(FKinematicOptions.FPickModeLinear));
2882
          CustomKinematicControllerSetMaxLinearFriction(FNewtonUserJoint,
2883
            FKinematicOptions.FLinearFriction);
2884
          CustomKinematicControllerSetMaxAngularFriction(FNewtonUserJoint,
2885
            FKinematicOptions.FAngularFriction);
2886
          CustomKinematicControllerSetTargetPosit(FNewtonUserJoint, @pickpoint);
2887
        end;
2888
      end;
2889

2890
      // Delete the joint
2891
      if PickedActions = paDetach then
2892
      begin
2893
        if Assigned(FNewtonUserJoint) then
2894
        begin
2895
          CustomDestroyJoint(FNewtonUserJoint);
2896
          FNewtonUserJoint := nil;
2897
          // Reset autosleep because this joint turns it off
2898
          NewtonBodySetAutoSleep(GetNGDDynamic(FParentObject).FNewtonBody,
2899
            Ord(GetNGDDynamic(FParentObject).AutoSleep));
2900
        end;
2901
        ParentObject := nil;
2902
      end;
2903
    end;
2904
end;
2905

2906
procedure TNGDJoint.Render;
2907

2908
  procedure DrawPivot(pivot: TVector);
2909
  var
2910
    size: Single;
2911
  begin
2912
    size := FManager.DebugOption.DotAxisSize;
2913
    FManager.FCurrentColor := FManager.DebugOption.JointPivotColor;
2914
    FManager.AddNode(VectorAdd(pivot, VectorMake(0, 0, size)));
2915
    FManager.AddNode(VectorAdd(pivot, VectorMake(0, 0, -size)));
2916
    FManager.AddNode(VectorAdd(pivot, VectorMake(0, size, 0)));
2917
    FManager.AddNode(VectorAdd(pivot, VectorMake(0, -size, 0)));
2918
    FManager.AddNode(VectorAdd(pivot, VectorMake(size, 0, 0)));
2919
    FManager.AddNode(VectorAdd(pivot, VectorMake(-size, 0, 0)));
2920
  end;
2921

2922
  procedure DrawPin(pin, pivot: TVector);
2923
  begin
2924
    FManager.FCurrentColor := FManager.DebugOption.JointAxisColor;
2925
    FManager.AddNode(VectorAdd(pivot, pin));
2926
    FManager.AddNode(VectorAdd(pivot, VectorNegate(pin)));
2927
  end;
2928

2929
  procedure DrawJoint(pivot: TVector);
2930
  begin
2931
    FManager.FCurrentColor := FManager.DebugOption.CustomColor;
2932
    FManager.AddNode(FParentObject.AbsolutePosition);
2933
    FManager.AddNode(pivot);
2934
    FManager.AddNode(pivot);
2935
    FManager.AddNode(FChildObject.AbsolutePosition);
2936
  end;
2937

2938
  procedure DrawKinematic;
2939
  var
2940
    pickedMatrix: TMatrix;
2941
    size: Single;
2942
  begin
2943
    size := FManager.DebugOption.DotAxisSize;
2944
    CustomKinematicControllerGetTargetMatrix(FNewtonUserJoint, @pickedMatrix);
2945
    FManager.FCurrentColor := FManager.DebugOption.JointAxisColor;
2946

2947
    FManager.AddNode(FParentObject.AbsolutePosition);
2948
    FManager.AddNode(pickedMatrix.V[3]);
2949

2950
    FManager.FCurrentColor := FManager.DebugOption.JointPivotColor;
2951
    FManager.AddNode(VectorAdd(pickedMatrix.V[3], VectorMake(0, 0, size)));
2952
    FManager.AddNode(VectorAdd(pickedMatrix.V[3], VectorMake(0, 0, -size)));
2953
    FManager.AddNode(VectorAdd(pickedMatrix.V[3], VectorMake(0, size, 0)));
2954
    FManager.AddNode(VectorAdd(pickedMatrix.V[3], VectorMake(0, -size, 0)));
2955
    FManager.AddNode(VectorAdd(pickedMatrix.V[3], VectorMake(size, 0, 0)));
2956
    FManager.AddNode(VectorAdd(pickedMatrix.V[3], VectorMake(-size, 0, 0)));
2957

2958
  end;
2959

2960
begin
2961

2962
  case FJointType of
2963
    nj_BallAndSocket:
2964
      if Assigned(FParentObject) and Assigned(FChildObject) then
2965
      begin
2966
        DrawJoint(FBallAndSocketOptions.FPivotPoint.AsVector);
2967
        DrawPivot(FBallAndSocketOptions.FPivotPoint.AsVector);
2968
      end;
2969

2970
    nj_Hinge:
2971
      if Assigned(FParentObject) and Assigned(FChildObject) then
2972
      begin
2973
        DrawJoint(FHingeOptions.FPivotPoint.AsVector);
2974
        DrawPin(FHingeOptions.FPinDirection.AsVector,
2975
          FHingeOptions.FPivotPoint.AsVector);
2976
        DrawPivot(FHingeOptions.FPivotPoint.AsVector);
2977
      end;
2978

2979
    nj_Slider:
2980
      if Assigned(FParentObject) and Assigned(FChildObject) then
2981
      begin
2982
        DrawJoint(FSliderOptions.FPivotPoint.AsVector);
2983
        DrawPin(FSliderOptions.FPinDirection.AsVector,
2984
          FSliderOptions.FPivotPoint.AsVector);
2985
        DrawPivot(FSliderOptions.FPivotPoint.AsVector);
2986
      end;
2987

2988
    nj_Corkscrew:
2989
      if Assigned(FParentObject) and Assigned(FChildObject) then
2990
      begin
2991
        DrawJoint(FCorkscrewOptions.FPivotPoint.AsVector);
2992
        DrawPin(FCorkscrewOptions.FPinDirection.AsVector,
2993
          FCorkscrewOptions.FPivotPoint.AsVector);
2994
        DrawPivot(FCorkscrewOptions.FPivotPoint.AsVector);
2995
      end;
2996

2997
    nj_Universal:
2998
      if Assigned(FParentObject) and Assigned(FChildObject) then
2999
      begin
3000
        DrawJoint(FUniversalOptions.FPivotPoint.AsVector);
3001
        DrawPin(FUniversalOptions.FPinDirection.AsVector,
3002
          FUniversalOptions.FPivotPoint.AsVector);
3003
        DrawPin(FUniversalOptions.FPinDirection2.AsVector,
3004
          FUniversalOptions.FPivotPoint.AsVector);
3005
        DrawPivot(FUniversalOptions.FPivotPoint.AsVector);
3006
      end;
3007

3008
    nj_CustomBallAndSocket:
3009
      if Assigned(FParentObject) and Assigned(FChildObject) then
3010
      begin
3011
        DrawJoint(FCustomBallAndSocketOptions.FPivotPoint.AsVector);
3012
        DrawPivot(FCustomBallAndSocketOptions.FPivotPoint.AsVector);
3013
      end;
3014

3015
    nj_CustomHinge:
3016
      if Assigned(FParentObject) and Assigned(FChildObject) then
3017
      begin
3018
        DrawJoint(FCustomHingeOptions.FPivotPoint.AsVector);
3019
        DrawPin(FCustomHingeOptions.FPinDirection.AsVector,
3020
          FCustomHingeOptions.FPivotPoint.AsVector);
3021
        DrawPivot(FCustomHingeOptions.FPivotPoint.AsVector);
3022
      end;
3023

3024
    nj_CustomSlider:
3025
      if Assigned(FParentObject) and Assigned(FChildObject) then
3026
      begin
3027
        DrawJoint(FCustomSliderOptions.FPivotPoint.AsVector);
3028
        DrawPin(FCustomSliderOptions.FPinDirection.AsVector,
3029
          FCustomSliderOptions.FPivotPoint.AsVector);
3030
        DrawPivot(FCustomSliderOptions.FPivotPoint.AsVector);
3031
      end;
3032

3033
    nj_UpVector:
3034
      if Assigned(FParentObject) then
3035
      begin // special
3036
        FManager.FCurrentColor := FManager.DebugOption.JointAxisColor;
3037
        FManager.AddNode(FParentObject.AbsolutePosition);
3038
        FManager.AddNode(VectorAdd(FParentObject.AbsolutePosition,
3039
            FUPVectorDirection.AsVector));
3040
      end;
3041

3042
    nj_KinematicController:
3043
      if Assigned(FParentObject) and Assigned(FNewtonUserJoint) then
3044
      begin // special
3045
        DrawKinematic;
3046
      end;
3047

3048
  end;
3049
end;
3050

3051
procedure TNGDJoint.SetChildObject(const Value: TGLBaseSceneObject);
3052
begin
3053
  FChildObject := Value;
3054
  FManager.RebuildAllJoint(self);
3055
end;
3056

3057
procedure TNGDJoint.SetCollisionState(const Value: Boolean);
3058
begin
3059
  FCollisionState := Value;
3060
  FManager.RebuildAllJoint(self);
3061
end;
3062

3063
procedure TNGDJoint.SetJointType(const Value: TNGDNewtonJoints);
3064
begin
3065
  FJointType := Value;
3066
  FManager.RebuildAllJoint(self);
3067
end;
3068

3069
procedure TNGDJoint.SetParentObject(const Value: TGLBaseSceneObject);
3070
begin
3071
  FParentObject := Value;
3072
  FManager.RebuildAllJoint(self);
3073
end;
3074

3075
procedure TNGDJoint.SetStiffness(const Value: Single);
3076
begin
3077
  if (Value >= 0) and (Value <= 1) then
3078
  begin
3079
    FStiffness := Value;
3080
    FManager.RebuildAllJoint(self);
3081
  end;
3082
end;
3083

3084
function TNGDJoint.StoredStiffness: Boolean;
3085
begin
3086
  Result := not SameValue(FStiffness, 0.9, epsilon);
3087
end;
3088

3089
{ TNGDJoint.TNGDJointPivot }
3090

3091
constructor TNGDJointPivot.Create(AOwner: TComponent; aOuter: TNGDJoint);
3092
begin
3093
  FManager := AOwner as TGLNGDManager;
3094
  FOuter := aOuter;
3095
  FPivotPoint := TGLCoordinates.CreateInitialized(aOuter, NullHMGPoint,
3096
    csPoint);
3097
  FPivotPoint.OnNotifyChange := FManager.RebuildAllJoint;
3098
end;
3099

3100
destructor TNGDJointPivot.Destroy;
3101
begin
3102
  FPivotPoint.Free;
3103
  inherited;
3104
end;
3105

3106
{ TNGDJoint.TNGDJointPin }
3107

3108
constructor TNGDJointPin.Create(AOwner: TComponent; aOuter: TNGDJoint);
3109
begin
3110
  inherited;
3111
  FPinDirection := TGLCoordinates.CreateInitialized(aOuter, NullHmgVector,
3112
    csVector);
3113
  FPinDirection.OnNotifyChange := FManager.RebuildAllJoint;
3114
end;
3115

3116
destructor TNGDJointPin.Destroy;
3117
begin
3118
  FPinDirection.Free;
3119
  inherited;
3120
end;
3121

3122
{ TNGDJoint.TNGDJointPin2 }
3123

3124
constructor TNGDJointPin2.Create(AOwner: TComponent; aOuter: TNGDJoint);
3125
begin
3126
  inherited;
3127
  FPinDirection2 := TGLCoordinates.CreateInitialized(aOuter, NullHmgVector,
3128
    csVector);
3129
  FPinDirection2.OnNotifyChange := FManager.RebuildAllJoint;
3130
end;
3131

3132
destructor TNGDJointPin2.Destroy;
3133
begin
3134
  FPinDirection2.Free;
3135
  inherited;
3136
end;
3137

3138
{ TNGDJoint.TNGDJointBallAndSocket }
3139

3140
constructor TNGDJointBallAndSocket.Create(AOwner: TComponent;
3141
  aOuter: TNGDJoint);
3142
begin
3143
  inherited;
3144
  FConeAngle := 90;
3145
  FMinTwistAngle := -90;
3146
  FMaxTwistAngle := 90;
3147
end;
3148

3149
procedure TNGDJointBallAndSocket.SetConeAngle(const Value: Single);
3150
begin
3151
  FConeAngle := Value;
3152
  FManager.RebuildAllJoint(FOuter);
3153
end;
3154

3155
procedure TNGDJointBallAndSocket.SetMaxTwistAngle(const Value: Single);
3156
begin
3157
  FMaxTwistAngle := Value;
3158
  FManager.RebuildAllJoint(FOuter);
3159
end;
3160

3161
procedure TNGDJointBallAndSocket.SetMinTwistAngle(const Value: Single);
3162
begin
3163
  FMinTwistAngle := Value;
3164
  FManager.RebuildAllJoint(FOuter);
3165
end;
3166

3167
function TNGDJointBallAndSocket.StoredConeAngle: Boolean;
3168
begin
3169
  Result := not SameValue(FConeAngle, 90, epsilon);
3170
end;
3171

3172
function TNGDJointBallAndSocket.StoredMaxTwistAngle: Boolean;
3173
begin
3174
  Result := not SameValue(FMaxTwistAngle, 90, epsilon);
3175
end;
3176

3177
function TNGDJointBallAndSocket.StoredMinTwistAngle: Boolean;
3178
begin
3179
  Result := not SameValue(FMinTwistAngle, -90, epsilon);
3180
end;
3181

3182
{ TNGDJoint.TNGDJointHinge }
3183

3184
constructor TNGDJointHinge.Create(AOwner: TComponent; aOuter: TNGDJoint);
3185
begin
3186
  inherited;
3187
  FMinAngle := -90;
3188
  FMaxAngle := 90;
3189
end;
3190

3191
procedure TNGDJointHinge.SetMaxAngle(const Value: Single);
3192
begin
3193
  FMaxAngle := Value;
3194
  FManager.RebuildAllJoint(FOuter);
3195
end;
3196

3197
procedure TNGDJointHinge.SetMinAngle(const Value: Single);
3198
begin
3199
  FMinAngle := Value;
3200
  FManager.RebuildAllJoint(FOuter);
3201
end;
3202

3203
function TNGDJointHinge.StoredMaxAngle: Boolean;
3204
begin
3205
  Result := not SameValue(FMaxAngle, 90, epsilon);
3206
end;
3207

3208
function TNGDJointHinge.StoredMinAngle: Boolean;
3209
begin
3210
  Result := not SameValue(FMinAngle, -90, epsilon);
3211
end;
3212

3213
{ TNGDJoint.TNGDJointSlider }
3214

3215

3216
constructor TNGDJointSlider.Create(AOwner: TComponent; aOuter: TNGDJoint);
3217
begin
3218
  inherited;
3219
  FMinDistance := -10;
3220
  FMaxDistance := 10;
3221
end;
3222

3223

3224
procedure TNGDJointSlider.SetMaxDistance(const Value: Single);
3225
begin
3226
  FMaxDistance := Value;
3227
  FManager.RebuildAllJoint(FOuter);
3228
end;
3229

3230
procedure TNGDJointSlider.SetMinDistance(const Value: Single);
3231
begin
3232
  FMinDistance := Value;
3233
  FManager.RebuildAllJoint(FOuter);
3234
end;
3235

3236

3237
function TNGDJointSlider.StoredMaxDistance: Boolean;
3238
begin
3239
  Result := not SameValue(FMaxDistance, 10, epsilon);
3240
end;
3241

3242
function TNGDJointSlider.StoredMinDistance: Boolean;
3243
begin
3244
  Result := not SameValue(FMinDistance, -10, epsilon);
3245
end;
3246

3247
{ TNGDJoint.TNGDJointKinematicController }
3248

3249
constructor TNGDJointKinematicController.Create;
3250
begin
3251
  FPickModeLinear := False;
3252
  FLinearFriction := 750;
3253
  FAngularFriction := 250;
3254
end;
3255

3256
function TNGDJointKinematicController.StoredAngularFriction: Boolean;
3257
begin
3258
  Result := not SameValue(FAngularFriction, 250, epsilon);
3259
end;
3260

3261
function TNGDJointKinematicController.StoredLinearFriction: Boolean;
3262
begin
3263
  Result := not SameValue(FLinearFriction, 750, epsilon);
3264
end;
3265

3266
{ TGLNGDBehaviourList }
3267

3268
function TGLNGDBehaviourList.GetBehav(index: Integer): TGLNGDBehaviour;
3269
begin
3270
  Result := Items[index];
3271
end;
3272

3273
procedure TGLNGDBehaviourList.PutBehav(index: Integer; Item: TGLNGDBehaviour);
3274
begin
3275
  inherited put(index, Item);
3276
end;
3277

3278
initialization
3279

3280
// ------------------------------------------------------------------
3281
// ------------------------------------------------------------------
3282
// ------------------------------------------------------------------
3283

3284
RegisterXCollectionItemClass(TGLNGDDynamic);
3285
RegisterXCollectionItemClass(TGLNGDStatic);
3286

3287
// ------------------------------------------------------------------
3288
// ------------------------------------------------------------------
3289
// ------------------------------------------------------------------
3290

3291
finalization
3292

3293
// ------------------------------------------------------------------
3294
// ------------------------------------------------------------------
3295
// ------------------------------------------------------------------
3296

3297
UnregisterXCollectionItemClass(TGLNGDDynamic);
3298
UnregisterXCollectionItemClass(TGLNGDStatic);
3299

3300
// CloseNGD;
3301

3302
end.
3303

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

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

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

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