1 /*
2 Copyright (c) 2019-2022 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 */
27 
28 module dagon.ext.newton.shape;
29 
30 import dlib.core.ownership;
31 import dlib.core.memory;
32 import dlib.math.vector;
33 import dlib.math.matrix;
34 import dlib.geometry.triangle;
35 import bindbc.newton;
36 import dagon.graphics.mesh;
37 import dagon.graphics.heightmap;
38 import dagon.ext.newton.world;
39 
40 abstract class NewtonCollisionShape: Owner
41 {
42     NewtonPhysicsWorld world;
43     NewtonCollision* newtonCollision;
44 
45     this(NewtonPhysicsWorld world)
46     {
47         super(world);
48         this.world = world;
49     }
50 
51     ~this()
52     {
53         //if (newtonCollision)
54         //    NewtonDestroyCollision(newtonCollision);
55     }
56     
57     void setTransformation(Matrix4x4f m)
58     {
59         if (newtonCollision)
60             NewtonCollisionSetMatrix(newtonCollision, m.arrayof.ptr);
61     }
62 }
63 
64 class NewtonBoxShape: NewtonCollisionShape
65 {
66     Vector3f halfSize;
67 
68     this(Vector3f extents, NewtonPhysicsWorld world)
69     {
70         super(world);
71         newtonCollision = NewtonCreateBox(world.newtonWorld, extents.x, extents.y, extents.z, 0, null);
72         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
73         halfSize = extents * 0.5f;
74     }
75 }
76 
77 class NewtonSphereShape: NewtonCollisionShape
78 {
79     float radius;
80 
81     this(float radius, NewtonPhysicsWorld world)
82     {
83         super(world);
84         this.radius = radius;
85         newtonCollision = NewtonCreateSphere(world.newtonWorld, radius, 0, null);
86         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
87     }
88 }
89 
90 class NewtonCylinderShape: NewtonCollisionShape
91 {
92     float radius1;
93     float radius2;
94     float height;
95 
96     this(float radius1, float radius2, float height, NewtonPhysicsWorld world)
97     {
98         super(world);
99         this.radius1 = radius1;
100         this.radius2 = radius2;
101         this.height = height;
102         newtonCollision = NewtonCreateCylinder(world.newtonWorld, radius1, radius2, height, 0, null);
103         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
104     }
105 }
106 
107 class NewtonChamferCylinderShape: NewtonCollisionShape
108 {
109     float radius;
110     float height;
111 
112     this(float radius, float height, NewtonPhysicsWorld world)
113     {
114         super(world);
115         this.radius = radius;
116         this.height = height;
117         newtonCollision = NewtonCreateChamferCylinder(world.newtonWorld, radius, height, 0, null);
118         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
119     }
120 }
121 
122 class NewtonCapsuleShape: NewtonCollisionShape
123 {
124     float radius1;
125     float radius2;
126     float height;
127 
128     this(float radius, float height, NewtonPhysicsWorld world)
129     {
130         super(world);
131         this.radius1 = radius1;
132         this.radius2 = radius2;
133         this.height = height;
134         newtonCollision = NewtonCreateCapsule(world.newtonWorld, radius1, radius2, height, 0, null);
135         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
136     }
137 }
138 
139 class NewtonConeShape: NewtonCollisionShape
140 {
141     float radius;
142     float height;
143 
144     this(float radius, float height, NewtonPhysicsWorld world)
145     {
146         super(world);
147         this.radius = radius;
148         this.height = height;
149         newtonCollision = NewtonCreateCone(world.newtonWorld, radius, height, 0, null);
150         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
151     }
152 }
153 
154 class NewtonMeshShape: NewtonCollisionShape
155 {
156     this(TriangleSet triangleSet, NewtonPhysicsWorld world)
157     {
158         super(world);
159         NewtonMesh* nmesh = NewtonMeshCreate(world.newtonWorld);
160         NewtonMeshBeginBuild(nmesh);
161         foreach(triangle; triangleSet)
162         foreach(i, p; triangle.v)
163         {
164             Vector3f n = triangle.n[i];
165             NewtonMeshAddPoint(nmesh, p.x, p.y, p.z);
166             NewtonMeshAddNormal(nmesh, n.x, n.y, n.z);
167         }
168         NewtonMeshEndBuild(nmesh);
169         
170         newtonCollision = NewtonCreateTreeCollisionFromMesh(world.newtonWorld, nmesh, 0);
171         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
172         
173         NewtonMeshDestroy(nmesh);
174     }
175 }
176 
177 class NewtonConvexHullShape: NewtonCollisionShape
178 {
179     this(TriangleSet triangleSet, float tolerance, NewtonPhysicsWorld world)
180     {
181         super(world);
182         NewtonMesh* nmesh = NewtonMeshCreate(world.newtonWorld);
183         NewtonMeshBeginBuild(nmesh);
184         foreach(triangle; triangleSet)
185         foreach(i, p; triangle.v)
186         {
187             Vector3f n = triangle.n[i];
188             NewtonMeshAddPoint(nmesh, p.x, p.y, p.z);
189             NewtonMeshAddNormal(nmesh, n.x, n.y, n.z);
190         }
191         NewtonMeshEndBuild(nmesh);
192         
193         newtonCollision = NewtonCreateConvexHullFromMesh(world.newtonWorld, nmesh, tolerance, 0);
194         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
195         
196         NewtonMeshDestroy(nmesh);
197     }
198 }
199 
200 class NewtonCompoundShape: NewtonCollisionShape
201 {
202     this(NewtonCollisionShape[] shapes, NewtonPhysicsWorld world)
203     {
204         super(world);
205         newtonCollision = NewtonCreateCompoundCollision(world.newtonWorld, 0);
206         NewtonCompoundCollisionBeginAddRemove(newtonCollision);
207         foreach(shape; shapes)
208         {
209             NewtonCompoundCollisionAddSubCollision(newtonCollision, shape.newtonCollision);
210         }
211         NewtonCompoundCollisionEndAddRemove(newtonCollision);
212     }
213 }
214 
215 class NewtonHeightmapShape: NewtonCollisionShape
216 {
217     uint width;
218     uint height;
219     float[] elevationMap;
220     ubyte[] attributeMap;
221     
222     this(Heightmap heightmap, uint w, uint h, Vector3f scale, NewtonPhysicsWorld world)
223     {
224         super(world);
225         
226         width = w;
227         height = h;
228         
229         elevationMap = New!(float[])(width * height);
230         attributeMap = New!(ubyte[])(width * height);
231         
232         foreach(x; 0..width)
233         foreach(z; 0..height)
234         {
235             float y = heightmap.getHeight(
236                 cast(float)x / cast(float)(width - 1),
237                 cast(float)z / cast(float)(height - 1));
238             elevationMap[z * width + x] = y;
239             attributeMap[z * width + x] = 0; // TODO
240         }
241         
242         newtonCollision = NewtonCreateHeightFieldCollision(world.newtonWorld, 
243             width, height, 1, 0, elevationMap.ptr, cast(char*)attributeMap.ptr, scale.y, scale.x, scale.z, 0);
244     }
245     
246     ~this()
247     {
248         Delete(elevationMap);
249         Delete(attributeMap);
250     }
251 }