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