1 /*
2 Copyright (c) 2019-2020 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(Mesh mesh, float tolerance, NewtonPhysicsWorld world)
180     {
181         super(world);
182         NewtonMesh* nmesh = NewtonMeshCreate(world.newtonWorld);
183         NewtonMeshBeginBuild(nmesh);
184         foreach(face; mesh.indices)
185         foreach(i; face)
186         {
187             Vector3f p = mesh.vertices[i];
188             Vector3f n = mesh.normals[i];
189             NewtonMeshAddPoint(nmesh, p.x, p.y, p.z);
190             NewtonMeshAddNormal(nmesh, n.x, n.y, n.z);
191         }
192         NewtonMeshEndBuild(nmesh);
193         
194         newtonCollision = NewtonCreateConvexHullFromMesh(world.newtonWorld, nmesh, tolerance, 0);
195         NewtonCollisionSetUserData(newtonCollision, cast(void*)this);
196         
197         NewtonMeshDestroy(nmesh);
198     }
199 }
200 
201 class NewtonCompoundShape: NewtonCollisionShape
202 {
203     this(NewtonCollisionShape[] shapes, NewtonPhysicsWorld world)
204     {
205         super(world);
206         newtonCollision = NewtonCreateCompoundCollision(world.newtonWorld, 0);
207         NewtonCompoundCollisionBeginAddRemove(newtonCollision);
208         foreach(shape; shapes)
209         {
210             NewtonCompoundCollisionAddSubCollision(newtonCollision, shape.newtonCollision);
211         }
212         NewtonCompoundCollisionEndAddRemove(newtonCollision);
213     }
214 }
215 
216 class NewtonHeightmapShape: NewtonCollisionShape
217 {
218     uint width;
219     uint height;
220     float[] elevationMap;
221     ubyte[] attributeMap;
222     
223     this(Heightmap heightmap, uint w, uint h, Vector3f scale, NewtonPhysicsWorld world)
224     {
225         super(world);
226         
227         width = w;
228         height = h;
229         
230         elevationMap = New!(float[])(width * height);
231         attributeMap = New!(ubyte[])(width * height);
232         
233         foreach(x; 0..width)
234         foreach(z; 0..height)
235         {
236             float y = heightmap.getHeight(
237                 cast(float)x / cast(float)(width - 1),
238                 cast(float)z / cast(float)(height - 1));
239             elevationMap[z * width + x] = y;
240             attributeMap[z * width + x] = 0; // TODO
241         }
242         
243         newtonCollision = NewtonCreateHeightFieldCollision(world.newtonWorld, 
244             width, height, 1, 0, elevationMap.ptr, cast(char*)attributeMap.ptr, scale.y, scale.x, scale.z, 0);
245     }
246     
247     ~this()
248     {
249         Delete(elevationMap);
250         Delete(attributeMap);
251     }
252 }