diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 617 |
1 files changed, 547 insertions, 70 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index eb4b2ad..7470d23 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -1,70 +1,547 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyrightD | 9 | * * Redistributions in binary form must reproduce the above copyrightD |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | using OMV = OpenMetaverse; | 30 | using OMV = OpenMetaverse; |
31 | 31 | using OpenSim.Framework; | |
32 | namespace OpenSim.Region.Physics.BulletSPlugin | 32 | using OpenSim.Region.Physics.Manager; |
33 | { | 33 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; |
34 | public class BSShapeCollection : IDisposable | 34 | |
35 | { | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | protected BSScene PhysicsScene { get; set; } | 36 | { |
37 | 37 | public class BSShapeCollection : IDisposable | |
38 | public BSShapeCollection(BSScene physScene) | 38 | { |
39 | { | 39 | protected BSScene PhysicsScene { get; set; } |
40 | PhysicsScene = physScene; | 40 | |
41 | } | 41 | private Object m_shapeActivityLock = new Object(); |
42 | 42 | ||
43 | public void Dispose() | 43 | private struct MeshDesc |
44 | { | 44 | { |
45 | } | 45 | public IntPtr Ptr; |
46 | 46 | public int referenceCount; | |
47 | // Track another user of a body | 47 | public DateTime lastReferenced; |
48 | public void ReferenceBody(BulletBody shape) | 48 | public IMesh meshData; |
49 | { | 49 | } |
50 | } | 50 | |
51 | 51 | private struct HullDesc | |
52 | // Release the usage of a body | 52 | { |
53 | public void DereferenceBody(BulletBody shape) | 53 | public IntPtr Ptr; |
54 | { | 54 | public int referenceCount; |
55 | } | 55 | public DateTime lastReferenced; |
56 | 56 | } | |
57 | // Track another user of the shape | 57 | |
58 | public void ReferenceShape(BulletShape shape) | 58 | private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); |
59 | { | 59 | private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); |
60 | } | 60 | |
61 | 61 | public BSShapeCollection(BSScene physScene) | |
62 | // Release the usage of a shape | 62 | { |
63 | public void DereferenceShape(BulletShape shape) | 63 | PhysicsScene = physScene; |
64 | { | 64 | } |
65 | } | 65 | |
66 | 66 | public void Dispose() | |
67 | 67 | { | |
68 | 68 | } | |
69 | } | 69 | |
70 | } | 70 | // Called to update/change the body and shape for an object. |
71 | // First checks the shape and updates that if necessary then makes | ||
72 | // sure the body is of the right type. | ||
73 | // Return 'true' if either the body or the shape changed. | ||
74 | // Called at taint-time!! | ||
75 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
76 | { | ||
77 | bool ret = false; | ||
78 | |||
79 | // Do we have the correct geometry for this type of object? | ||
80 | if (CreateGeom(forceRebuild, prim, shapeData, pbs)) | ||
81 | { | ||
82 | // If we had to select a new shape geometry for the object, | ||
83 | // rebuild the body around it. | ||
84 | CreateObject(true, prim, PhysicsScene.World, prim.BSShape, shapeData); | ||
85 | ret = true; | ||
86 | } | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | // Track another user of a body | ||
92 | public void ReferenceBody(BulletBody shape) | ||
93 | { | ||
94 | } | ||
95 | |||
96 | // Release the usage of a body | ||
97 | public void DereferenceBody(BulletBody shape) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | // Track another user of the shape | ||
102 | public void ReferenceShape(BulletShape shape) | ||
103 | { | ||
104 | ReferenceShape(shape, null); | ||
105 | } | ||
106 | |||
107 | // Track the datastructures and use count for a shape. | ||
108 | // When creating a hull, this is called first to reference the mesh | ||
109 | // and then again to reference the hull. | ||
110 | // Meshes and hulls for the same shape have the same hash key. | ||
111 | private void ReferenceShape(BulletShape shape, IMesh meshData) | ||
112 | { | ||
113 | switch (shape.type) | ||
114 | { | ||
115 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
116 | MeshDesc meshDesc; | ||
117 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
118 | { | ||
119 | // There is an existing instance of this mesh. | ||
120 | meshDesc.referenceCount++; | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | // This is a new reference to a mesh | ||
125 | meshDesc.Ptr = shape.Ptr; | ||
126 | meshDesc.meshData = meshData; | ||
127 | meshDesc.referenceCount = 1; | ||
128 | |||
129 | } | ||
130 | meshDesc.lastReferenced = System.DateTime.Now; | ||
131 | Meshes[shape.shapeKey] = meshDesc; | ||
132 | break; | ||
133 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | ||
134 | HullDesc hullDesc; | ||
135 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
136 | { | ||
137 | // There is an existing instance of this mesh. | ||
138 | hullDesc.referenceCount++; | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | // This is a new reference to a mesh | ||
143 | hullDesc.Ptr = shape.Ptr; | ||
144 | hullDesc.referenceCount = 1; | ||
145 | |||
146 | } | ||
147 | hullDesc.lastReferenced = System.DateTime.Now; | ||
148 | Hulls[shape.shapeKey] = hullDesc; | ||
149 | break; | ||
150 | default: | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // Release the usage of a shape | ||
156 | public void DereferenceShape(BulletShape shape) | ||
157 | { | ||
158 | switch (shape.type) | ||
159 | { | ||
160 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | ||
161 | DereferenceHull(shape); | ||
162 | // Hulls also include a mesh | ||
163 | DereferenceMesh(shape); | ||
164 | break; | ||
165 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
166 | DereferenceMesh(shape); | ||
167 | break; | ||
168 | default: | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | // Count down the reference count for a mesh shape | ||
174 | private void DereferenceMesh(BulletShape shape) | ||
175 | { | ||
176 | MeshDesc meshDesc; | ||
177 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
178 | { | ||
179 | meshDesc.referenceCount--; | ||
180 | // TODO: release the Bullet storage | ||
181 | meshDesc.lastReferenced = System.DateTime.Now; | ||
182 | Meshes[shape.shapeKey] = meshDesc; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | // Count down the reference count for a hull shape | ||
187 | private void DereferenceHull(BulletShape shape) | ||
188 | { | ||
189 | HullDesc hullDesc; | ||
190 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
191 | { | ||
192 | hullDesc.referenceCount--; | ||
193 | // TODO: release the Bullet storage (aging old entries?) | ||
194 | hullDesc.lastReferenced = System.DateTime.Now; | ||
195 | Hulls[shape.shapeKey] = hullDesc; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | // Create the geometry information in Bullet for later use. | ||
200 | // The objects needs a hull if it's physical otherwise a mesh is enough. | ||
201 | // No locking here because this is done when we know physics is not simulating. | ||
202 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. | ||
203 | // Returns 'true' if the geometry was rebuilt. | ||
204 | // Called at taint-time! | ||
205 | private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
206 | { | ||
207 | bool ret = false; | ||
208 | bool haveShape = false; | ||
209 | bool nativeShapePossible = true; | ||
210 | |||
211 | BulletShape newShape = new BulletShape(IntPtr.Zero); | ||
212 | |||
213 | // If the object is dynamic, it must have a hull shape | ||
214 | if (prim.IsPhysical) | ||
215 | nativeShapePossible = false; | ||
216 | |||
217 | // If the prim attributes are simple, this could be a simple Bullet native shape | ||
218 | if (nativeShapePossible | ||
219 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | ||
220 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
221 | && pbs.ProfileHollow == 0 | ||
222 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
223 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
224 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
225 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
226 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | ||
227 | { | ||
228 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | ||
229 | { | ||
230 | haveShape = true; | ||
231 | if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) | ||
232 | { | ||
233 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere (force={1}", prim.LocalID, forceRebuild); | ||
234 | newShape = AddNativeShapeToPrim(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE); | ||
235 | |||
236 | ret = true; | ||
237 | } | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size); | ||
242 | haveShape = true; | ||
243 | if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX)) | ||
244 | { | ||
245 | DetailLog("{0},BSShapeCollection.CreateGeom,box (force={1})", prim.LocalID, forceRebuild); | ||
246 | newShape = AddNativeShapeToPrim(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX); | ||
247 | |||
248 | ret = true; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | // If a simple shape isn't happening, create a mesh and possibly a hull | ||
253 | if (!haveShape) | ||
254 | { | ||
255 | if (prim.IsPhysical) | ||
256 | { | ||
257 | if (forceRebuild || !Hulls.ContainsKey(prim.BSShape.shapeKey)) | ||
258 | { | ||
259 | // physical objects require a hull for interaction. | ||
260 | // This also creates the mesh if it doesn't already exist | ||
261 | ret = CreateGeomHull(prim, shapeData, pbs); | ||
262 | } | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | if (forceRebuild || !Meshes.ContainsKey(prim.BSShape.shapeKey)) | ||
267 | { | ||
268 | // Static (non-physical) objects only need a mesh for bumping into | ||
269 | ret = CreateGeomMesh(prim, shapeData, pbs); | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | private BulletShape AddNativeShapeToPrim(BSPrim prim, ShapeData shapeData, ShapeData.PhysicsShapeType shapeType) | ||
277 | { | ||
278 | BulletShape newShape; | ||
279 | |||
280 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
281 | prim.Scale = shapeData.Size; | ||
282 | |||
283 | // release any previous shape | ||
284 | DereferenceShape(prim.BSShape); | ||
285 | |||
286 | MeshDesc existingShapeDesc; | ||
287 | if (Meshes.TryGetValue(shapeData.MeshKey, out existingShapeDesc)) | ||
288 | { | ||
289 | // If there is an existing allocated shape, use it | ||
290 | newShape = new BulletShape(existingShapeDesc.Ptr, shapeType); | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | // Shape of this discriptioin is not allocated. Create new. | ||
295 | newShape = new BulletShape( | ||
296 | BulletSimAPI.BuildNativeShape2(PhysicsScene.World.Ptr, | ||
297 | (float)shapeType, | ||
298 | PhysicsScene.Params.collisionMargin, | ||
299 | prim.Scale), | ||
300 | shapeType); | ||
301 | } | ||
302 | newShape.shapeKey = shapeData.MeshKey; | ||
303 | ReferenceShape(newShape); | ||
304 | prim.BSShape = newShape; | ||
305 | return newShape; | ||
306 | } | ||
307 | |||
308 | // No locking here because this is done when we know physics is not simulating | ||
309 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). | ||
310 | // Called at taint-time! | ||
311 | private bool CreateGeomMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
312 | { | ||
313 | BulletShape newShape = new BulletShape(IntPtr.Zero); | ||
314 | |||
315 | // level of detail based on size and type of the object | ||
316 | float lod = PhysicsScene.MeshLOD; | ||
317 | if (pbs.SculptEntry) | ||
318 | lod = PhysicsScene.SculptLOD; | ||
319 | |||
320 | float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); | ||
321 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | ||
322 | lod = PhysicsScene.MeshMegaPrimLOD; | ||
323 | |||
324 | ulong newMeshKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod); | ||
325 | // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, LocalID, _meshKey, newMeshKey); | ||
326 | |||
327 | // if this new shape is the same as last time, don't recreate the mesh | ||
328 | if (prim.BSShape.shapeKey == newMeshKey) return false; | ||
329 | |||
330 | DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,key={1}", prim.LocalID, newMeshKey); | ||
331 | |||
332 | // Since we're recreating new, get rid of the reference to the previous shape | ||
333 | DereferenceShape(prim.BSShape); | ||
334 | |||
335 | IMesh meshData = null; | ||
336 | IntPtr meshPtr; | ||
337 | MeshDesc meshDesc; | ||
338 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | ||
339 | { | ||
340 | // If the mesh has already been built just use it. | ||
341 | meshPtr = meshDesc.Ptr; | ||
342 | } | ||
343 | else | ||
344 | { | ||
345 | // always pass false for physicalness as this creates some sort of bounding box which we don't need | ||
346 | meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, shapeData.Size, lod, false); | ||
347 | |||
348 | int[] indices = meshData.getIndexListAsInt(); | ||
349 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
350 | |||
351 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
352 | int vi = 0; | ||
353 | foreach (OMV.Vector3 vv in vertices) | ||
354 | { | ||
355 | verticesAsFloats[vi++] = vv.X; | ||
356 | verticesAsFloats[vi++] = vv.Y; | ||
357 | verticesAsFloats[vi++] = vv.Z; | ||
358 | } | ||
359 | |||
360 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
361 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | ||
362 | |||
363 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.Ptr, | ||
364 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | ||
365 | } | ||
366 | newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | ||
367 | newShape.shapeKey = newMeshKey; | ||
368 | |||
369 | ReferenceShape(newShape, meshData); | ||
370 | |||
371 | // meshes are already scaled by the meshmerizer | ||
372 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
373 | prim.BSShape = newShape; | ||
374 | return true; // 'true' means a new shape has been added to this prim | ||
375 | } | ||
376 | |||
377 | // No locking here because this is done when we know physics is not simulating | ||
378 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). | ||
379 | List<ConvexResult> m_hulls; | ||
380 | private bool CreateGeomHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
381 | { | ||
382 | BulletShape newShape; | ||
383 | |||
384 | float lod = pbs.SculptEntry ? PhysicsScene.SculptLOD : PhysicsScene.MeshLOD; | ||
385 | ulong newHullKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod); | ||
386 | // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, LocalID, _hullKey, newHullKey); | ||
387 | |||
388 | // if the hull hasn't changed, don't rebuild it | ||
389 | if (newHullKey == prim.BSShape.shapeKey) return false; | ||
390 | |||
391 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", prim.LocalID, newHullKey, newHullKey); | ||
392 | |||
393 | // remove references to any previous shape | ||
394 | DereferenceShape(prim.BSShape); | ||
395 | |||
396 | // Make sure the underlying mesh exists and is correct | ||
397 | // Since we're in the hull code, we know CreateGeomMesh() will not create a native shape. | ||
398 | CreateGeomMesh(prim, shapeData, pbs); | ||
399 | MeshDesc meshDesc = Meshes[newHullKey]; | ||
400 | |||
401 | IntPtr hullPtr; | ||
402 | HullDesc hullDesc; | ||
403 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | ||
404 | { | ||
405 | hullPtr = hullDesc.Ptr; | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | int[] indices = meshDesc.meshData.getIndexListAsInt(); | ||
410 | List<OMV.Vector3> vertices = meshDesc.meshData.getVertexList(); | ||
411 | |||
412 | //format conversion from IMesh format to DecompDesc format | ||
413 | List<int> convIndices = new List<int>(); | ||
414 | List<float3> convVertices = new List<float3>(); | ||
415 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
416 | { | ||
417 | convIndices.Add(indices[ii]); | ||
418 | } | ||
419 | foreach (OMV.Vector3 vv in vertices) | ||
420 | { | ||
421 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
422 | } | ||
423 | |||
424 | // setup and do convex hull conversion | ||
425 | m_hulls = new List<ConvexResult>(); | ||
426 | DecompDesc dcomp = new DecompDesc(); | ||
427 | dcomp.mIndices = convIndices; | ||
428 | dcomp.mVertices = convVertices; | ||
429 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
430 | // create the hull into the _hulls variable | ||
431 | convexBuilder.process(dcomp); | ||
432 | |||
433 | // Convert the vertices and indices for passing to unmanaged. | ||
434 | // The hull information is passed as a large floating point array. | ||
435 | // The format is: | ||
436 | // convHulls[0] = number of hulls | ||
437 | // convHulls[1] = number of vertices in first hull | ||
438 | // convHulls[2] = hull centroid X coordinate | ||
439 | // convHulls[3] = hull centroid Y coordinate | ||
440 | // convHulls[4] = hull centroid Z coordinate | ||
441 | // convHulls[5] = first hull vertex X | ||
442 | // convHulls[6] = first hull vertex Y | ||
443 | // convHulls[7] = first hull vertex Z | ||
444 | // convHulls[8] = second hull vertex X | ||
445 | // ... | ||
446 | // convHulls[n] = number of vertices in second hull | ||
447 | // convHulls[n+1] = second hull centroid X coordinate | ||
448 | // ... | ||
449 | // | ||
450 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
451 | // data structures that do not need to be converted in order to pass to Bullet. | ||
452 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
453 | int hullCount = m_hulls.Count; | ||
454 | int totalVertices = 1; // include one for the count of the hulls | ||
455 | foreach (ConvexResult cr in m_hulls) | ||
456 | { | ||
457 | totalVertices += 4; // add four for the vertex count and centroid | ||
458 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
459 | } | ||
460 | float[] convHulls = new float[totalVertices]; | ||
461 | |||
462 | convHulls[0] = (float)hullCount; | ||
463 | int jj = 1; | ||
464 | foreach (ConvexResult cr in m_hulls) | ||
465 | { | ||
466 | // copy vertices for index access | ||
467 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
468 | int kk = 0; | ||
469 | foreach (float3 ff in cr.HullVertices) | ||
470 | { | ||
471 | verts[kk++] = ff; | ||
472 | } | ||
473 | |||
474 | // add to the array one hull's worth of data | ||
475 | convHulls[jj++] = cr.HullIndices.Count; | ||
476 | convHulls[jj++] = 0f; // centroid x,y,z | ||
477 | convHulls[jj++] = 0f; | ||
478 | convHulls[jj++] = 0f; | ||
479 | foreach (int ind in cr.HullIndices) | ||
480 | { | ||
481 | convHulls[jj++] = verts[ind].x; | ||
482 | convHulls[jj++] = verts[ind].y; | ||
483 | convHulls[jj++] = verts[ind].z; | ||
484 | } | ||
485 | } | ||
486 | // create the hull data structure in Bullet | ||
487 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, LocalID, _hullKey, hullCount); | ||
488 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.Ptr, hullCount, convHulls); | ||
489 | } | ||
490 | newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | ||
491 | newShape.shapeKey = newHullKey; | ||
492 | |||
493 | ReferenceShape(newShape); | ||
494 | |||
495 | // meshes are already scaled by the meshmerizer | ||
496 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
497 | prim.BSShape = newShape; | ||
498 | return true; // 'true' means a new shape has been added to this prim | ||
499 | } | ||
500 | |||
501 | // Callback from convex hull creater with a newly created hull. | ||
502 | // Just add it to the collection of hulls for this shape. | ||
503 | private void HullReturn(ConvexResult result) | ||
504 | { | ||
505 | m_hulls.Add(result); | ||
506 | return; | ||
507 | } | ||
508 | |||
509 | // Create an object in Bullet if it has not already been created | ||
510 | // No locking here because this is done when the physics engine is not simulating | ||
511 | // Returns 'true' if an object was actually created. | ||
512 | private bool CreateObject(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, ShapeData shapeData) | ||
513 | { | ||
514 | // the mesh or hull must have already been created in Bullet | ||
515 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, LocalID, shape.Type); | ||
516 | |||
517 | DereferenceBody(prim.BSBody); | ||
518 | |||
519 | BulletBody aBody; | ||
520 | IntPtr bodyPtr = IntPtr.Zero; | ||
521 | if (prim.IsSolid) | ||
522 | { | ||
523 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.Ptr, shape.Ptr, shapeData.Position, shapeData.Rotation); | ||
524 | } | ||
525 | else | ||
526 | { | ||
527 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.Ptr, shape.Ptr, shapeData.Position, shapeData.Rotation); | ||
528 | } | ||
529 | aBody = new BulletBody(shapeData.ID, bodyPtr); | ||
530 | |||
531 | ReferenceBody(aBody); | ||
532 | |||
533 | prim.BSBody = aBody; | ||
534 | return true; | ||
535 | } | ||
536 | |||
537 | private void DetailLog(string msg, params Object[] args) | ||
538 | { | ||
539 | PhysicsScene.PhysicsLogging.Write(msg, args); | ||
540 | } | ||
541 | |||
542 | |||
543 | |||
544 | |||
545 | |||
546 | } | ||
547 | } | ||