2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Methods for turning a TGLBaseMesh into a Verlet cloth / jelly
8
16/09/10 - YP - Created public NodeList property of TFaceExtractor, it allow us to nail some vertex
9
23/08/10 - Yar - Added OpenGLTokens to uses, replaced OpenGL1x functions to OpenGLAdapter
10
06/06/10 - Yar - Fixed warnings
11
05/03/10 - DanB - More state added to TGLStateCache
12
22/02/10 - Yar - Optimization of switching states
13
30/03/07 - DaStr - Added $I GLScene.inc
14
28/03/07 - DaStr - Added explicit pointer dereferencing (even more)
15
16/03/07 - DaStr - Added explicit pointer dereferencing
16
(thanks Burkhard Carstens) (Bugtracker ID = 1678644)
17
27/05/04 - MF - Added some length information to edges
18
24/06/03 - MF - Removed several embarrassing warnings
19
17/06/03 - MF - Creation
32
GLVectorFileObjects, GLVerletTypes, GLVectorTypes, GLVectorLists,
33
GLVectorGeometry, GLTexture, OpenGLTokens, GLRenderContextInfo,
38
{ Class that represents a face. This structure is not used for rendering, but
39
for extracting info from meshes }
42
Vertices : array[0..2] of integer;
43
Normal : TAffineVector;
44
MeshObject : TGLMeshObject;
47
procedure UpdateNormal;
49
constructor Create(aMeshObject : TGLMeshObject);
53
TFaceList = class(TList)
55
function GetItems(i: integer): TFace;
56
procedure SetItems(i: integer; const Value: TFace);
58
property Items[i : integer] : TFace read GetItems write SetItems; default;
61
{ Class that extracts faces from a GLBaseMesh}
62
TFaceExtractor = class
64
FFaceList : TFaceList;
65
FGLBaseMesh : TGLBaseMesh;
66
FNodeList : TVerletNodeList;
67
FWeldDistance: single;
68
FEdgeDoublesSkipped : integer;
70
procedure SetWeldDistance(const Value: single);
72
procedure ProcessMeshObject(const MeshObject : TGLMeshObject); virtual;
74
procedure ExtractFacesFromVertexIndexList(
75
const FaceGroup : TFGVertexIndexList; const MeshObject : TGLMeshObject);
77
property FaceList : TFaceList read FFaceList;
79
procedure Clear; virtual;
80
procedure ProcessMesh; virtual;
82
property WeldDistance : single read FWeldDistance write SetWeldDistance;
83
property EdgeDoublesSkipped : integer read FEdgeDoublesSkipped;
85
property GLBaseMesh : TGLBaseMesh read FGLBaseMesh;
87
property NodeList : TVerletNodeList read FNodeList;
89
function AddFace(const Vi0, Vi1, Vi2 : integer; const MeshObject : TGLMeshObject) : TFace; virtual;
91
constructor Create(const aGLBaseMesh : TGLBaseMesh); virtual;
92
destructor Destroy; override;
95
// ************ EDGE DETECTOR
97
TEdgeDetector = class;
102
FMeshObject: TGLMeshObject;
103
FOwner: TEdgeDetector;
105
Vertices : array[0..1] of integer;
106
Faces : array[0..1] of TFace;
110
property Owner : TEdgeDetector read FOwner;
111
property MeshObject : TGLMeshObject read FMeshObject write FMeshObject;
112
property Length : single read FLength write FLength;
113
property Solid : boolean read FSolid write FSolid;
115
procedure UpdateEdgeLength;
117
constructor Create(const AOwner: TEdgeDetector; AVi0, AVi1 : integer;
118
AFace0, AFace1 : TFace; AMeshObject : TGLMeshObject; ASolid : boolean);
121
TEdgeList = class(TList)
123
function GetItems(i: integer): TEdge;
124
procedure SetItems(i: integer; const Value: TEdge);
126
property Items[i : integer] : TEdge read GetItems write SetItems; default;
128
procedure SortByLength;
129
function InsertSorted(AEdge : TEdge) : integer;
132
TEdgeDetector = class(TFaceExtractor)
134
FEdgeList : TEdgeList;
135
FCurrentNodeOffset : integer;
136
FNodesAdded : boolean;
138
procedure BuildOpposingEdges;
140
FCalcEdgeLength : boolean;
142
property EdgeList : TEdgeList read FEdgeList;
144
procedure Clear; override;
145
procedure ProcessMesh; override;
147
function AddEdge(const Vi0, Vi1 : integer; const Face : TFace; const AMeshObject : TGLMeshObject) : TEdge;
148
function AddFace(const Vi0, Vi1, Vi2 : integer; const MeshObject : TGLMeshObject) : TFace; override;
149
function AddNode(const VerletWorld : TGLVerletWorld; const MeshObject : TGLMeshObject; const VertexIndex : integer) : TVerletNode; virtual;
151
procedure AddNodes(const VerletWorld : TGLVerletWorld);
152
procedure AddEdgesAsSticks(const VerletWorld : TGLVerletWorld; const Slack : single);
153
procedure AddEdgesAsSprings(const VerletWorld : TGLVerletWorld; const Strength, Damping, Slack : single);
154
procedure AddEdgesAsSolidEdges(const VerletWorld : TGLVerletWorld);
155
procedure AddOuterEdgesAsSolidEdges(const VerletWorld : TGLVerletWorld);
157
procedure RenderEdges(var rci : TGLRenderContextInfo);
159
property CurrentNodeOffset : integer read FCurrentNodeOffset;
160
property NodesAdded : boolean read FNodesAdded;
162
procedure ReplaceVertexIndex(const ViRemove, ViReplaceWith : integer);
164
constructor Create(const aGLBaseMesh : TGLBaseMesh); override;
165
destructor Destroy; override;
168
TGLMeshObjectVerletNode = class(TVerletNode)
170
MeshObject : TGLMeshObject;
171
VertexIndices : TIntegerList;
173
procedure AfterProgress; override;
175
constructor CreateOwned(const aOwner : TGLVerletWorld); override;
176
destructor Destroy; override;
183
procedure TFaceExtractor.Clear;
187
for i := 0 to FaceList.Count-1 do
193
constructor TFaceExtractor.Create(const aGLBaseMesh : TGLBaseMesh);
195
FFaceList := TFaceList.Create;
196
FGLBaseMesh := aGLBaseMesh;
197
FNodeList := TVerletNodeList.Create;
198
FWeldDistance := 0.01;
201
destructor TFaceExtractor.Destroy;
205
FreeAndNil(FNodeList);
206
FreeAndNil(FFaceList);
211
procedure TFaceExtractor.ExtractFacesFromVertexIndexList(
212
const FaceGroup : TFGVertexIndexList; const MeshObject : TGLMeshObject);
214
List : PIntegerArray;
215
iFace, iVertex : integer;
217
case FaceGroup.Mode of
219
fgmmTriangles, fgmmFlatTriangles :
221
for iFace := 0 to FaceGroup.TriangleCount - 1 do
223
List := @FaceGroup.VertexIndices.List[iFace * 3 + 0];
224
AddFace(List^[0], List^[1], List^[2], MeshObject);
230
for iFace:=0 to FaceGroup.VertexIndices.Count-3 do
232
List := @FaceGroup.VertexIndices.List[iFace];
233
if (iFace and 1)=0 then
234
AddFace(List^[0], List^[1], List^[2], MeshObject)
236
AddFace(List^[2], List^[1], List^[0], MeshObject);
242
List := @FaceGroup.VertexIndices.List;
244
for iVertex:=2 to FaceGroup.VertexIndices.Count-1 do
245
AddFace(List^[0], List^[iVertex-1], List^[iVertex], MeshObject)
248
Assert(false,'Not supported');
252
procedure TFaceExtractor.ProcessMesh;
254
iMeshObject : integer;
255
MeshObject : TGLMeshObject;
257
for iMeshObject := 0 to FGLBaseMesh.MeshObjects.Count - 1 do
259
MeshObject := FGLBaseMesh.MeshObjects[iMeshObject];
261
ProcessMeshObject(MeshObject);
265
procedure TFaceExtractor.ProcessMeshObject(const MeshObject : TGLMeshObject);
267
iFaceGroup : integer;
269
if MeshObject.Mode = momFaceGroups then
271
for iFaceGroup := 0 to MeshObject.FaceGroups.Count - 1 do
273
if MeshObject.FaceGroups[iFaceGroup] is TFGVertexIndexList then
275
ExtractFacesFromVertexIndexList(MeshObject.FaceGroups[iFaceGroup] as TFGVertexIndexList, MeshObject);
283
function TFaceExtractor.AddFace(const Vi0, Vi1, Vi2: integer; const MeshObject : TGLMeshObject) : TFace;
287
Face := TFace.Create(MeshObject);
291
Face.Vertices[0] := Vi0;
292
Face.Vertices[1] := Vi1;
293
Face.Vertices[2] := Vi2;
298
procedure TFaceExtractor.SetWeldDistance(const Value: single);
300
FWeldDistance := Value;
306
function TFaceList.GetItems(i: integer): TFace;
308
result := TFace(Get(i));
311
procedure TFaceList.SetItems(i: integer; const Value: TFace);
318
function TEdgeList.GetItems(i: integer): TEdge;
320
result := TEdge(Get(i));
323
function TEdgeList.InsertSorted(AEdge: TEdge): integer;
327
for i := 0 to Count-1 do
329
if AEdge.Length<Items[i].Length then
337
result := Add(AEdge);
340
procedure TEdgeList.SetItems(i: integer; const Value: TEdge);
345
function EdgeLength(Item1, Item2 : pointer) : integer;
347
if TEdge(Item1).Length < TEdge(Item2).Length then
350
else if TEdge(Item1).Length = TEdge(Item2).Length then
357
procedure TEdgeList.SortByLength;
362
{ TGLMeshObjectVerletNode }
364
constructor TGLMeshObjectVerletNode.CreateOwned(const aOwner: TGLVerletWorld);
367
VertexIndices := TIntegerList.Create;
370
destructor TGLMeshObjectVerletNode.Destroy;
376
procedure TGLMeshObjectVerletNode.AfterProgress;
380
// Update the actual vertex
381
for i := 0 to VertexIndices.Count-1 do
382
MeshObject.Vertices[VertexIndices[i]] := MeshObject.Owner.Owner.AbsoluteToLocal(Location);
387
procedure TEdgeDetector.Clear;
393
for i := 0 to EdgeList.Count-1 do
398
FCurrentNodeOffset := 0;
399
FNodesAdded := false;
402
constructor TEdgeDetector.Create(const aGLBaseMesh: TGLBaseMesh);
404
FEdgeList := TEdgeList.Create;
405
FCurrentNodeOffset := 0;
406
FNodesAdded := false;
407
FCalcEdgeLength := false;
412
destructor TEdgeDetector.Destroy;
416
FreeAndNil(FEdgeList);
419
function TEdgeDetector.AddEdge(const Vi0, Vi1: integer; const Face: TFace; const AMeshObject : TGLMeshObject): TEdge;
424
// Find an indentical edge, if there is one
425
for i := 0 to EdgeList.Count - 1 do
429
if (Edge.Vertices[0]=Vi0) and (Edge.Vertices[1]=Vi1) or
430
(Edge.Vertices[1]=Vi0) and (Edge.Vertices[0]=Vi1) then
432
Edge.Faces[1] := Face;
439
// No edge was found, create a new one
440
Edge := TEdge.Create(self, Vi0, Vi1, Face, nil, AMeshObject, true);
446
function TEdgeDetector.AddFace(const Vi0, Vi1, Vi2: integer;
447
const MeshObject: TGLMeshObject): TFace;
451
Face := TFace.Create(MeshObject);
455
Face.Vertices[0] := Vi0;
456
Face.Vertices[1] := Vi1;
457
Face.Vertices[2] := Vi2;
459
AddEdge(Vi0, Vi1, Face, MeshObject);
460
AddEdge(Vi1, Vi2, Face, MeshObject);
461
AddEdge(Vi2, Vi0, Face, MeshObject);//}
466
procedure TEdgeDetector.AddNodes(const VerletWorld : TGLVerletWorld);
472
FCurrentNodeOffset := FNodeList.Count;
474
MO := FGLBaseMesh.MeshObjects[0];
476
for i := 0 to MO.Vertices.Count-1 do
477
AddNode(VerletWorld, MO, i);
479
// Assert(FNodeList.Count = MO.Vertices.Count, Format('%d <> %d',[FNodeList.Count, MO.Vertices.Count]));
482
procedure TEdgeDetector.AddEdgesAsSprings(const VerletWorld : TGLVerletWorld;
483
const Strength, Damping, Slack: single);
488
if not FNodesAdded then
489
AddNodes(VerletWorld);
491
for i := 0 to EdgeList.Count-1 do
493
// if not EdgeList[i].SameSame(FNodeList) then
495
if FNodeList[FCurrentNodeOffset+Edge.Vertices[0]] <> FNodeList[FCurrentNodeOffset+Edge.Vertices[1]] then
497
VerletWorld.CreateSpring(
498
FNodeList[FCurrentNodeOffset+Edge.Vertices[0]],
499
FNodeList[FCurrentNodeOffset+Edge.Vertices[1]],
500
Strength, Damping, Slack);
505
procedure TEdgeDetector.AddEdgesAsSticks(const VerletWorld : TGLVerletWorld;
506
const Slack : single);
511
if not FNodesAdded then
512
AddNodes(VerletWorld);
514
for i := 0 to EdgeList.Count-1 do
516
// if not EdgeList[i].SameSame(FNodeList) then
518
if FNodeList[FCurrentNodeOffset+Edge.Vertices[0]] <> FNodeList[FCurrentNodeOffset+Edge.Vertices[1]] then
520
VerletWorld.CreateStick(
521
FNodeList[FCurrentNodeOffset + Edge.Vertices[0]],
522
FNodeList[FCurrentNodeOffset + Edge.Vertices[1]],
528
procedure TEdgeDetector.AddEdgesAsSolidEdges(
529
const VerletWorld: TGLVerletWorld);
534
if not FNodesAdded then
535
AddNodes(VerletWorld);
537
for i := 0 to EdgeList.Count-1 do
539
// if not EdgeList[i].SameSame(FNodeList) then
541
if FNodeList[FCurrentNodeOffset+Edge.Vertices[0]] <> FNodeList[FCurrentNodeOffset+Edge.Vertices[1]] then
544
VerletWorld.AddSolidEdge(
545
FNodeList[FCurrentNodeOffset + Edge.Vertices[0]],
546
FNodeList[FCurrentNodeOffset + Edge.Vertices[1]]);
551
procedure TEdgeDetector.AddOuterEdgesAsSolidEdges(
552
const VerletWorld: TGLVerletWorld);
557
if not FNodesAdded then
558
AddNodes(VerletWorld);
560
for i := 0 to EdgeList.Count-1 do
562
// if not EdgeList[i].SameSame(FNodeList) then
564
if FNodeList[FCurrentNodeOffset+Edge.Vertices[0]] <> FNodeList[FCurrentNodeOffset+Edge.Vertices[1]] then
566
if Edge.Solid and (Edge.Faces[1]=nil) then
567
VerletWorld.AddSolidEdge(
568
FNodeList[FCurrentNodeOffset + Edge.Vertices[0]],
569
FNodeList[FCurrentNodeOffset + Edge.Vertices[1]]);
574
procedure TEdgeDetector.RenderEdges(var rci: TGLRenderContextInfo);
578
Vertex0, Vertex1 : TAffineVector;
580
if EdgeList.Count>0 then
582
rci.GLStates.Disable(stLighting);
583
rci.GLStates.LineWidth := 3;
587
for i := 0 to EdgeList.Count - 1 do
591
Vertex0 := Edge.MeshObject.Vertices[Edge.Vertices[0]];
592
Vertex1 := Edge.MeshObject.Vertices[Edge.Vertices[1]];
594
GL.Vertex3fv(PGLfloat(@Vertex0));
595
GL.Vertex3fv(PGLfloat(@Vertex1));
601
procedure TEdgeDetector.BuildOpposingEdges;
603
iEdge, EdgeCount, vi0, vi1, iEdgeTest : integer;
604
Face0, Face1 : TFace;
605
Edge, NewEdge, TestEdge : TEdge;
607
// For each edge that's connected by two triangles, create a new edge that
608
// connects the two "extra" vertices.... makes sense?
609
EdgeCount := EdgeList.Count;
611
for iEdge := 0 to EdgeCount-1 do
613
Edge := EdgeList[iEdge];
615
if Assigned(Edge.Faces[1]) then
617
Face0 := Edge.Faces[0];
618
Face1 := Edge.Faces[1];
620
if (Face0.Vertices[0] <> Edge.Vertices[0]) and (Face0.Vertices[0] <> Edge.Vertices[1]) then
621
vi0 := Face0.Vertices[0]
622
else if (Face0.Vertices[1] <> Edge.Vertices[0]) and (Face0.Vertices[1] <> Edge.Vertices[1]) then
623
vi0 := Face0.Vertices[1]
625
vi0 := Face0.Vertices[2];
627
if (Face1.Vertices[0] <> Edge.Vertices[0]) and (Face1.Vertices[0] <> Edge.Vertices[1]) then
628
vi1 := Face1.Vertices[0]
629
else if (Face1.Vertices[1] <> Edge.Vertices[0]) and (Face1.Vertices[1] <> Edge.Vertices[1]) then
630
vi1 := Face1.Vertices[1]
632
vi1 := Face1.Vertices[2];
635
(vi0=Edge.Vertices[0]) or
636
(vi0=Edge.Vertices[1]) or
637
(vi1=Edge.Vertices[0]) or
638
(vi1=Edge.Vertices[1]) then
641
// Find an indentical edge, if there is one
642
for iEdgeTest := 0 to EdgeList.Count - 1 do
644
TestEdge := EdgeList[iEdgeTest];
646
if (TestEdge.Vertices[0]=Vi0) and (TestEdge.Vertices[1]=Vi1) or
647
(TestEdge.Vertices[1]=Vi0) and (TestEdge.Vertices[0]=Vi1) then
649
// Edge allready exists!
650
inc(FEdgeDoublesSkipped);
655
NewEdge := TEdge.Create(self, Vi0, Vi1, nil, nil, Edge.MeshObject, false);
657
EdgeList.Add(NewEdge);//}
662
function TEdgeDetector.AddNode(const VerletWorld : TGLVerletWorld; const MeshObject: TGLMeshObject;
663
const VertexIndex: integer): TVerletNode;
665
Location : TAffineVector;
666
aNode : TGLMeshObjectVerletNode;
669
// Is there an identical node?
670
Location := MeshObject.Owner.Owner.LocalToAbsolute(MeshObject.Vertices[VertexIndex]);
672
for i := FCurrentNodeOffset to FNodeList.Count-1 do
674
aNode := TGLMeshObjectVerletNode(FNodeList[i]);
676
if VectorDistance2(Location, aNode.Location)<=FWeldDistance then
678
FNodeList.Add(aNode);
679
aNode.VertexIndices.Add(VertexIndex);
685
aNode := TGLMeshObjectVerletNode.CreateOwned(VerletWorld);
686
aNode.MeshObject := MeshObject;
687
aNode.VertexIndices.Add(VertexIndex);
688
aNode.Location := Location;
689
aNode.OldLocation := Location;
691
FNodeList.Add(aNode);
695
procedure TEdgeDetector.ProcessMesh;
702
procedure TEdgeDetector.ReplaceVertexIndex(const ViRemove,
703
ViReplaceWith: integer);
709
for i := 0 to FaceList.Count-1 do
714
if Vertices[0] = ViRemove then
715
Vertices[0] := ViReplaceWith;
717
if Vertices[1] = ViRemove then
718
Vertices[1] := ViReplaceWith;
720
if Vertices[2] = ViRemove then
721
Vertices[2] := ViReplaceWith;
723
if (Vertices[0]=Vertices[1]) or
724
(Vertices[1]=Vertices[2]) or
725
(Vertices[2]=Vertices[0]) then
734
for i := 0 to EdgeList.Count-1 do
737
if (Vertices[0] = ViRemove) or (Vertices[1] = ViRemove) then
739
if Vertices[0] = ViRemove then
740
Vertices[0] := ViReplaceWith;
742
if Vertices[1] = ViRemove then
743
Vertices[1] := ViReplaceWith;
750
if Edge.Length=-1 then
753
EdgeList.InsertSorted(Edge);
765
constructor TFace.Create(aMeshObject: TGLMeshObject);
767
MeshObject := aMeshObject;
771
procedure TFace.UpdateNormal;
774
MeshObject.Vertices[Vertices[0]],
775
MeshObject.Vertices[Vertices[1]],
776
MeshObject.Vertices[Vertices[2]], Normal);
781
procedure TEdge.Contract;
783
// We're removing vertex 1 and replacing it with vertex 0
784
FOwner.ReplaceVertexIndex(Vertices[1], Vertices[0]);
785
//MeshObject.Vertices[Vertices[0]] := MeshObject.Vertices[Vertices[1]];
789
constructor TEdge.Create(const AOwner: TEdgeDetector; AVi0, AVi1 : integer;
790
AFace0, AFace1 : TFace; AMeshObject : TGLMeshObject; ASolid : boolean);
797
FMeshObject := AMeshObject;
803
procedure TEdge.UpdateEdgeLength;
805
if FOwner.FCalcEdgeLength then
807
if Vertices[0] = Vertices[1] then
810
Length := VectorDistance(
811
FOwner.GLBaseMesh.LocalToAbsolute(FMeshObject.Vertices[Vertices[0]]),
812
FOwner.GLBaseMesh.LocalToAbsolute(FMeshObject.Vertices[Vertices[1]]));