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