aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs1021
1 files changed, 932 insertions, 89 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index c75eb9b..9d47657 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -27,118 +27,287 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Text; 30using System.Text;
32 31
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.ConvexDecompositionDotNet;
35
36using OMV = OpenMetaverse;
37
33namespace OpenSim.Region.Physics.BulletSPlugin 38namespace OpenSim.Region.Physics.BulletSPlugin
34{ 39{
35public abstract class BSShape 40public abstract class BSShape
36{ 41{
37 public IntPtr ptr { get; set; } 42 private static string LogHeader = "[BULLETSIM SHAPE]";
38 public BSPhysicsShapeType type { get; set; } 43
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; } 44 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; } 45 public DateTime lastReferenced { get; set; }
46 public BulletShape physShapeInfo { get; set; }
42 47
43 public BSShape() 48 public BSShape()
44 { 49 {
45 ptr = IntPtr.Zero; 50 referenceCount = 1;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0;
49 lastReferenced = DateTime.Now; 51 lastReferenced = DateTime.Now;
52 physShapeInfo = new BulletShape();
50 } 53 }
51 54 public BSShape(BulletShape pShape)
52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 { 55 {
55 BSShape ret = null; 56 referenceCount = 1;
56 57 lastReferenced = DateTime.Now;
57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 58 physShapeInfo = pShape;
58 { 59 }
59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 }
64
65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 }
73 60
74 if (ret == null) 61 // Get another reference to this shape.
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 62 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
76 63
77 return ret; 64 // Called when this shape is being used again.
78 } 65 // Used internally. External callers should call instance.GetReference() to properly copy/reference
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 66 // the shape.
67 protected virtual void IncrementReference()
80 { 68 {
81 return null; 69 referenceCount++;
70 lastReferenced = DateTime.Now;
82 } 71 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 72
73 // Called when this shape is being used again.
74 protected virtual void DecrementReference()
84 { 75 {
85 return null; 76 referenceCount--;
77 lastReferenced = DateTime.Now;
86 } 78 }
87 79
88 // Release the use of a physical shape. 80 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene); 81 public abstract void Dereference(BSScene physicsScene);
90 82
91 // All shapes have a static call to get a reference to the physical shape 83 // Return 'true' if there is an allocated physics physical shape under this class instance.
92 // protected abstract static BSShape GetReference(); 84 public virtual bool HasPhysicalShape
85 {
86 get
87 {
88 if (physShapeInfo != null)
89 return physShapeInfo.HasPhysicalShape;
90 return false;
91 }
92 }
93 public virtual BSPhysicsShapeType ShapeType
94 {
95 get
96 {
97 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
98 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
99 ret = physShapeInfo.shapeType;
100 return ret;
101 }
102 }
93 103
94 // Returns a string for debugging that uniquily identifies the memory used by this instance 104 // Returns a string for debugging that uniquily identifies the memory used by this instance
95 public string AddrString 105 public virtual string AddrString
96 { 106 {
97 get { return ptr.ToString("X"); } 107 get
108 {
109 if (physShapeInfo != null)
110 return physShapeInfo.AddrString;
111 return "unknown";
112 }
98 } 113 }
99 114
100 public override string ToString() 115 public override string ToString()
101 { 116 {
102 StringBuilder buff = new StringBuilder(); 117 StringBuilder buff = new StringBuilder();
103 buff.Append("<p="); 118 if (physShapeInfo == null)
104 buff.Append(AddrString); 119 {
105 buff.Append(",s="); 120 buff.Append("<noPhys");
106 buff.Append(type.ToString()); 121 }
107 buff.Append(",k="); 122 else
108 buff.Append(key.ToString("X")); 123 {
124 buff.Append("<phy=");
125 buff.Append(physShapeInfo.ToString());
126 }
109 buff.Append(",c="); 127 buff.Append(",c=");
110 buff.Append(referenceCount.ToString()); 128 buff.Append(referenceCount.ToString());
111 buff.Append(">"); 129 buff.Append(">");
112 return buff.ToString(); 130 return buff.ToString();
113 } 131 }
132
133 #region Common shape routines
134 // Create a hash of all the shape parameters to be used as a key for this particular shape.
135 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
136 {
137 // level of detail based on size and type of the object
138 float lod = BSParam.MeshLOD;
139 if (pbs.SculptEntry)
140 lod = BSParam.SculptLOD;
141
142 // Mega prims usually get more detail because one can interact with shape approximations at this size.
143 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
144 if (maxAxis > BSParam.MeshMegaPrimThreshold)
145 lod = BSParam.MeshMegaPrimLOD;
146
147 retLod = lod;
148 return pbs.GetMeshKey(size, lod);
149 }
150
151 // The creation of a mesh or hull can fail if an underlying asset is not available.
152 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
153 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
154 // The first case causes the asset to be fetched. The second case requires
155 // us to not loop forever.
156 // Called after creating a physical mesh or hull. If the physical shape was created,
157 // just return.
158 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
159 {
160 // If the shape was successfully created, nothing more to do
161 if (newShape.HasPhysicalShape)
162 return newShape;
163
164 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
165 // fetched but we end up here again, the meshing of the asset must have failed.
166 // Prevent trying to keep fetching the mesh by declaring failure.
167 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
168 {
169 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
170 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
171 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
172 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
173 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
174 }
175 else
176 {
177 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
178 if (prim.BaseShape.SculptEntry
179 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
180 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
181 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
182 )
183 {
184 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
185 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
186 // Multiple requestors will know we're waiting for this asset
187 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
188
189 BSPhysObject xprim = prim;
190 Util.FireAndForget(delegate
191 {
192 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
193 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
194 if (assetProvider != null)
195 {
196 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
197 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
198 {
199 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
200 bool assetFound = false;
201 string mismatchIDs = String.Empty; // DEBUG DEBUG
202 if (asset != null && yprim.BaseShape.SculptEntry)
203 {
204 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
205 {
206 yprim.BaseShape.SculptData = asset.Data;
207 // This will cause the prim to see that the filler shape is not the right
208 // one and try again to build the object.
209 // No race condition with the normal shape setting since the rebuild is at taint time.
210 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
211 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
212 assetFound = true;
213 }
214 else
215 {
216 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
217 }
218 }
219 if (!assetFound)
220 {
221 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
222 }
223 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
224 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
225 });
226 }
227 else
228 {
229 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
230 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
231 LogHeader, physicsScene.Name);
232 }
233 });
234 }
235 else
236 {
237 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
238 {
239 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
240 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
241 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
242 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
243 }
244 }
245 }
246
247 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
248 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
249 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
250
251 return fillShape.physShapeInfo;
252 }
253
254 #endregion // Common shape routines
114} 255}
115 256
257// ============================================================================================================
116public class BSShapeNull : BSShape 258public class BSShapeNull : BSShape
117{ 259{
118 public BSShapeNull() : base() 260 public BSShapeNull() : base()
119 { 261 {
120 } 262 }
121 public static BSShape GetReference() { return new BSShapeNull(); } 263 public static BSShape GetReference() { return new BSShapeNull(); }
264 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
122 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 265 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
123} 266}
124 267
268// ============================================================================================================
125public class BSShapeNative : BSShape 269public class BSShapeNative : BSShape
126{ 270{
127 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; 271 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
128 public BSShapeNative() : base() 272 public BSShapeNative(BulletShape pShape) : base(pShape)
129 { 273 {
130 } 274 }
131 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 275
132 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 276 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
277 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
133 { 278 {
134 // Native shapes are not shared and are always built anew. 279 // Native shapes are not shared and are always built anew.
135 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 280 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
136 return null; 281 }
282
283 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
284 {
285 // Native shapes are not shared so we return a new shape.
286 return new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
287 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey) );
137 } 288 }
138 289
139 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 290 // Make this reference to the physical shape go away since native shapes are not shared.
140 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 291 public override void Dereference(BSScene physicsScene)
141 { 292 {
293 // Native shapes are not tracked and are released immediately
294 lock (physShapeInfo)
295 {
296 if (physShapeInfo.HasPhysicalShape)
297 {
298 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
299 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
300 }
301 physShapeInfo.Clear();
302 // Garbage collection will free up this instance.
303 }
304 }
305
306 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
307 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
308 {
309 BulletShape newShape;
310
142 ShapeData nativeShapeData = new ShapeData(); 311 ShapeData nativeShapeData = new ShapeData();
143 nativeShapeData.Type = shapeType; 312 nativeShapeData.Type = shapeType;
144 nativeShapeData.ID = prim.LocalID; 313 nativeShapeData.ID = prim.LocalID;
@@ -147,86 +316,760 @@ public class BSShapeNative : BSShape
147 nativeShapeData.MeshKey = (ulong)shapeKey; 316 nativeShapeData.MeshKey = (ulong)shapeKey;
148 nativeShapeData.HullKey = (ulong)shapeKey; 317 nativeShapeData.HullKey = (ulong)shapeKey;
149 318
150
151 /*
152 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 319 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
153 { 320 {
154 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); 321 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
155 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 322 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
156 } 323 }
157 else 324 else
158 { 325 {
159 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); 326 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
160 } 327 }
161 if (ptr == IntPtr.Zero) 328 if (!newShape.HasPhysicalShape)
162 { 329 {
163 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 330 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
164 LogHeader, prim.LocalID, shapeType); 331 LogHeader, prim.LocalID, shapeType);
165 } 332 }
166 type = shapeType; 333 newShape.shapeType = shapeType;
167 key = (UInt64)shapeKey; 334 newShape.isNativeShape = true;
168 */ 335 newShape.shapeKey = (UInt64)shapeKey;
169 } 336 return newShape;
170 // Make this reference to the physical shape go away since native shapes are not shared.
171 public override void Dereference(BSScene physicsScene)
172 {
173 /*
174 // Native shapes are not tracked and are released immediately
175 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
176 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
177 ptr = IntPtr.Zero;
178 // Garbage collection will free up this instance.
179 */
180 } 337 }
338
181} 339}
182 340
341// ============================================================================================================
183public class BSShapeMesh : BSShape 342public class BSShapeMesh : BSShape
184{ 343{
185 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 344 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
186 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 345 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
187 346
188 public BSShapeMesh() : base() 347 public BSShapeMesh(BulletShape pShape) : base(pShape)
189 { 348 {
190 } 349 }
191 public static BSShape GetReference() { return new BSShapeNull(); } 350 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
192 public override void Dereference(BSScene physicsScene) { } 351 {
352 float lod;
353 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
354
355 BSShapeMesh retMesh = null;
356 lock (Meshes)
357 {
358 if (Meshes.TryGetValue(newMeshKey, out retMesh))
359 {
360 // The mesh has already been created. Return a new reference to same.
361 retMesh.IncrementReference();
362 }
363 else
364 {
365 retMesh = new BSShapeMesh(new BulletShape());
366 // An instance of this mesh has not been created. Build and remember same.
367 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
368
369 // Check to see if mesh was created (might require an asset).
370 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
371 if (!newShape.isNativeShape)
372 {
373 // If a mesh was what was created, remember the built shape for later sharing.
374 Meshes.Add(newMeshKey, retMesh);
375 }
376
377 retMesh.physShapeInfo = newShape;
378 }
379 }
380 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
381 return retMesh;
382 }
383 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
384 {
385 // Another reference to this shape is just counted.
386 IncrementReference();
387 return this;
388 }
389 public override void Dereference(BSScene physicsScene)
390 {
391 lock (Meshes)
392 {
393 this.DecrementReference();
394 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
395 // TODO: schedule aging and destruction of unused meshes.
396 }
397 }
398 // Loop through all the known meshes and return the description based on the physical address.
399 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
400 {
401 bool ret = false;
402 BSShapeMesh foundDesc = null;
403 lock (Meshes)
404 {
405 foreach (BSShapeMesh sm in Meshes.Values)
406 {
407 if (sm.physShapeInfo.ReferenceSame(pShape))
408 {
409 foundDesc = sm;
410 ret = true;
411 break;
412 }
413
414 }
415 }
416 outMesh = foundDesc;
417 return ret;
418 }
419 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
420 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
421 {
422 BulletShape newShape = new BulletShape();
423
424 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
425 false, // say it is not physical so a bounding box is not built
426 false // do not cache the mesh and do not use previously built versions
427 );
428
429 if (meshData != null)
430 {
431 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
432 {
433 // Release the fetched asset data once it has been used.
434 pbs.SculptData = new byte[0];
435 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
436 }
437
438 int[] indices = meshData.getIndexListAsInt();
439 int realIndicesIndex = indices.Length;
440 float[] verticesAsFloats = meshData.getVertexListAsFloat();
441
442 if (BSParam.ShouldRemoveZeroWidthTriangles)
443 {
444 // Remove degenerate triangles. These are triangles with two of the vertices
445 // are the same. This is complicated by the problem that vertices are not
446 // made unique in sculpties so we have to compare the values in the vertex.
447 realIndicesIndex = 0;
448 for (int tri = 0; tri < indices.Length; tri += 3)
449 {
450 // Compute displacements into vertex array for each vertex of the triangle
451 int v1 = indices[tri + 0] * 3;
452 int v2 = indices[tri + 1] * 3;
453 int v3 = indices[tri + 2] * 3;
454 // Check to see if any two of the vertices are the same
455 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
456 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
457 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
458 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
459 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
460 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
461 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
462 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
463 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
464 )
465 {
466 // None of the vertices of the triangles are the same. This is a good triangle;
467 indices[realIndicesIndex + 0] = indices[tri + 0];
468 indices[realIndicesIndex + 1] = indices[tri + 1];
469 indices[realIndicesIndex + 2] = indices[tri + 2];
470 realIndicesIndex += 3;
471 }
472 }
473 }
474 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
475 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
476
477 if (realIndicesIndex != 0)
478 {
479 newShape = physicsScene.PE.CreateMeshShape(physicsScene.World,
480 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
481 }
482 else
483 {
484 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
485 LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name);
486 }
487 }
488 newShape.shapeKey = newMeshKey;
489
490 return newShape;
491 }
193} 492}
194 493
494// ============================================================================================================
195public class BSShapeHull : BSShape 495public class BSShapeHull : BSShape
196{ 496{
197 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 497 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
198 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 498 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
199 499
200 public BSShapeHull() : base() 500 public BSShapeHull(BulletShape pShape) : base(pShape)
201 { 501 {
202 } 502 }
203 public static BSShape GetReference() { return new BSShapeNull(); } 503 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
204 public override void Dereference(BSScene physicsScene) { } 504 {
505 float lod;
506 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
507
508 BSShapeHull retHull = null;
509 lock (Hulls)
510 {
511 if (Hulls.TryGetValue(newHullKey, out retHull))
512 {
513 // The mesh has already been created. Return a new reference to same.
514 retHull.IncrementReference();
515 }
516 else
517 {
518 retHull = new BSShapeHull(new BulletShape());
519 // An instance of this mesh has not been created. Build and remember same.
520 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
521
522 // Check to see if hull was created (might require an asset).
523 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
524 if (!newShape.isNativeShape)
525 {
526 // If a mesh was what was created, remember the built shape for later sharing.
527 Hulls.Add(newHullKey, retHull);
528 }
529 retHull.physShapeInfo = newShape;
530 }
531 }
532 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
533 return retHull;
534 }
535 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
536 {
537 // Another reference to this shape is just counted.
538 IncrementReference();
539 return this;
540 }
541 public override void Dereference(BSScene physicsScene)
542 {
543 lock (Hulls)
544 {
545 this.DecrementReference();
546 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
547 // TODO: schedule aging and destruction of unused meshes.
548 }
549 }
550 List<ConvexResult> m_hulls;
551 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
552 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
553 {
554 BulletShape newShape = new BulletShape();
555 IntPtr hullPtr = IntPtr.Zero;
556
557 if (BSParam.ShouldUseBulletHACD)
558 {
559 // Build the hull shape from an existing mesh shape.
560 // The mesh should have already been created in Bullet.
561 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID);
562 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
563
564 if (meshShape.physShapeInfo.HasPhysicalShape)
565 {
566 HACDParams parms;
567 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
568 parms.minClusters = BSParam.BHullMinClusters;
569 parms.compacityWeight = BSParam.BHullCompacityWeight;
570 parms.volumeWeight = BSParam.BHullVolumeWeight;
571 parms.concavity = BSParam.BHullConcavity;
572 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
573 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
574 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
575 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
576
577 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
578 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
579 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
580
581 // Now done with the mesh shape.
582 meshShape.Dereference(physicsScene);
583 }
584 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
585 }
586 if (!newShape.HasPhysicalShape)
587 {
588 // Build a new hull in the physical world using the C# HACD algorigthm.
589 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
590 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
591 if (meshData != null)
592 {
593 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
594 {
595 // Release the fetched asset data once it has been used.
596 pbs.SculptData = new byte[0];
597 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
598 }
599
600 int[] indices = meshData.getIndexListAsInt();
601 List<OMV.Vector3> vertices = meshData.getVertexList();
602
603 //format conversion from IMesh format to DecompDesc format
604 List<int> convIndices = new List<int>();
605 List<float3> convVertices = new List<float3>();
606 for (int ii = 0; ii < indices.GetLength(0); ii++)
607 {
608 convIndices.Add(indices[ii]);
609 }
610 foreach (OMV.Vector3 vv in vertices)
611 {
612 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
613 }
614
615 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
616 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
617 {
618 // Simple primitive shapes we know are convex so they are better implemented with
619 // fewer hulls.
620 // Check for simple shape (prim without cuts) and reduce split parameter if so.
621 if (BSShapeCollection.PrimHasNoCuts(pbs))
622 {
623 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
624 }
625 }
626
627 // setup and do convex hull conversion
628 m_hulls = new List<ConvexResult>();
629 DecompDesc dcomp = new DecompDesc();
630 dcomp.mIndices = convIndices;
631 dcomp.mVertices = convVertices;
632 dcomp.mDepth = maxDepthSplit;
633 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
634 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
635 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
636 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
637 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
638 // create the hull into the _hulls variable
639 convexBuilder.process(dcomp);
640
641 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
642 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
643
644 // Convert the vertices and indices for passing to unmanaged.
645 // The hull information is passed as a large floating point array.
646 // The format is:
647 // convHulls[0] = number of hulls
648 // convHulls[1] = number of vertices in first hull
649 // convHulls[2] = hull centroid X coordinate
650 // convHulls[3] = hull centroid Y coordinate
651 // convHulls[4] = hull centroid Z coordinate
652 // convHulls[5] = first hull vertex X
653 // convHulls[6] = first hull vertex Y
654 // convHulls[7] = first hull vertex Z
655 // convHulls[8] = second hull vertex X
656 // ...
657 // convHulls[n] = number of vertices in second hull
658 // convHulls[n+1] = second hull centroid X coordinate
659 // ...
660 //
661 // TODO: is is very inefficient. Someday change the convex hull generator to return
662 // data structures that do not need to be converted in order to pass to Bullet.
663 // And maybe put the values directly into pinned memory rather than marshaling.
664 int hullCount = m_hulls.Count;
665 int totalVertices = 1; // include one for the count of the hulls
666 foreach (ConvexResult cr in m_hulls)
667 {
668 totalVertices += 4; // add four for the vertex count and centroid
669 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
670 }
671 float[] convHulls = new float[totalVertices];
672
673 convHulls[0] = (float)hullCount;
674 int jj = 1;
675 foreach (ConvexResult cr in m_hulls)
676 {
677 // copy vertices for index access
678 float3[] verts = new float3[cr.HullVertices.Count];
679 int kk = 0;
680 foreach (float3 ff in cr.HullVertices)
681 {
682 verts[kk++] = ff;
683 }
684
685 // add to the array one hull's worth of data
686 convHulls[jj++] = cr.HullIndices.Count;
687 convHulls[jj++] = 0f; // centroid x,y,z
688 convHulls[jj++] = 0f;
689 convHulls[jj++] = 0f;
690 foreach (int ind in cr.HullIndices)
691 {
692 convHulls[jj++] = verts[ind].x;
693 convHulls[jj++] = verts[ind].y;
694 convHulls[jj++] = verts[ind].z;
695 }
696 }
697 // create the hull data structure in Bullet
698 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
699 }
700 newShape.shapeKey = newHullKey;
701 }
702 return newShape;
703 }
704 // Callback from convex hull creater with a newly created hull.
705 // Just add it to our collection of hulls for this shape.
706 private void HullReturn(ConvexResult result)
707 {
708 m_hulls.Add(result);
709 return;
710 }
711 // Loop through all the known hulls and return the description based on the physical address.
712 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
713 {
714 bool ret = false;
715 BSShapeHull foundDesc = null;
716 lock (Hulls)
717 {
718 foreach (BSShapeHull sh in Hulls.Values)
719 {
720 if (sh.physShapeInfo.ReferenceSame(pShape))
721 {
722 foundDesc = sh;
723 ret = true;
724 break;
725 }
726
727 }
728 }
729 outHull = foundDesc;
730 return ret;
731 }
205} 732}
206 733
734// ============================================================================================================
207public class BSShapeCompound : BSShape 735public class BSShapeCompound : BSShape
208{ 736{
209 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 737 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
210 public BSShapeCompound() : base() 738 public BSShapeCompound(BulletShape pShape) : base(pShape)
211 { 739 {
212 } 740 }
213 public static BSShape GetReference(BSPhysObject prim) 741 public static BSShape GetReference(BSScene physicsScene)
214 { 742 {
215 return new BSShapeNull(); 743 // Base compound shapes are not shared so this returns a raw shape.
744 // A built compound shape can be reused in linksets.
745 return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
746 }
747 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
748 {
749 // Calling this reference means we want another handle to an existing compound shape
750 // (usually linksets) so return this copy.
751 IncrementReference();
752 return this;
753 }
754 // Dereferencing a compound shape releases the hold on all the child shapes.
755 public override void Dereference(BSScene physicsScene)
756 {
757 lock (physShapeInfo)
758 {
759 this.DecrementReference();
760 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
761 if (referenceCount <= 0)
762 {
763 if (!physicsScene.PE.IsCompound(physShapeInfo))
764 {
765 // Failed the sanity check!!
766 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
767 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
768 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
769 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
770 return;
771 }
772
773 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
774 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
775 BSScene.DetailLogZero, physShapeInfo, numChildren);
776
777 // Loop through all the children dereferencing each.
778 for (int ii = numChildren - 1; ii >= 0; ii--)
779 {
780 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
781 DereferenceAnonCollisionShape(physicsScene, childShape);
782 }
783 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
784 }
785 }
786 }
787 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
788 {
789 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
790 return cShape;
791 }
792 // Sometimes we have a pointer to a collision shape but don't know what type it is.
793 // Figure out type and call the correct dereference routine.
794 // Called at taint-time.
795 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
796 {
797 BSShapeMesh meshDesc;
798 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
799 {
800 meshDesc.Dereference(physicsScene);
801 }
802 else
803 {
804 BSShapeHull hullDesc;
805 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
806 {
807 hullDesc.Dereference(physicsScene);
808 }
809 else
810 {
811 BSShapeConvexHull chullDesc;
812 if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc))
813 {
814 chullDesc.Dereference(physicsScene);
815 }
816 else
817 {
818 if (physicsScene.PE.IsCompound(pShape))
819 {
820 BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
821 recursiveCompound.Dereference(physicsScene);
822 }
823 else
824 {
825 if (physicsScene.PE.IsNativeShape(pShape))
826 {
827 BSShapeNative nativeShape = new BSShapeNative(pShape);
828 nativeShape.Dereference(physicsScene);
829 }
830 }
831 }
832 }
833 }
216 } 834 }
217 public override void Dereference(BSScene physicsScene) { }
218} 835}
219 836
837// ============================================================================================================
838public class BSShapeConvexHull : BSShape
839{
840 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
841 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
842
843 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
844 {
845 }
846 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
847 {
848 float lod;
849 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
850
851 physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}",
852 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
853
854 BSShapeConvexHull retConvexHull = null;
855 lock (ConvexHulls)
856 {
857 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
858 {
859 // The mesh has already been created. Return a new reference to same.
860 retConvexHull.IncrementReference();
861 }
862 else
863 {
864 retConvexHull = new BSShapeConvexHull(new BulletShape());
865 BulletShape convexShape = null;
866
867 // Get a handle to a mesh to build the hull from
868 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
869 if (baseMesh.physShapeInfo.isNativeShape)
870 {
871 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
872 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
873 // get back to this code with a buildable mesh.
874 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
875 convexShape = baseMesh.physShapeInfo;
876 }
877 else
878 {
879 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
880 convexShape.shapeKey = newMeshKey;
881 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
882 }
883
884 // Done with the base mesh
885 baseMesh.Dereference(physicsScene);
886
887 retConvexHull.physShapeInfo = convexShape;
888 }
889 }
890 return retConvexHull;
891 }
892 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
893 {
894 // Calling this reference means we want another handle to an existing shape
895 // (usually linksets) so return this copy.
896 IncrementReference();
897 return this;
898 }
899 // Dereferencing a compound shape releases the hold on all the child shapes.
900 public override void Dereference(BSScene physicsScene)
901 {
902 lock (ConvexHulls)
903 {
904 this.DecrementReference();
905 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
906 // TODO: schedule aging and destruction of unused meshes.
907 }
908 }
909 // Loop through all the known hulls and return the description based on the physical address.
910 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
911 {
912 bool ret = false;
913 BSShapeConvexHull foundDesc = null;
914 lock (ConvexHulls)
915 {
916 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
917 {
918 if (sh.physShapeInfo.ReferenceSame(pShape))
919 {
920 foundDesc = sh;
921 ret = true;
922 break;
923 }
924
925 }
926 }
927 outHull = foundDesc;
928 return ret;
929 }
930}
931
932// ============================================================================================================
220public class BSShapeAvatar : BSShape 933public class BSShapeAvatar : BSShape
221{ 934{
222 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; 935 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
223 public BSShapeAvatar() : base() 936 public BSShapeAvatar() : base()
224 { 937 {
225 } 938 }
226 public static BSShape GetReference(BSPhysObject prim) 939 public static BSShape GetReference(BSPhysObject prim)
227 { 940 {
941 return new BSShapeNull();
942 }
943 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
944 {
228 return new BSShapeNull(); 945 return new BSShapeNull();
229 } 946 }
230 public override void Dereference(BSScene physicsScene) { } 947 public override void Dereference(BSScene physicsScene) { }
948
949 // From the front:
950 // A---A
951 // / \
952 // B-------B
953 // / \ +Z
954 // C-----------C |
955 // \ / -Y --+-- +Y
956 // \ / |
957 // \ / -Z
958 // D-----D
959 // \ /
960 // E-E
961
962 // From the top A and E are just lines.
963 // B, C and D are hexagons:
964 //
965 // C1--C2 +X
966 // / \ |
967 // C0 C3 -Y --+-- +Y
968 // \ / |
969 // C5--C4 -X
970
971 // Zero goes directly through the middle so the offsets are from that middle axis
972 // and up and down from a middle horizon (A and E are the same distance from the zero).
973 // The height, width and depth is one. All scaling is done by the simulator.
974
975 // Z component -- how far the level is from the middle zero
976 private const float Aup = 0.5f;
977 private const float Bup = 0.4f;
978 private const float Cup = 0.3f;
979 private const float Dup = -0.4f;
980 private const float Eup = -0.5f;
981
982 // Y component -- distance from center to x0 and x3
983 private const float Awid = 0.25f;
984 private const float Bwid = 0.3f;
985 private const float Cwid = 0.5f;
986 private const float Dwid = 0.3f;
987 private const float Ewid = 0.2f;
988
989 // Y component -- distance from center to x1, x2, x4 and x5
990 private const float Afwid = 0.0f;
991 private const float Bfwid = 0.2f;
992 private const float Cfwid = 0.4f;
993 private const float Dfwid = 0.2f;
994 private const float Efwid = 0.0f;
995
996 // X component -- distance from zero to the front or back of a level
997 private const float Adep = 0f;
998 private const float Bdep = 0.3f;
999 private const float Cdep = 0.5f;
1000 private const float Ddep = 0.2f;
1001 private const float Edep = 0f;
1002
1003 private OMV.Vector3[] avatarVertices = {
1004 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
1005 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
1006
1007 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
1008 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
1009 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
1010 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
1011 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
1012 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
1013
1014 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
1015 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
1016 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
1017 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
1018 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
1019 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
1020
1021 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
1022 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
1023 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
1024 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
1025 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
1026 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
1027
1028 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
1029 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
1030 };
1031
1032 // Offsets of the vertices in the vertices array
1033 private enum Ind : int
1034 {
1035 A0, A3,
1036 B0, B1, B2, B3, B4, B5,
1037 C0, C1, C2, C3, C4, C5,
1038 D0, D1, D2, D3, D4, D5,
1039 E0, E3
1040 }
1041
1042 // Comments specify trianges and quads in clockwise direction
1043 private Ind[] avatarIndices = {
1044 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
1045 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
1046 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
1047 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
1048 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
1049 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
1050
1051 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
1052 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
1053 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
1054 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
1055 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
1056 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
1057
1058 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
1059 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
1060 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
1061 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
1062 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
1063 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
1064
1065 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
1066 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
1067 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
1068 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
1069 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
1070 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
1071
1072 };
1073
231} 1074}
232} 1075}