clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
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
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
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.Text;
31  
32 using OpenSim.Framework;
33 using OpenSim.Region.Physics.Manager;
34 using OpenSim.Region.Physics.Meshing;
35 using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36  
37 using OMV = OpenMetaverse;
38  
39 namespace OpenSim.Region.Physics.BulletSPlugin
40 {
41 public abstract class BSShape
42 {
43 private static string LogHeader = "[BULLETSIM SHAPE]";
44  
45 public int referenceCount { get; set; }
46 public DateTime lastReferenced { get; set; }
47 public BulletShape physShapeInfo { get; set; }
48  
49 public BSShape()
50 {
51 referenceCount = 1;
52 lastReferenced = DateTime.Now;
53 physShapeInfo = new BulletShape();
54 }
55 public BSShape(BulletShape pShape)
56 {
57 referenceCount = 1;
58 lastReferenced = DateTime.Now;
59 physShapeInfo = pShape;
60 }
61  
62 // Get another reference to this shape.
63 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
64  
65 // Called when this shape is being used again.
66 // Used internally. External callers should call instance.GetReference() to properly copy/reference
67 // the shape.
68 protected virtual void IncrementReference()
69 {
70 referenceCount++;
71 lastReferenced = DateTime.Now;
72 }
73  
74 // Called when this shape is done being used.
75 protected virtual void DecrementReference()
76 {
77 referenceCount--;
78 lastReferenced = DateTime.Now;
79 }
80  
81 // Release the use of a physical shape.
82 public abstract void Dereference(BSScene physicsScene);
83  
84 // Return 'true' if there is an allocated physics physical shape under this class instance.
85 public virtual bool HasPhysicalShape
86 {
87 get
88 {
89 if (physShapeInfo != null)
90 return physShapeInfo.HasPhysicalShape;
91 return false;
92 }
93 }
94 public virtual BSPhysicsShapeType ShapeType
95 {
96 get
97 {
98 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
99 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
100 ret = physShapeInfo.shapeType;
101 return ret;
102 }
103 }
104  
105 // Returns a string for debugging that uniquily identifies the memory used by this instance
106 public virtual string AddrString
107 {
108 get
109 {
110 if (physShapeInfo != null)
111 return physShapeInfo.AddrString;
112 return "unknown";
113 }
114 }
115  
116 public override string ToString()
117 {
118 StringBuilder buff = new StringBuilder();
119 if (physShapeInfo == null)
120 {
121 buff.Append("<noPhys");
122 }
123 else
124 {
125 buff.Append("<phy=");
126 buff.Append(physShapeInfo.ToString());
127 }
128 buff.Append(",c=");
129 buff.Append(referenceCount.ToString());
130 buff.Append(">");
131 return buff.ToString();
132 }
133  
134 #region Common shape routines
135 // Create a hash of all the shape parameters to be used as a key for this particular shape.
136 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
137 {
138 // level of detail based on size and type of the object
139 float lod = BSParam.MeshLOD;
140 if (pbs.SculptEntry)
141 lod = BSParam.SculptLOD;
142  
143 // Mega prims usually get more detail because one can interact with shape approximations at this size.
144 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
145 if (maxAxis > BSParam.MeshMegaPrimThreshold)
146 lod = BSParam.MeshMegaPrimLOD;
147  
148 retLod = lod;
149 return pbs.GetMeshKey(size, lod);
150 }
151  
152 // The creation of a mesh or hull can fail if an underlying asset is not available.
153 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
154 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
155 // The first case causes the asset to be fetched. The second case requires
156 // us to not loop forever.
157 // Called after creating a physical mesh or hull. If the physical shape was created,
158 // just return.
159 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
160 {
161 // If the shape was successfully created, nothing more to do
162 if (newShape.HasPhysicalShape)
163 return newShape;
164  
165 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
166 // fetched but we end up here again, the meshing of the asset must have failed.
167 // Prevent trying to keep fetching the mesh by declaring failure.
168 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
169 {
170 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
171 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
172 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
173 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
174 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
175 }
176 else
177 {
178 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
179 if (prim.BaseShape.SculptEntry
180 && !prim.AssetFailed()
181 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
182 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
183 )
184 {
185 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
186 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
187 // Multiple requestors will know we're waiting for this asset
188 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
189  
190 BSPhysObject xprim = prim;
191 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
192 if (assetProvider != null)
193 {
194 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
195 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
196 {
197 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
198 bool assetFound = false;
199 string mismatchIDs = String.Empty; // DEBUG DEBUG
200 if (asset != null && yprim.BaseShape.SculptEntry)
201 {
202 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
203 {
204 yprim.BaseShape.SculptData = asset.Data;
205 // This will cause the prim to see that the filler shape is not the right
206 // one and try again to build the object.
207 // No race condition with the normal shape setting since the rebuild is at taint time.
208 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
209 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
210 assetFound = true;
211 }
212 else
213 {
214 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
215 }
216 }
217 if (!assetFound)
218 {
219 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
220 }
221 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
222 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
223 });
224 }
225 else
226 {
227 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
228 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
229 LogHeader, physicsScene.Name);
230 }
231 }
232 else
233 {
234 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
235 {
236 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
237 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
238 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
239 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
240 }
241 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
242 {
243 physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
244 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
245 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
246 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
247 }
248 }
249 }
250  
251 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
252 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
253 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
254  
255 return fillShape.physShapeInfo;
256 }
257  
258 public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
259 {
260 StringBuilder buff = new StringBuilder(prim.PhysObjectName);
261 buff.Append("/pos=");
262 buff.Append(prim.RawPosition.ToString());
263 if (pScene != null)
264 {
265 buff.Append("/rgn=");
266 buff.Append(pScene.Name);
267 }
268 return buff.ToString();
269 }
270  
271 #endregion // Common shape routines
272 }
273  
274 // ============================================================================================================
275 public class BSShapeNull : BSShape
276 {
277 public BSShapeNull() : base()
278 {
279 }
280 public static BSShape GetReference() { return new BSShapeNull(); }
281 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
282 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
283 }
284  
285 // ============================================================================================================
286 public class BSShapeNative : BSShape
287 {
288 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
289 public BSShapeNative(BulletShape pShape) : base(pShape)
290 {
291 }
292  
293 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
294 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
295 {
296 // Native shapes are not shared and are always built anew.
297 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
298 }
299  
300 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
301 {
302 // Native shapes are not shared so we return a new shape.
303 BSShape ret = null;
304 lock (physShapeInfo)
305 {
306 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
307 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
308 }
309 return ret;
310 }
311  
312 // Make this reference to the physical shape go away since native shapes are not shared.
313 public override void Dereference(BSScene physicsScene)
314 {
315 // Native shapes are not tracked and are released immediately
316 lock (physShapeInfo)
317 {
318 if (physShapeInfo.HasPhysicalShape)
319 {
320 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
321 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
322 }
323 physShapeInfo.Clear();
324 // Garbage collection will free up this instance.
325 }
326 }
327  
328 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
329 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
330 {
331 BulletShape newShape;
332  
333 ShapeData nativeShapeData = new ShapeData();
334 nativeShapeData.Type = shapeType;
335 nativeShapeData.ID = prim.LocalID;
336 nativeShapeData.Scale = prim.Scale;
337 nativeShapeData.Size = prim.Scale;
338 nativeShapeData.MeshKey = (ulong)shapeKey;
339 nativeShapeData.HullKey = (ulong)shapeKey;
340  
341 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
342 {
343 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
344 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
345 }
346 else
347 {
348 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
349 }
350 if (!newShape.HasPhysicalShape)
351 {
352 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
353 LogHeader, prim.LocalID, shapeType);
354 }
355 newShape.shapeType = shapeType;
356 newShape.isNativeShape = true;
357 newShape.shapeKey = (UInt64)shapeKey;
358 return newShape;
359 }
360  
361 }
362  
363 // ============================================================================================================
364 public class BSShapeMesh : BSShape
365 {
366 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
367 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
368  
369 public BSShapeMesh(BulletShape pShape) : base(pShape)
370 {
371 }
372 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
373 {
374 float lod;
375 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
376  
377 BSShapeMesh retMesh = null;
378 lock (Meshes)
379 {
380 if (Meshes.TryGetValue(newMeshKey, out retMesh))
381 {
382 // The mesh has already been created. Return a new reference to same.
383 retMesh.IncrementReference();
384 }
385 else
386 {
387 retMesh = new BSShapeMesh(new BulletShape());
388 // An instance of this mesh has not been created. Build and remember same.
389 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
390  
391 // Check to see if mesh was created (might require an asset).
392 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
393 if (!newShape.isNativeShape || prim.AssetFailed() )
394 {
395 // If a mesh was what was created, remember the built shape for later sharing.
396 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
397 Meshes.Add(newMeshKey, retMesh);
398 }
399  
400 retMesh.physShapeInfo = newShape;
401 }
402 }
403 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
404 return retMesh;
405 }
406 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
407 {
408 BSShape ret = null;
409 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
410 // and we must create a copy of the native shape since they are never shared.
411 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
412 {
413 // TODO: decide when the native shapes should be freed. Check in Dereference?
414 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
415 }
416 else
417 {
418 // Another reference to this shape is just counted.
419 IncrementReference();
420 ret = this;
421 }
422 return ret;
423 }
424 public override void Dereference(BSScene physicsScene)
425 {
426 lock (Meshes)
427 {
428 this.DecrementReference();
429 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
430 // TODO: schedule aging and destruction of unused meshes.
431 }
432 }
433 // Loop through all the known meshes and return the description based on the physical address.
434 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
435 {
436 bool ret = false;
437 BSShapeMesh foundDesc = null;
438 lock (Meshes)
439 {
440 foreach (BSShapeMesh sm in Meshes.Values)
441 {
442 if (sm.physShapeInfo.ReferenceSame(pShape))
443 {
444 foundDesc = sm;
445 ret = true;
446 break;
447 }
448  
449 }
450 }
451 outMesh = foundDesc;
452 return ret;
453 }
454  
455 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
456 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
457 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
458 {
459 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
460 (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) );
461 }
462  
463 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
464 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
465 // The actual build call is passed so this logic can be used by several of the shapes that use a
466 // simple mesh as their base shape.
467 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
468 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
469 {
470 BulletShape newShape = new BulletShape();
471  
472 IMesh meshData = null;
473 lock (physicsScene.mesher)
474 {
475 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
476 false, // say it is not physical so a bounding box is not built
477 false // do not cache the mesh and do not use previously built versions
478 );
479 }
480  
481 if (meshData != null)
482 {
483 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
484 {
485 // Release the fetched asset data once it has been used.
486 pbs.SculptData = new byte[0];
487 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
488 }
489  
490 int[] indices = meshData.getIndexListAsInt();
491 int realIndicesIndex = indices.Length;
492 float[] verticesAsFloats = meshData.getVertexListAsFloat();
493  
494 if (BSParam.ShouldRemoveZeroWidthTriangles)
495 {
496 // Remove degenerate triangles. These are triangles with two of the vertices
497 // are the same. This is complicated by the problem that vertices are not
498 // made unique in sculpties so we have to compare the values in the vertex.
499 realIndicesIndex = 0;
500 for (int tri = 0; tri < indices.Length; tri += 3)
501 {
502 // Compute displacements into vertex array for each vertex of the triangle
503 int v1 = indices[tri + 0] * 3;
504 int v2 = indices[tri + 1] * 3;
505 int v3 = indices[tri + 2] * 3;
506 // Check to see if any two of the vertices are the same
507 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
508 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
509 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
510 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
511 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
512 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
513 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
514 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
515 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
516 )
517 {
518 // None of the vertices of the triangles are the same. This is a good triangle;
519 indices[realIndicesIndex + 0] = indices[tri + 0];
520 indices[realIndicesIndex + 1] = indices[tri + 1];
521 indices[realIndicesIndex + 2] = indices[tri + 2];
522 realIndicesIndex += 3;
523 }
524 }
525 }
526 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
527 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
528  
529 if (realIndicesIndex != 0)
530 {
531 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
532 }
533 else
534 {
535 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
536 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
537 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
538 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
539 }
540 }
541 newShape.shapeKey = newMeshKey;
542  
543 return newShape;
544 }
545 }
546  
547 // ============================================================================================================
548 public class BSShapeHull : BSShape
549 {
550 #pragma warning disable 414
551 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
552 #pragma warning restore 414
553  
554 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
555  
556 public BSShapeHull(BulletShape pShape) : base(pShape)
557 {
558 }
559 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
560 {
561 float lod;
562 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
563  
564 BSShapeHull retHull = null;
565 lock (Hulls)
566 {
567 if (Hulls.TryGetValue(newHullKey, out retHull))
568 {
569 // The mesh has already been created. Return a new reference to same.
570 retHull.IncrementReference();
571 }
572 else
573 {
574 retHull = new BSShapeHull(new BulletShape());
575 // An instance of this mesh has not been created. Build and remember same.
576 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
577  
578 // Check to see if hull was created (might require an asset).
579 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
580 if (!newShape.isNativeShape || prim.AssetFailed())
581 {
582 // If a mesh was what was created, remember the built shape for later sharing.
583 Hulls.Add(newHullKey, retHull);
584 }
585 retHull.physShapeInfo = newShape;
586 }
587 }
588 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
589 return retHull;
590 }
591 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
592 {
593 BSShape ret = null;
594 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
595 // and we must create a copy of the native shape since they are never shared.
596 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
597 {
598 // TODO: decide when the native shapes should be freed. Check in Dereference?
599 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
600 }
601 else
602 {
603 // Another reference to this shape is just counted.
604 IncrementReference();
605 ret = this;
606 }
607 return ret;
608 }
609 public override void Dereference(BSScene physicsScene)
610 {
611 lock (Hulls)
612 {
613 this.DecrementReference();
614 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
615 // TODO: schedule aging and destruction of unused meshes.
616 }
617 }
618 List<ConvexResult> m_hulls;
619 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
620 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
621 {
622 BulletShape newShape = new BulletShape();
623  
624 IMesh meshData = null;
625 List<List<OMV.Vector3>> allHulls = null;
626 lock (physicsScene.mesher)
627 {
628 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
629 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
630  
631 // If we should use the asset's hull info, fetch it out of the locked mesher
632 if (meshData != null && BSParam.ShouldUseAssetHulls)
633 {
634 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
635 if (realMesher != null)
636 {
637 allHulls = realMesher.GetConvexHulls(size);
638 }
639 if (allHulls == null)
640 {
641 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
642 }
643 }
644 }
645  
646 // If there is hull data in the mesh asset, build the hull from that
647 if (allHulls != null && BSParam.ShouldUseAssetHulls)
648 {
649 int hullCount = allHulls.Count;
650 int totalVertices = 1; // include one for the count of the hulls
651 // Using the structure described for HACD hulls, create the memory sturcture
652 // to pass the hull data to the creater.
653 foreach (List<OMV.Vector3> hullVerts in allHulls)
654 {
655 totalVertices += 4; // add four for the vertex count and centroid
656 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
657 }
658 float[] convHulls = new float[totalVertices];
659  
660 convHulls[0] = (float)hullCount;
661 int jj = 1;
662 foreach (List<OMV.Vector3> hullVerts in allHulls)
663 {
664 convHulls[jj + 0] = hullVerts.Count;
665 convHulls[jj + 1] = 0f; // centroid x,y,z
666 convHulls[jj + 2] = 0f;
667 convHulls[jj + 3] = 0f;
668 jj += 4;
669 foreach (OMV.Vector3 oneVert in hullVerts)
670 {
671 convHulls[jj + 0] = oneVert.X;
672 convHulls[jj + 1] = oneVert.Y;
673 convHulls[jj + 2] = oneVert.Z;
674 jj += 3;
675 }
676 }
677  
678 // create the hull data structure in Bullet
679 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
680  
681 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
682 prim.LocalID, hullCount, totalVertices, newShape);
683 }
684  
685 // If no hull specified in the asset and we should use Bullet's HACD approximation...
686 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
687 {
688 // Build the hull shape from an existing mesh shape.
689 // The mesh should have already been created in Bullet.
690 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
691 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
692  
693 if (meshShape.physShapeInfo.HasPhysicalShape)
694 {
695 HACDParams parms;
696 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
697 parms.minClusters = BSParam.BHullMinClusters;
698 parms.compacityWeight = BSParam.BHullCompacityWeight;
699 parms.volumeWeight = BSParam.BHullVolumeWeight;
700 parms.concavity = BSParam.BHullConcavity;
701 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
702 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
703 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
704 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
705  
706 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
707 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
708 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
709  
710 // Now done with the mesh shape.
711 meshShape.Dereference(physicsScene);
712 }
713 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
714 }
715  
716 // If no other hull specifications, use our HACD hull approximation.
717 if (!newShape.HasPhysicalShape && meshData != null)
718 {
719 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
720 {
721 // Release the fetched asset data once it has been used.
722 pbs.SculptData = new byte[0];
723 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
724 }
725  
726 int[] indices = meshData.getIndexListAsInt();
727 List<OMV.Vector3> vertices = meshData.getVertexList();
728  
729 //format conversion from IMesh format to DecompDesc format
730 List<int> convIndices = new List<int>();
731 List<float3> convVertices = new List<float3>();
732 for (int ii = 0; ii < indices.GetLength(0); ii++)
733 {
734 convIndices.Add(indices[ii]);
735 }
736 foreach (OMV.Vector3 vv in vertices)
737 {
738 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
739 }
740  
741 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
742 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
743 {
744 // Simple primitive shapes we know are convex so they are better implemented with
745 // fewer hulls.
746 // Check for simple shape (prim without cuts) and reduce split parameter if so.
747 if (BSShapeCollection.PrimHasNoCuts(pbs))
748 {
749 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
750 }
751 }
752  
753 // setup and do convex hull conversion
754 m_hulls = new List<ConvexResult>();
755 DecompDesc dcomp = new DecompDesc();
756 dcomp.mIndices = convIndices;
757 dcomp.mVertices = convVertices;
758 dcomp.mDepth = maxDepthSplit;
759 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
760 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
761 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
762 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
763 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
764 // create the hull into the _hulls variable
765 convexBuilder.process(dcomp);
766  
767 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
768 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
769  
770 // Convert the vertices and indices for passing to unmanaged.
771 // The hull information is passed as a large floating point array.
772 // The format is:
773 // convHulls[0] = number of hulls
774 // convHulls[1] = number of vertices in first hull
775 // convHulls[2] = hull centroid X coordinate
776 // convHulls[3] = hull centroid Y coordinate
777 // convHulls[4] = hull centroid Z coordinate
778 // convHulls[5] = first hull vertex X
779 // convHulls[6] = first hull vertex Y
780 // convHulls[7] = first hull vertex Z
781 // convHulls[8] = second hull vertex X
782 // ...
783 // convHulls[n] = number of vertices in second hull
784 // convHulls[n+1] = second hull centroid X coordinate
785 // ...
786 //
787 // TODO: is is very inefficient. Someday change the convex hull generator to return
788 // data structures that do not need to be converted in order to pass to Bullet.
789 // And maybe put the values directly into pinned memory rather than marshaling.
790 int hullCount = m_hulls.Count;
791 int totalVertices = 1; // include one for the count of the hulls
792 foreach (ConvexResult cr in m_hulls)
793 {
794 totalVertices += 4; // add four for the vertex count and centroid
795 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
796 }
797 float[] convHulls = new float[totalVertices];
798  
799 convHulls[0] = (float)hullCount;
800 int jj = 1;
801 foreach (ConvexResult cr in m_hulls)
802 {
803 // copy vertices for index access
804 float3[] verts = new float3[cr.HullVertices.Count];
805 int kk = 0;
806 foreach (float3 ff in cr.HullVertices)
807 {
808 verts[kk++] = ff;
809 }
810  
811 // add to the array one hull's worth of data
812 convHulls[jj++] = cr.HullIndices.Count;
813 convHulls[jj++] = 0f; // centroid x,y,z
814 convHulls[jj++] = 0f;
815 convHulls[jj++] = 0f;
816 foreach (int ind in cr.HullIndices)
817 {
818 convHulls[jj++] = verts[ind].x;
819 convHulls[jj++] = verts[ind].y;
820 convHulls[jj++] = verts[ind].z;
821 }
822 }
823 // create the hull data structure in Bullet
824 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
825 }
826 newShape.shapeKey = newHullKey;
827 return newShape;
828 }
829 // Callback from convex hull creater with a newly created hull.
830 // Just add it to our collection of hulls for this shape.
831 private void HullReturn(ConvexResult result)
832 {
833 m_hulls.Add(result);
834 return;
835 }
836 // Loop through all the known hulls and return the description based on the physical address.
837 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
838 {
839 bool ret = false;
840 BSShapeHull foundDesc = null;
841 lock (Hulls)
842 {
843 foreach (BSShapeHull sh in Hulls.Values)
844 {
845 if (sh.physShapeInfo.ReferenceSame(pShape))
846 {
847 foundDesc = sh;
848 ret = true;
849 break;
850 }
851  
852 }
853 }
854 outHull = foundDesc;
855 return ret;
856 }
857 }
858  
859 // ============================================================================================================
860 public class BSShapeCompound : BSShape
861 {
862 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
863 public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>();
864  
865 public BSShapeCompound(BulletShape pShape) : base(pShape)
866 {
867 }
868 public static BSShape GetReference(BSScene physicsScene)
869 {
870 // Base compound shapes are not shared so this returns a raw shape.
871 // A built compound shape can be reused in linksets.
872 BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
873 CompoundShapes.Add(ret.AddrString, ret);
874 return ret;
875 }
876 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
877 {
878 // Calling this reference means we want another handle to an existing compound shape
879 // (usually linksets) so return this copy.
880 IncrementReference();
881 return this;
882 }
883 // Dereferencing a compound shape releases the hold on all the child shapes.
884 public override void Dereference(BSScene physicsScene)
885 {
886 lock (physShapeInfo)
887 {
888 this.DecrementReference();
889 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
890 if (referenceCount <= 0)
891 {
892 if (!physicsScene.PE.IsCompound(physShapeInfo))
893 {
894 // Failed the sanity check!!
895 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
896 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
897 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
898 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
899 return;
900 }
901  
902 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
903 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
904 BSScene.DetailLogZero, physShapeInfo, numChildren);
905  
906 // Loop through all the children dereferencing each.
907 for (int ii = numChildren - 1; ii >= 0; ii--)
908 {
909 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
910 DereferenceAnonCollisionShape(physicsScene, childShape);
911 }
912  
913 lock (CompoundShapes)
914 CompoundShapes.Remove(physShapeInfo.AddrString);
915 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
916 }
917 }
918 }
919 public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
920 {
921 lock (CompoundShapes)
922 {
923 string addr = pShape.AddrString;
924 return CompoundShapes.TryGetValue(addr, out outCompound);
925 }
926 }
927 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
928 {
929 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
930 return cShape;
931 }
932 // Sometimes we have a pointer to a collision shape but don't know what type it is.
933 // Figure out type and call the correct dereference routine.
934 // Called at taint-time.
935 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
936 {
937 // TODO: figure a better way to go through all the shape types and find a possible instance.
938 physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
939 BSScene.DetailLogZero, pShape);
940 BSShapeMesh meshDesc;
941 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
942 {
943 meshDesc.Dereference(physicsScene);
944 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
945 }
946 else
947 {
948 BSShapeHull hullDesc;
949 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
950 {
951 hullDesc.Dereference(physicsScene);
952 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
953 }
954 else
955 {
956 BSShapeConvexHull chullDesc;
957 if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
958 {
959 chullDesc.Dereference(physicsScene);
960 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
961 }
962 else
963 {
964 BSShapeGImpact gImpactDesc;
965 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
966 {
967 gImpactDesc.Dereference(physicsScene);
968 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
969 }
970 else
971 {
972 // Didn't find it in the lists of specific types. It could be compound.
973 BSShapeCompound compoundDesc;
974 if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc))
975 {
976 compoundDesc.Dereference(physicsScene);
977 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
978 }
979 else
980 {
981 // If none of the above, maybe it is a simple native shape.
982 if (physicsScene.PE.IsNativeShape(pShape))
983 {
984 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
985 BSShapeNative nativeShape = new BSShapeNative(pShape);
986 nativeShape.Dereference(physicsScene);
987 }
988 else
989 {
990 physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}",
991 LogHeader, pShape);
992 }
993 }
994 }
995 }
996 }
997 }
998 }
999 }
1000  
1001 // ============================================================================================================
1002 public class BSShapeConvexHull : BSShape
1003 {
1004 #pragma warning disable 414
1005 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
1006 #pragma warning restore 414
1007  
1008 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
1009  
1010 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
1011 {
1012 }
1013 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1014 {
1015 float lod;
1016 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1017  
1018 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
1019 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1020  
1021 BSShapeConvexHull retConvexHull = null;
1022 lock (ConvexHulls)
1023 {
1024 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
1025 {
1026 // The mesh has already been created. Return a new reference to same.
1027 retConvexHull.IncrementReference();
1028 }
1029 else
1030 {
1031 retConvexHull = new BSShapeConvexHull(new BulletShape());
1032 BulletShape convexShape = null;
1033  
1034 // Get a handle to a mesh to build the hull from
1035 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
1036 if (baseMesh.physShapeInfo.isNativeShape)
1037 {
1038 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
1039 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
1040 // get back to this code with a buildable mesh.
1041 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
1042 convexShape = baseMesh.physShapeInfo;
1043 }
1044 else
1045 {
1046 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1047 convexShape.shapeKey = newMeshKey;
1048 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1049 physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}",
1050 BSScene.DetailLogZero, convexShape);
1051 }
1052  
1053 // Done with the base mesh
1054 baseMesh.Dereference(physicsScene);
1055  
1056 retConvexHull.physShapeInfo = convexShape;
1057 }
1058 }
1059 return retConvexHull;
1060 }
1061 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1062 {
1063 // Calling this reference means we want another handle to an existing shape
1064 // (usually linksets) so return this copy.
1065 IncrementReference();
1066 return this;
1067 }
1068 // Dereferencing a compound shape releases the hold on all the child shapes.
1069 public override void Dereference(BSScene physicsScene)
1070 {
1071 lock (ConvexHulls)
1072 {
1073 this.DecrementReference();
1074 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1075 // TODO: schedule aging and destruction of unused meshes.
1076 }
1077 }
1078 // Loop through all the known hulls and return the description based on the physical address.
1079 public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1080 {
1081 bool ret = false;
1082 BSShapeConvexHull foundDesc = null;
1083 lock (ConvexHulls)
1084 {
1085 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1086 {
1087 if (sh.physShapeInfo.ReferenceSame(pShape))
1088 {
1089 foundDesc = sh;
1090 ret = true;
1091 break;
1092 }
1093  
1094 }
1095 }
1096 outHull = foundDesc;
1097 return ret;
1098 }
1099 }
1100 // ============================================================================================================
1101 public class BSShapeGImpact : BSShape
1102 {
1103 #pragma warning disable 414
1104 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1105 #pragma warning restore 414
1106  
1107 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1108  
1109 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1110 {
1111 }
1112 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1113 {
1114 float lod;
1115 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1116  
1117 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1118 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1119  
1120 BSShapeGImpact retGImpact = null;
1121 lock (GImpacts)
1122 {
1123 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1124 {
1125 // The mesh has already been created. Return a new reference to same.
1126 retGImpact.IncrementReference();
1127 }
1128 else
1129 {
1130 retGImpact = new BSShapeGImpact(new BulletShape());
1131 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
1132  
1133 // Check to see if mesh was created (might require an asset).
1134 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1135 newShape.shapeKey = newMeshKey;
1136 if (!newShape.isNativeShape || prim.AssetFailed())
1137 {
1138 // If a mesh was what was created, remember the built shape for later sharing.
1139 // Also note that if meshing failed we put it in the mesh list as there is nothing
1140 // else to do about the mesh.
1141 GImpacts.Add(newMeshKey, retGImpact);
1142 }
1143  
1144 retGImpact.physShapeInfo = newShape;
1145 }
1146 }
1147 return retGImpact;
1148 }
1149  
1150 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1151 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1152 {
1153 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1154 (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) );
1155 }
1156  
1157 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1158 {
1159 BSShape ret = null;
1160 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1161 // and we must create a copy of the native shape since they are never shared.
1162 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1163 {
1164 // TODO: decide when the native shapes should be freed. Check in Dereference?
1165 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1166 }
1167 else
1168 {
1169 // Another reference to this shape is just counted.
1170 IncrementReference();
1171 ret = this;
1172 }
1173 return ret;
1174 }
1175 // Dereferencing a compound shape releases the hold on all the child shapes.
1176 public override void Dereference(BSScene physicsScene)
1177 {
1178 lock (GImpacts)
1179 {
1180 this.DecrementReference();
1181 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1182 // TODO: schedule aging and destruction of unused meshes.
1183 }
1184 }
1185 // Loop through all the known hulls and return the description based on the physical address.
1186 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1187 {
1188 bool ret = false;
1189 BSShapeGImpact foundDesc = null;
1190 lock (GImpacts)
1191 {
1192 foreach (BSShapeGImpact sh in GImpacts.Values)
1193 {
1194 if (sh.physShapeInfo.ReferenceSame(pShape))
1195 {
1196 foundDesc = sh;
1197 ret = true;
1198 break;
1199 }
1200  
1201 }
1202 }
1203 outHull = foundDesc;
1204 return ret;
1205 }
1206 }
1207  
1208 // ============================================================================================================
1209 public class BSShapeAvatar : BSShape
1210 {
1211 #pragma warning disable 414
1212 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
1213 #pragma warning restore 414
1214  
1215 public BSShapeAvatar()
1216 : base()
1217 {
1218 }
1219 public static BSShape GetReference(BSPhysObject prim)
1220 {
1221 return new BSShapeNull();
1222 }
1223 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1224 {
1225 return new BSShapeNull();
1226 }
1227 public override void Dereference(BSScene physicsScene) { }
1228  
1229 // From the front:
1230 // A---A
1231 // / \
1232 // B-------B
1233 // / \ +Z
1234 // C-----------C |
1235 // \ / -Y --+-- +Y
1236 // \ / |
1237 // \ / -Z
1238 // D-----D
1239 // \ /
1240 // E-E
1241  
1242 // From the top A and E are just lines.
1243 // B, C and D are hexagons:
1244 //
1245 // C1--C2 +X
1246 // / \ |
1247 // C0 C3 -Y --+-- +Y
1248 // \ / |
1249 // C5--C4 -X
1250  
1251 // Zero goes directly through the middle so the offsets are from that middle axis
1252 // and up and down from a middle horizon (A and E are the same distance from the zero).
1253 // The height, width and depth is one. All scaling is done by the simulator.
1254  
1255 // Z component -- how far the level is from the middle zero
1256 private const float Aup = 0.5f;
1257 private const float Bup = 0.4f;
1258 private const float Cup = 0.3f;
1259 private const float Dup = -0.4f;
1260 private const float Eup = -0.5f;
1261  
1262 // Y component -- distance from center to x0 and x3
1263 private const float Awid = 0.25f;
1264 private const float Bwid = 0.3f;
1265 private const float Cwid = 0.5f;
1266 private const float Dwid = 0.3f;
1267 private const float Ewid = 0.2f;
1268  
1269 // Y component -- distance from center to x1, x2, x4 and x5
1270 private const float Afwid = 0.0f;
1271 private const float Bfwid = 0.2f;
1272 private const float Cfwid = 0.4f;
1273 private const float Dfwid = 0.2f;
1274 private const float Efwid = 0.0f;
1275  
1276 // X component -- distance from zero to the front or back of a level
1277 private const float Adep = 0f;
1278 private const float Bdep = 0.3f;
1279 private const float Cdep = 0.5f;
1280 private const float Ddep = 0.2f;
1281 private const float Edep = 0f;
1282  
1283 private OMV.Vector3[] avatarVertices = {
1284 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
1285 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
1286  
1287 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
1288 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
1289 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
1290 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
1291 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
1292 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
1293  
1294 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
1295 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
1296 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
1297 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
1298 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
1299 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
1300  
1301 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
1302 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
1303 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
1304 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
1305 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
1306 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
1307  
1308 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
1309 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
1310 };
1311  
1312 // Offsets of the vertices in the vertices array
1313 private enum Ind : int
1314 {
1315 A0, A3,
1316 B0, B1, B2, B3, B4, B5,
1317 C0, C1, C2, C3, C4, C5,
1318 D0, D1, D2, D3, D4, D5,
1319 E0, E3
1320 }
1321  
1322 // Comments specify trianges and quads in clockwise direction
1323 private Ind[] avatarIndices = {
1324 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
1325 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
1326 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
1327 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
1328 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
1329 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
1330  
1331 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
1332 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
1333 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
1334 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
1335 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
1336 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
1337  
1338 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
1339 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
1340 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
1341 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
1342 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
1343 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
1344  
1345 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
1346 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
1347 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
1348 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
1349 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
1350 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
1351  
1352 };
1353  
1354 }
1355 }