diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 716 |
1 files changed, 634 insertions, 82 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index dd5ae1a..1008184 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -31,6 +31,7 @@ using System.Text; | |||
31 | 31 | ||
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.Physics.Manager; |
34 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
34 | 35 | ||
35 | using OMV = OpenMetaverse; | 36 | using OMV = OpenMetaverse; |
36 | 37 | ||
@@ -38,74 +39,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
38 | { | 39 | { |
39 | public abstract class BSShape | 40 | public abstract class BSShape |
40 | { | 41 | { |
42 | private static string LogHeader = "[BULLETSIM SHAPE]"; | ||
43 | |||
41 | public int referenceCount { get; set; } | 44 | public int referenceCount { get; set; } |
42 | public DateTime lastReferenced { get; set; } | 45 | public DateTime lastReferenced { get; set; } |
43 | public BulletShape physShapeInfo { get; set; } | 46 | public BulletShape physShapeInfo { get; set; } |
44 | 47 | ||
45 | public BSShape() | 48 | public BSShape() |
46 | { | 49 | { |
47 | referenceCount = 0; | 50 | referenceCount = 1; |
48 | lastReferenced = DateTime.Now; | 51 | lastReferenced = DateTime.Now; |
49 | physShapeInfo = new BulletShape(); | 52 | physShapeInfo = new BulletShape(); |
50 | } | 53 | } |
51 | public BSShape(BulletShape pShape) | 54 | public BSShape(BulletShape pShape) |
52 | { | 55 | { |
53 | referenceCount = 0; | 56 | referenceCount = 1; |
54 | lastReferenced = DateTime.Now; | 57 | lastReferenced = DateTime.Now; |
55 | physShapeInfo = pShape; | 58 | physShapeInfo = pShape; |
56 | } | 59 | } |
57 | 60 | ||
58 | // Get a reference to a physical shape. Create if it doesn't exist | 61 | // Get another reference to this shape. |
59 | public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 62 | public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); |
60 | { | ||
61 | BSShape ret = null; | ||
62 | |||
63 | if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
64 | { | ||
65 | // an avatar capsule is close to a native shape (it is not shared) | ||
66 | ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, | ||
67 | FixedShapeKey.KEY_CAPSULE); | ||
68 | physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); | ||
69 | } | ||
70 | |||
71 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
72 | // This isn't too great a hardship since most of the child shapes will have already been created. | ||
73 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
74 | { | ||
75 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
76 | ret = BSShapeCompound.GetReference(prim); | ||
77 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); | ||
78 | } | ||
79 | |||
80 | // Avatars have their own unique shape | ||
81 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR) | ||
82 | { | ||
83 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
84 | ret = BSShapeAvatar.GetReference(prim); | ||
85 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret); | ||
86 | } | ||
87 | |||
88 | if (ret == null) | ||
89 | ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
94 | { | ||
95 | BSShapeMesh.GetReference(physicsScene, forceRebuild, prim); | ||
96 | BSShapeHull.GetReference(physicsScene, forceRebuild, prim); | ||
97 | return null; | ||
98 | } | ||
99 | 63 | ||
100 | // Called when this shape is being used again. | 64 | // Called when this shape is being used again. |
101 | public virtual void IncrementReference() | 65 | // Used internally. External callers should call instance.GetReference() to properly copy/reference |
66 | // the shape. | ||
67 | protected virtual void IncrementReference() | ||
102 | { | 68 | { |
103 | referenceCount++; | 69 | referenceCount++; |
104 | lastReferenced = DateTime.Now; | 70 | lastReferenced = DateTime.Now; |
105 | } | 71 | } |
106 | 72 | ||
107 | // Called when this shape is being used again. | 73 | // Called when this shape is being used again. |
108 | public virtual void DecrementReference() | 74 | protected virtual void DecrementReference() |
109 | { | 75 | { |
110 | referenceCount--; | 76 | referenceCount--; |
111 | lastReferenced = DateTime.Now; | 77 | lastReferenced = DateTime.Now; |
@@ -114,22 +80,178 @@ public abstract class BSShape | |||
114 | // Release the use of a physical shape. | 80 | // Release the use of a physical shape. |
115 | public abstract void Dereference(BSScene physicsScene); | 81 | public abstract void Dereference(BSScene physicsScene); |
116 | 82 | ||
83 | // Return 'true' if there is an allocated physics physical shape under this class instance. | ||
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 | } | ||
103 | |||
117 | // 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 |
118 | public virtual string AddrString | 105 | public virtual string AddrString |
119 | { | 106 | { |
120 | get { return "unknown"; } | 107 | get |
108 | { | ||
109 | if (physShapeInfo != null) | ||
110 | return physShapeInfo.AddrString; | ||
111 | return "unknown"; | ||
112 | } | ||
121 | } | 113 | } |
122 | 114 | ||
123 | public override string ToString() | 115 | public override string ToString() |
124 | { | 116 | { |
125 | StringBuilder buff = new StringBuilder(); | 117 | StringBuilder buff = new StringBuilder(); |
126 | buff.Append("<p="); | 118 | if (physShapeInfo == null) |
127 | buff.Append(AddrString); | 119 | { |
120 | buff.Append(",noPhys"); | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | buff.Append(",phy="); | ||
125 | buff.Append(physShapeInfo.ToString()); | ||
126 | } | ||
128 | buff.Append(",c="); | 127 | buff.Append(",c="); |
129 | buff.Append(referenceCount.ToString()); | 128 | buff.Append(referenceCount.ToString()); |
130 | buff.Append(">"); | 129 | buff.Append(">"); |
131 | return buff.ToString(); | 130 | return buff.ToString(); |
132 | } | 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 | ||
133 | } | 255 | } |
134 | 256 | ||
135 | // ============================================================================================================ | 257 | // ============================================================================================================ |
@@ -139,6 +261,7 @@ public class BSShapeNull : BSShape | |||
139 | { | 261 | { |
140 | } | 262 | } |
141 | 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(); } | ||
142 | 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 */ } |
143 | } | 266 | } |
144 | 267 | ||
@@ -150,24 +273,34 @@ public class BSShapeNative : BSShape | |||
150 | { | 273 | { |
151 | } | 274 | } |
152 | 275 | ||
153 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, | 276 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, |
154 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | 277 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) |
155 | { | 278 | { |
156 | // Native shapes are not shared and are always built anew. | 279 | // Native shapes are not shared and are always built anew. |
157 | return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); | 280 | return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); |
158 | } | 281 | } |
159 | 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) ); | ||
288 | } | ||
289 | |||
160 | // Make this reference to the physical shape go away since native shapes are not shared. | 290 | // Make this reference to the physical shape go away since native shapes are not shared. |
161 | public override void Dereference(BSScene physicsScene) | 291 | public override void Dereference(BSScene physicsScene) |
162 | { | 292 | { |
163 | // Native shapes are not tracked and are released immediately | 293 | // Native shapes are not tracked and are released immediately |
164 | if (physShapeInfo.HasPhysicalShape) | 294 | lock (physShapeInfo) |
165 | { | 295 | { |
166 | physicsScene.DetailLog("{0},BSShapeNative.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | 296 | if (physShapeInfo.HasPhysicalShape) |
167 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | 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. | ||
168 | } | 303 | } |
169 | physShapeInfo.Clear(); | ||
170 | // Garbage collection will free up this instance. | ||
171 | } | 304 | } |
172 | 305 | ||
173 | private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, | 306 | private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, |
@@ -197,7 +330,7 @@ public class BSShapeNative : BSShape | |||
197 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 330 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
198 | LogHeader, prim.LocalID, shapeType); | 331 | LogHeader, prim.LocalID, shapeType); |
199 | } | 332 | } |
200 | newShape.type = shapeType; | 333 | newShape.shapeType = shapeType; |
201 | newShape.isNativeShape = true; | 334 | newShape.isNativeShape = true; |
202 | newShape.shapeKey = (UInt64)shapeKey; | 335 | newShape.shapeKey = (UInt64)shapeKey; |
203 | return newShape; | 336 | return newShape; |
@@ -209,7 +342,7 @@ public class BSShapeNative : BSShape | |||
209 | public class BSShapeMesh : BSShape | 342 | public class BSShapeMesh : BSShape |
210 | { | 343 | { |
211 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; | 344 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; |
212 | 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>(); |
213 | 346 | ||
214 | public BSShapeMesh(BulletShape pShape) : base(pShape) | 347 | public BSShapeMesh(BulletShape pShape) : base(pShape) |
215 | { | 348 | { |
@@ -217,12 +350,9 @@ public class BSShapeMesh : BSShape | |||
217 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 350 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) |
218 | { | 351 | { |
219 | float lod; | 352 | float lod; |
220 | System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 353 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
221 | 354 | ||
222 | physicsScene.DetailLog("{0},BSShapeMesh,create,oldKey={1},newKey={2},size={3},lod={4}", | 355 | BSShapeMesh retMesh = null; |
223 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); | ||
224 | |||
225 | BSShapeMesh retMesh; | ||
226 | lock (Meshes) | 356 | lock (Meshes) |
227 | { | 357 | { |
228 | if (Meshes.TryGetValue(newMeshKey, out retMesh)) | 358 | if (Meshes.TryGetValue(newMeshKey, out retMesh)) |
@@ -232,39 +362,80 @@ public class BSShapeMesh : BSShape | |||
232 | } | 362 | } |
233 | else | 363 | else |
234 | { | 364 | { |
365 | retMesh = new BSShapeMesh(new BulletShape()); | ||
235 | // An instance of this mesh has not been created. Build and remember same. | 366 | // An instance of this mesh has not been created. Build and remember same. |
236 | BulletShape newShape = CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | 367 | BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); |
237 | // Take evasive action if the mesh was not constructed. | ||
238 | newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); | ||
239 | 368 | ||
240 | retMesh = new BSShapeMesh(newShape); | 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 | } | ||
241 | 376 | ||
242 | Meshes.Add(newMeshKey, retMesh); | 377 | retMesh.physShapeInfo = newShape; |
243 | } | 378 | } |
244 | } | 379 | } |
380 | physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); | ||
245 | return retMesh; | 381 | return retMesh; |
246 | } | 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 | } | ||
247 | public override void Dereference(BSScene physicsScene) | 389 | public override void Dereference(BSScene physicsScene) |
248 | { | 390 | { |
249 | lock (Meshes) | 391 | lock (Meshes) |
250 | { | 392 | { |
251 | this.DecrementReference(); | 393 | this.DecrementReference(); |
394 | physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
252 | // TODO: schedule aging and destruction of unused meshes. | 395 | // TODO: schedule aging and destruction of unused meshes. |
253 | } | 396 | } |
254 | } | 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 | } | ||
255 | 413 | ||
256 | private static BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | 414 | } |
415 | } | ||
416 | outMesh = foundDesc; | ||
417 | return ret; | ||
418 | } | ||
419 | private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
257 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 420 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
258 | { | 421 | { |
259 | BulletShape newShape = null; | 422 | BulletShape newShape = new BulletShape(); |
260 | 423 | ||
261 | IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, | 424 | IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, |
262 | false, // say it is not physical so a bounding box is not built | 425 | false, // say it is not physical so a bounding box is not built |
263 | false // do not cache the mesh and do not use previously built versions | 426 | false, // do not cache the mesh and do not use previously built versions |
427 | false, | ||
428 | false | ||
264 | ); | 429 | ); |
265 | 430 | ||
266 | if (meshData != null) | 431 | if (meshData != null) |
267 | { | 432 | { |
433 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
434 | { | ||
435 | // Release the fetched asset data once it has been used. | ||
436 | pbs.SculptData = new byte[0]; | ||
437 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
438 | } | ||
268 | 439 | ||
269 | int[] indices = meshData.getIndexListAsInt(); | 440 | int[] indices = meshData.getIndexListAsInt(); |
270 | int realIndicesIndex = indices.Length; | 441 | int realIndicesIndex = indices.Length; |
@@ -302,8 +473,8 @@ public class BSShapeMesh : BSShape | |||
302 | } | 473 | } |
303 | } | 474 | } |
304 | } | 475 | } |
305 | physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", | 476 | physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", |
306 | BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | 477 | BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); |
307 | 478 | ||
308 | if (realIndicesIndex != 0) | 479 | if (realIndicesIndex != 0) |
309 | { | 480 | { |
@@ -326,17 +497,239 @@ public class BSShapeMesh : BSShape | |||
326 | public class BSShapeHull : BSShape | 497 | public class BSShapeHull : BSShape |
327 | { | 498 | { |
328 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; | 499 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; |
329 | private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); | 500 | public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); |
330 | 501 | ||
331 | public BSShapeHull(BulletShape pShape) : base(pShape) | 502 | public BSShapeHull(BulletShape pShape) : base(pShape) |
332 | { | 503 | { |
333 | } | 504 | } |
334 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 505 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) |
335 | { | 506 | { |
336 | return new BSShapeNull(); | 507 | float lod; |
508 | System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
509 | |||
510 | BSShapeHull retHull = null; | ||
511 | lock (Hulls) | ||
512 | { | ||
513 | if (Hulls.TryGetValue(newHullKey, out retHull)) | ||
514 | { | ||
515 | // The mesh has already been created. Return a new reference to same. | ||
516 | retHull.IncrementReference(); | ||
517 | } | ||
518 | else | ||
519 | { | ||
520 | retHull = new BSShapeHull(new BulletShape()); | ||
521 | // An instance of this mesh has not been created. Build and remember same. | ||
522 | BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); | ||
523 | |||
524 | // Check to see if hull was created (might require an asset). | ||
525 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
526 | if (!newShape.isNativeShape) | ||
527 | { | ||
528 | // If a mesh was what was created, remember the built shape for later sharing. | ||
529 | Hulls.Add(newHullKey, retHull); | ||
530 | } | ||
531 | retHull.physShapeInfo = newShape; | ||
532 | } | ||
533 | } | ||
534 | physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); | ||
535 | return retHull; | ||
536 | } | ||
537 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
538 | { | ||
539 | // Another reference to this shape is just counted. | ||
540 | IncrementReference(); | ||
541 | return this; | ||
337 | } | 542 | } |
338 | public override void Dereference(BSScene physicsScene) | 543 | public override void Dereference(BSScene physicsScene) |
339 | { | 544 | { |
545 | lock (Hulls) | ||
546 | { | ||
547 | this.DecrementReference(); | ||
548 | physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
549 | // TODO: schedule aging and destruction of unused meshes. | ||
550 | } | ||
551 | } | ||
552 | List<ConvexResult> m_hulls; | ||
553 | private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, | ||
554 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
555 | { | ||
556 | BulletShape newShape = new BulletShape(); | ||
557 | IntPtr hullPtr = IntPtr.Zero; | ||
558 | |||
559 | if (BSParam.ShouldUseBulletHACD) | ||
560 | { | ||
561 | // Build the hull shape from an existing mesh shape. | ||
562 | // The mesh should have already been created in Bullet. | ||
563 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); | ||
564 | BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); | ||
565 | |||
566 | if (meshShape.physShapeInfo.HasPhysicalShape) | ||
567 | { | ||
568 | HACDParams parms; | ||
569 | parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; | ||
570 | parms.minClusters = BSParam.BHullMinClusters; | ||
571 | parms.compacityWeight = BSParam.BHullCompacityWeight; | ||
572 | parms.volumeWeight = BSParam.BHullVolumeWeight; | ||
573 | parms.concavity = BSParam.BHullConcavity; | ||
574 | parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); | ||
575 | parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); | ||
576 | parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); | ||
577 | parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); | ||
578 | |||
579 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); | ||
580 | newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); | ||
581 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
582 | |||
583 | // Now done with the mesh shape. | ||
584 | meshShape.Dereference(physicsScene); | ||
585 | } | ||
586 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
587 | } | ||
588 | if (!newShape.HasPhysicalShape) | ||
589 | { | ||
590 | // Build a new hull in the physical world using the C# HACD algorigthm. | ||
591 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | ||
592 | IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false); | ||
593 | if (meshData != null) | ||
594 | { | ||
595 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
596 | { | ||
597 | // Release the fetched asset data once it has been used. | ||
598 | pbs.SculptData = new byte[0]; | ||
599 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
600 | } | ||
601 | |||
602 | int[] indices = meshData.getIndexListAsInt(); | ||
603 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
604 | |||
605 | //format conversion from IMesh format to DecompDesc format | ||
606 | List<int> convIndices = new List<int>(); | ||
607 | List<float3> convVertices = new List<float3>(); | ||
608 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
609 | { | ||
610 | convIndices.Add(indices[ii]); | ||
611 | } | ||
612 | foreach (OMV.Vector3 vv in vertices) | ||
613 | { | ||
614 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
615 | } | ||
616 | |||
617 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | ||
618 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | ||
619 | { | ||
620 | // Simple primitive shapes we know are convex so they are better implemented with | ||
621 | // fewer hulls. | ||
622 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | ||
623 | if (BSShapeCollection.PrimHasNoCuts(pbs)) | ||
624 | { | ||
625 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | ||
626 | } | ||
627 | } | ||
628 | |||
629 | // setup and do convex hull conversion | ||
630 | m_hulls = new List<ConvexResult>(); | ||
631 | DecompDesc dcomp = new DecompDesc(); | ||
632 | dcomp.mIndices = convIndices; | ||
633 | dcomp.mVertices = convVertices; | ||
634 | dcomp.mDepth = maxDepthSplit; | ||
635 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | ||
636 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | ||
637 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
638 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
639 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
640 | // create the hull into the _hulls variable | ||
641 | convexBuilder.process(dcomp); | ||
642 | |||
643 | physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
644 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
645 | |||
646 | // Convert the vertices and indices for passing to unmanaged. | ||
647 | // The hull information is passed as a large floating point array. | ||
648 | // The format is: | ||
649 | // convHulls[0] = number of hulls | ||
650 | // convHulls[1] = number of vertices in first hull | ||
651 | // convHulls[2] = hull centroid X coordinate | ||
652 | // convHulls[3] = hull centroid Y coordinate | ||
653 | // convHulls[4] = hull centroid Z coordinate | ||
654 | // convHulls[5] = first hull vertex X | ||
655 | // convHulls[6] = first hull vertex Y | ||
656 | // convHulls[7] = first hull vertex Z | ||
657 | // convHulls[8] = second hull vertex X | ||
658 | // ... | ||
659 | // convHulls[n] = number of vertices in second hull | ||
660 | // convHulls[n+1] = second hull centroid X coordinate | ||
661 | // ... | ||
662 | // | ||
663 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
664 | // data structures that do not need to be converted in order to pass to Bullet. | ||
665 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
666 | int hullCount = m_hulls.Count; | ||
667 | int totalVertices = 1; // include one for the count of the hulls | ||
668 | foreach (ConvexResult cr in m_hulls) | ||
669 | { | ||
670 | totalVertices += 4; // add four for the vertex count and centroid | ||
671 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
672 | } | ||
673 | float[] convHulls = new float[totalVertices]; | ||
674 | |||
675 | convHulls[0] = (float)hullCount; | ||
676 | int jj = 1; | ||
677 | foreach (ConvexResult cr in m_hulls) | ||
678 | { | ||
679 | // copy vertices for index access | ||
680 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
681 | int kk = 0; | ||
682 | foreach (float3 ff in cr.HullVertices) | ||
683 | { | ||
684 | verts[kk++] = ff; | ||
685 | } | ||
686 | |||
687 | // add to the array one hull's worth of data | ||
688 | convHulls[jj++] = cr.HullIndices.Count; | ||
689 | convHulls[jj++] = 0f; // centroid x,y,z | ||
690 | convHulls[jj++] = 0f; | ||
691 | convHulls[jj++] = 0f; | ||
692 | foreach (int ind in cr.HullIndices) | ||
693 | { | ||
694 | convHulls[jj++] = verts[ind].x; | ||
695 | convHulls[jj++] = verts[ind].y; | ||
696 | convHulls[jj++] = verts[ind].z; | ||
697 | } | ||
698 | } | ||
699 | // create the hull data structure in Bullet | ||
700 | newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); | ||
701 | } | ||
702 | newShape.shapeKey = newHullKey; | ||
703 | } | ||
704 | return newShape; | ||
705 | } | ||
706 | // Callback from convex hull creater with a newly created hull. | ||
707 | // Just add it to our collection of hulls for this shape. | ||
708 | private void HullReturn(ConvexResult result) | ||
709 | { | ||
710 | m_hulls.Add(result); | ||
711 | return; | ||
712 | } | ||
713 | // Loop through all the known hulls and return the description based on the physical address. | ||
714 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) | ||
715 | { | ||
716 | bool ret = false; | ||
717 | BSShapeHull foundDesc = null; | ||
718 | lock (Hulls) | ||
719 | { | ||
720 | foreach (BSShapeHull sh in Hulls.Values) | ||
721 | { | ||
722 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
723 | { | ||
724 | foundDesc = sh; | ||
725 | ret = true; | ||
726 | break; | ||
727 | } | ||
728 | |||
729 | } | ||
730 | } | ||
731 | outHull = foundDesc; | ||
732 | return ret; | ||
340 | } | 733 | } |
341 | } | 734 | } |
342 | 735 | ||
@@ -344,14 +737,169 @@ public class BSShapeHull : BSShape | |||
344 | public class BSShapeCompound : BSShape | 737 | public class BSShapeCompound : BSShape |
345 | { | 738 | { |
346 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; | 739 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; |
347 | public BSShapeCompound() : base() | 740 | public BSShapeCompound(BulletShape pShape) : base(pShape) |
348 | { | 741 | { |
349 | } | 742 | } |
350 | public static BSShape GetReference(BSPhysObject prim) | 743 | public static BSShape GetReference(BSScene physicsScene) |
351 | { | 744 | { |
352 | return new BSShapeNull(); | 745 | // Base compound shapes are not shared so this returns a raw shape. |
746 | // A built compound shape can be reused in linksets. | ||
747 | return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); | ||
748 | } | ||
749 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
750 | { | ||
751 | // Calling this reference means we want another handle to an existing compound shape | ||
752 | // (usually linksets) so return this copy. | ||
753 | IncrementReference(); | ||
754 | return this; | ||
755 | } | ||
756 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
757 | public override void Dereference(BSScene physicsScene) | ||
758 | { | ||
759 | lock (physShapeInfo) | ||
760 | { | ||
761 | this.DecrementReference(); | ||
762 | physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
763 | if (referenceCount <= 0) | ||
764 | { | ||
765 | if (!physicsScene.PE.IsCompound(physShapeInfo)) | ||
766 | { | ||
767 | // Failed the sanity check!! | ||
768 | physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
769 | LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
770 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
771 | BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
772 | return; | ||
773 | } | ||
774 | |||
775 | int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); | ||
776 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", | ||
777 | BSScene.DetailLogZero, physShapeInfo, numChildren); | ||
778 | |||
779 | // Loop through all the children dereferencing each. | ||
780 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
781 | { | ||
782 | BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); | ||
783 | DereferenceAnonCollisionShape(physicsScene, childShape); | ||
784 | } | ||
785 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
786 | } | ||
787 | } | ||
788 | } | ||
789 | private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) | ||
790 | { | ||
791 | BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); | ||
792 | return cShape; | ||
793 | } | ||
794 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
795 | // Figure out type and call the correct dereference routine. | ||
796 | // Called at taint-time. | ||
797 | private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) | ||
798 | { | ||
799 | BSShapeMesh meshDesc; | ||
800 | if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) | ||
801 | { | ||
802 | meshDesc.Dereference(physicsScene); | ||
803 | } | ||
804 | else | ||
805 | { | ||
806 | BSShapeHull hullDesc; | ||
807 | if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) | ||
808 | { | ||
809 | hullDesc.Dereference(physicsScene); | ||
810 | } | ||
811 | else | ||
812 | { | ||
813 | if (physicsScene.PE.IsCompound(pShape)) | ||
814 | { | ||
815 | BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); | ||
816 | recursiveCompound.Dereference(physicsScene); | ||
817 | } | ||
818 | else | ||
819 | { | ||
820 | if (physicsScene.PE.IsNativeShape(pShape)) | ||
821 | { | ||
822 | BSShapeNative nativeShape = new BSShapeNative(pShape); | ||
823 | nativeShape.Dereference(physicsScene); | ||
824 | } | ||
825 | } | ||
826 | } | ||
827 | } | ||
828 | } | ||
829 | } | ||
830 | |||
831 | // ============================================================================================================ | ||
832 | public class BSShapeConvexHull : BSShape | ||
833 | { | ||
834 | private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; | ||
835 | public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>(); | ||
836 | |||
837 | public BSShapeConvexHull(BulletShape pShape) : base(pShape) | ||
838 | { | ||
839 | } | ||
840 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
841 | { | ||
842 | float lod; | ||
843 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
844 | |||
845 | physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}", | ||
846 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
847 | |||
848 | BSShapeConvexHull retConvexHull = null; | ||
849 | lock (ConvexHulls) | ||
850 | { | ||
851 | if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) | ||
852 | { | ||
853 | // The mesh has already been created. Return a new reference to same. | ||
854 | retConvexHull.IncrementReference(); | ||
855 | } | ||
856 | else | ||
857 | { | ||
858 | retConvexHull = new BSShapeConvexHull(new BulletShape()); | ||
859 | BulletShape convexShape = null; | ||
860 | |||
861 | // Get a handle to a mesh to build the hull from | ||
862 | BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); | ||
863 | if (baseMesh.physShapeInfo.isNativeShape) | ||
864 | { | ||
865 | // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. | ||
866 | // In the short term, we return the native shape and a later ForceBodyShapeRebuild should | ||
867 | // get back to this code with a buildable mesh. | ||
868 | // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? | ||
869 | convexShape = baseMesh.physShapeInfo; | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); | ||
874 | convexShape.shapeKey = newMeshKey; | ||
875 | ConvexHulls.Add(convexShape.shapeKey, retConvexHull); | ||
876 | } | ||
877 | |||
878 | // Done with the base mesh | ||
879 | baseMesh.Dereference(physicsScene); | ||
880 | |||
881 | retConvexHull.physShapeInfo = convexShape; | ||
882 | } | ||
883 | } | ||
884 | return retConvexHull; | ||
885 | } | ||
886 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
887 | { | ||
888 | // Calling this reference means we want another handle to an existing shape | ||
889 | // (usually linksets) so return this copy. | ||
890 | IncrementReference(); | ||
891 | return this; | ||
892 | } | ||
893 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
894 | public override void Dereference(BSScene physicsScene) | ||
895 | { | ||
896 | lock (ConvexHulls) | ||
897 | { | ||
898 | this.DecrementReference(); | ||
899 | physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
900 | // TODO: schedule aging and destruction of unused meshes. | ||
901 | } | ||
353 | } | 902 | } |
354 | public override void Dereference(BSScene physicsScene) { } | ||
355 | } | 903 | } |
356 | 904 | ||
357 | // ============================================================================================================ | 905 | // ============================================================================================================ |
@@ -361,8 +909,12 @@ public class BSShapeAvatar : BSShape | |||
361 | public BSShapeAvatar() : base() | 909 | public BSShapeAvatar() : base() |
362 | { | 910 | { |
363 | } | 911 | } |
364 | public static BSShape GetReference(BSPhysObject prim) | 912 | public static BSShape GetReference(BSPhysObject prim) |
365 | { | 913 | { |
914 | return new BSShapeNull(); | ||
915 | } | ||
916 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
917 | { | ||
366 | return new BSShapeNull(); | 918 | return new BSShapeNull(); |
367 | } | 919 | } |
368 | public override void Dereference(BSScene physicsScene) { } | 920 | public override void Dereference(BSScene physicsScene) { } |