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