diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 928 |
1 files changed, 302 insertions, 626 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 26a581f..a0e627e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -24,6 +24,9 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | |||
28 | // Uncomment this it enable code to do all shape an body memory management | ||
29 | // in the C# code. | ||
27 | using System; | 30 | using System; |
28 | using System.Reflection; | 31 | using System.Reflection; |
29 | using System.Collections.Generic; | 32 | using System.Collections.Generic; |
@@ -36,6 +39,7 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet; | |||
36 | 39 | ||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | 40 | namespace OpenSim.Region.Physics.BulletSPlugin |
38 | { | 41 | { |
42 | |||
39 | [Serializable] | 43 | [Serializable] |
40 | public sealed class BSPrim : BSPhysObject | 44 | public sealed class BSPrim : BSPhysObject |
41 | { | 45 | { |
@@ -49,11 +53,6 @@ public sealed class BSPrim : BSPhysObject | |||
49 | private ulong _hullKey; | 53 | private ulong _hullKey; |
50 | private List<ConvexResult> _hulls; | 54 | private List<ConvexResult> _hulls; |
51 | 55 | ||
52 | private BSScene _scene; | ||
53 | public BSScene Scene { get { return _scene; } } | ||
54 | private String _avName; | ||
55 | private uint _localID = 0; | ||
56 | |||
57 | // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. | 56 | // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. |
58 | // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. | 57 | // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. |
59 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 58 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
@@ -87,18 +86,6 @@ public sealed class BSPrim : BSPhysObject | |||
87 | private bool _kinematic; | 86 | private bool _kinematic; |
88 | private float _buoyancy; | 87 | private float _buoyancy; |
89 | 88 | ||
90 | // Membership in a linkset is controlled by this class. | ||
91 | public override BSLinkset Linkset { get; set; } | ||
92 | |||
93 | private int _subscribedEventsMs = 0; | ||
94 | private int _nextCollisionOkTime = 0; | ||
95 | long _collidingStep; | ||
96 | long _collidingGroundStep; | ||
97 | CollisionFlags m_currentCollisionFlags = 0; | ||
98 | |||
99 | public override BulletBody BSBody { get; set; } | ||
100 | public override BulletShape BSShape { get; set; } | ||
101 | |||
102 | private BSDynamics _vehicle; | 89 | private BSDynamics _vehicle; |
103 | 90 | ||
104 | private OMV.Vector3 _PIDTarget; | 91 | private OMV.Vector3 _PIDTarget; |
@@ -113,10 +100,8 @@ public sealed class BSPrim : BSPhysObject | |||
113 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 100 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
114 | { | 101 | { |
115 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); | 102 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); |
116 | _localID = localID; | 103 | base.BaseInitialize(parent_scene, localID, primName, "BSPrim"); |
117 | _avName = primName; | ||
118 | _physicsActorType = (int)ActorTypes.Prim; | 104 | _physicsActorType = (int)ActorTypes.Prim; |
119 | _scene = parent_scene; | ||
120 | _position = pos; | 105 | _position = pos; |
121 | _size = size; | 106 | _size = size; |
122 | _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type | 107 | _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type |
@@ -129,25 +114,23 @@ public sealed class BSPrim : BSPhysObject | |||
129 | _pbs = pbs; | 114 | _pbs = pbs; |
130 | _isPhysical = pisPhysical; | 115 | _isPhysical = pisPhysical; |
131 | _isVolumeDetect = false; | 116 | _isVolumeDetect = false; |
132 | _subscribedEventsMs = 0; | 117 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material |
133 | _friction = _scene.Params.defaultFriction; // TODO: compute based on object material | 118 | _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material |
134 | _density = _scene.Params.defaultDensity; // TODO: compute based on object material | 119 | _restitution = PhysicsScene.Params.defaultRestitution; |
135 | _restitution = _scene.Params.defaultRestitution; | 120 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness |
136 | Linkset = new BSLinkset(Scene, this); // a linkset of one | ||
137 | _vehicle = new BSDynamics(Scene, this); // add vehicleness | ||
138 | _mass = CalculateMass(); | 121 | _mass = CalculateMass(); |
122 | |||
123 | // No body or shape yet | ||
124 | BSBody = new BulletBody(LocalID, IntPtr.Zero); | ||
125 | BSShape = new BulletShape(IntPtr.Zero); | ||
126 | |||
139 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 127 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
140 | // do the actual object creation at taint time | 128 | // do the actual object creation at taint time |
141 | _scene.TaintedObject("BSPrim.create", delegate() | 129 | PhysicsScene.TaintedObject("BSPrim.create", delegate() |
142 | { | 130 | { |
143 | CreateGeomAndObject(true); | 131 | CreateGeomAndObject(true); |
144 | 132 | ||
145 | // Get the pointer to the physical body for this object. | 133 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr); |
146 | // At the moment, we're still letting BulletSim manage the creation and destruction | ||
147 | // of the object. Someday we'll move that into the C# code. | ||
148 | BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
149 | BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr)); | ||
150 | m_currentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.Ptr); | ||
151 | }); | 134 | }); |
152 | } | 135 | } |
153 | 136 | ||
@@ -168,57 +151,62 @@ public sealed class BSPrim : BSPhysObject | |||
168 | // Undo any vehicle properties | 151 | // Undo any vehicle properties |
169 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 152 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
170 | 153 | ||
171 | _scene.TaintedObject("BSPrim.destroy", delegate() | 154 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() |
172 | { | 155 | { |
173 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 156 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
174 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. | 157 | // If there are physical body and shape, release my use of same. |
175 | BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); | 158 | PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); |
159 | PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); | ||
176 | }); | 160 | }); |
177 | } | 161 | } |
178 | 162 | ||
179 | public override bool Stopped { | 163 | public override bool Stopped { |
180 | get { return _stopped; } | 164 | get { return _stopped; } |
181 | } | 165 | } |
182 | public override OMV.Vector3 Size { | 166 | public override OMV.Vector3 Size { |
183 | get { return _size; } | 167 | get { return _size; } |
184 | set { | 168 | set { |
185 | _size = value; | 169 | _size = value; |
186 | _scene.TaintedObject("BSPrim.setSize", delegate() | 170 | PhysicsScene.TaintedObject("BSPrim.setSize", delegate() |
187 | { | 171 | { |
188 | _mass = CalculateMass(); // changing size changes the mass | 172 | _mass = CalculateMass(); // changing size changes the mass |
189 | // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct | 173 | // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct |
190 | // scale and margins are set. | 174 | // scale and margins are set. |
191 | CreateGeomAndObject(true); | 175 | CreateGeomAndObject(true); |
192 | DetailLog("{0}: BSPrim.setSize: size={1}, scale={2}, mass={3}, physical={4}", LocalID, _size, _scale, _mass, IsPhysical); | 176 | // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical); |
193 | }); | 177 | }); |
194 | } | 178 | } |
195 | } | 179 | } |
196 | public override PrimitiveBaseShape Shape { | 180 | // Scale is what we set in the physics engine. It is different than 'size' in that |
181 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | ||
182 | public OMV.Vector3 Scale | ||
183 | { | ||
184 | get { return _scale; } | ||
185 | set { _scale = value; } | ||
186 | } | ||
187 | public override PrimitiveBaseShape Shape { | ||
197 | set { | 188 | set { |
198 | _pbs = value; | 189 | _pbs = value; |
199 | _scene.TaintedObject("BSPrim.setShape", delegate() | 190 | PhysicsScene.TaintedObject("BSPrim.setShape", delegate() |
200 | { | 191 | { |
201 | _mass = CalculateMass(); // changing the shape changes the mass | 192 | _mass = CalculateMass(); // changing the shape changes the mass |
202 | CreateGeomAndObject(false); | 193 | CreateGeomAndObject(true); |
203 | }); | 194 | }); |
204 | } | 195 | } |
205 | } | ||
206 | public override uint LocalID { | ||
207 | set { _localID = value; } | ||
208 | get { return _localID; } | ||
209 | } | 196 | } |
210 | public override bool Grabbed { | 197 | public override bool Grabbed { |
211 | set { _grabbed = value; | 198 | set { _grabbed = value; |
212 | } | 199 | } |
213 | } | 200 | } |
214 | public override bool Selected { | 201 | public override bool Selected { |
215 | set { | 202 | set { |
216 | _isSelected = value; | 203 | _isSelected = value; |
217 | _scene.TaintedObject("BSPrim.setSelected", delegate() | 204 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
218 | { | 205 | { |
219 | SetObjectDynamic(); | 206 | // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
207 | SetObjectDynamic(false); | ||
220 | }); | 208 | }); |
221 | } | 209 | } |
222 | } | 210 | } |
223 | public override void CrossingFailure() { return; } | 211 | public override void CrossingFailure() { return; } |
224 | 212 | ||
@@ -232,10 +220,10 @@ public sealed class BSPrim : BSPhysObject | |||
232 | 220 | ||
233 | Linkset = parent.Linkset.AddMeToLinkset(this); | 221 | Linkset = parent.Linkset.AddMeToLinkset(this); |
234 | 222 | ||
235 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | 223 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", |
236 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | 224 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); |
237 | } | 225 | } |
238 | return; | 226 | return; |
239 | } | 227 | } |
240 | 228 | ||
241 | // delink me from my linkset | 229 | // delink me from my linkset |
@@ -245,12 +233,12 @@ public sealed class BSPrim : BSPhysObject | |||
245 | 233 | ||
246 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 234 | BSPhysObject parentBefore = Linkset.LinksetRoot; |
247 | int childrenBefore = Linkset.NumberOfChildren; | 235 | int childrenBefore = Linkset.NumberOfChildren; |
248 | 236 | ||
249 | Linkset = Linkset.RemoveMeFromLinkset(this); | 237 | Linkset = Linkset.RemoveMeFromLinkset(this); |
250 | 238 | ||
251 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | 239 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", |
252 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | 240 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); |
253 | return; | 241 | return; |
254 | } | 242 | } |
255 | 243 | ||
256 | // Set motion values to zero. | 244 | // Set motion values to zero. |
@@ -264,43 +252,40 @@ public sealed class BSPrim : BSPhysObject | |||
264 | _rotationalVelocity = OMV.Vector3.Zero; | 252 | _rotationalVelocity = OMV.Vector3.Zero; |
265 | 253 | ||
266 | // Zero some other properties directly into the physics engine | 254 | // Zero some other properties directly into the physics engine |
267 | BulletSimAPI.SetLinearVelocity2(BSBody.Ptr, OMV.Vector3.Zero); | 255 | BulletSimAPI.ClearForces2(BSBody.ptr); |
268 | BulletSimAPI.SetAngularVelocity2(BSBody.Ptr, OMV.Vector3.Zero); | ||
269 | BulletSimAPI.SetInterpolationVelocity2(BSBody.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
270 | BulletSimAPI.ClearForces2(BSBody.Ptr); | ||
271 | } | 256 | } |
272 | 257 | ||
273 | public override void LockAngularMotion(OMV.Vector3 axis) | 258 | public override void LockAngularMotion(OMV.Vector3 axis) |
274 | { | 259 | { |
275 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 260 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
276 | return; | 261 | return; |
277 | } | 262 | } |
278 | 263 | ||
279 | public override OMV.Vector3 Position { | 264 | public override OMV.Vector3 Position { |
280 | get { | 265 | get { |
281 | if (!Linkset.IsRoot(this)) | 266 | if (!Linkset.IsRoot(this)) |
282 | // child prims move around based on their parent. Need to get the latest location | 267 | // child prims move around based on their parent. Need to get the latest location |
283 | _position = BulletSimAPI.GetPosition2(BSBody.Ptr); | 268 | _position = BulletSimAPI.GetPosition2(BSBody.ptr); |
284 | 269 | ||
285 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | 270 | // don't do the GetObjectPosition for root elements because this function is called a zillion times |
286 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 271 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
287 | return _position; | 272 | return _position; |
288 | } | 273 | } |
289 | set { | 274 | set { |
290 | _position = value; | 275 | _position = value; |
291 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | 276 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? |
292 | _scene.TaintedObject("BSPrim.setPosition", delegate() | 277 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
293 | { | 278 | { |
294 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 279 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
295 | BulletSimAPI.SetTranslation2(BSBody.Ptr, _position, _orientation); | 280 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); |
296 | }); | 281 | }); |
297 | } | 282 | } |
298 | } | 283 | } |
299 | 284 | ||
300 | // Return the effective mass of the object. | 285 | // Return the effective mass of the object. |
301 | // If there are multiple items in the linkset, add them together for the root | 286 | // If there are multiple items in the linkset, add them together for the root |
302 | public override float Mass | 287 | public override float Mass |
303 | { | 288 | { |
304 | get | 289 | get |
305 | { | 290 | { |
306 | // return Linkset.LinksetMass; | 291 | // return Linkset.LinksetMass; |
@@ -323,59 +308,59 @@ public sealed class BSPrim : BSPhysObject | |||
323 | get { return Linkset.GeometricCenter; } | 308 | get { return Linkset.GeometricCenter; } |
324 | } | 309 | } |
325 | 310 | ||
326 | public override OMV.Vector3 Force { | 311 | public override OMV.Vector3 Force { |
327 | get { return _force; } | 312 | get { return _force; } |
328 | set { | 313 | set { |
329 | _force = value; | 314 | _force = value; |
330 | _scene.TaintedObject("BSPrim.setForce", delegate() | 315 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() |
331 | { | 316 | { |
332 | DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 317 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |
333 | BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force); | 318 | BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); |
334 | }); | 319 | }); |
335 | } | 320 | } |
336 | } | 321 | } |
337 | 322 | ||
338 | public override int VehicleType { | 323 | public override int VehicleType { |
339 | get { | 324 | get { |
340 | return (int)_vehicle.Type; // if we are a vehicle, return that type | 325 | return (int)_vehicle.Type; // if we are a vehicle, return that type |
341 | } | 326 | } |
342 | set { | 327 | set { |
343 | Vehicle type = (Vehicle)value; | 328 | Vehicle type = (Vehicle)value; |
344 | BSPrim vehiclePrim = this; | 329 | BSPrim vehiclePrim = this; |
345 | _scene.TaintedObject("setVehicleType", delegate() | 330 | PhysicsScene.TaintedObject("setVehicleType", delegate() |
346 | { | 331 | { |
347 | // Done at taint time so we're sure the physics engine is not using the variables | 332 | // Done at taint time so we're sure the physics engine is not using the variables |
348 | // Vehicle code changes the parameters for this vehicle type. | 333 | // Vehicle code changes the parameters for this vehicle type. |
349 | _vehicle.ProcessTypeChange(type); | 334 | _vehicle.ProcessTypeChange(type); |
350 | // Tell the scene about the vehicle so it will get processing each frame. | 335 | // Tell the scene about the vehicle so it will get processing each frame. |
351 | _scene.VehicleInSceneTypeChanged(this, type); | 336 | PhysicsScene.VehicleInSceneTypeChanged(this, type); |
352 | }); | 337 | }); |
353 | } | 338 | } |
354 | } | 339 | } |
355 | public override void VehicleFloatParam(int param, float value) | 340 | public override void VehicleFloatParam(int param, float value) |
356 | { | 341 | { |
357 | _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 342 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
358 | { | 343 | { |
359 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 344 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); |
360 | }); | 345 | }); |
361 | } | 346 | } |
362 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 347 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
363 | { | 348 | { |
364 | _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 349 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
365 | { | 350 | { |
366 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 351 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); |
367 | }); | 352 | }); |
368 | } | 353 | } |
369 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 354 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
370 | { | 355 | { |
371 | _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 356 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
372 | { | 357 | { |
373 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 358 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); |
374 | }); | 359 | }); |
375 | } | 360 | } |
376 | public override void VehicleFlags(int param, bool remove) | 361 | public override void VehicleFlags(int param, bool remove) |
377 | { | 362 | { |
378 | _scene.TaintedObject("BSPrim.VehicleFlags", delegate() | 363 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
379 | { | 364 | { |
380 | _vehicle.ProcessVehicleFlags(param, remove); | 365 | _vehicle.ProcessVehicleFlags(param, remove); |
381 | }); | 366 | }); |
@@ -392,73 +377,81 @@ public sealed class BSPrim : BSPhysObject | |||
392 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 377 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
393 | public override void SetVolumeDetect(int param) { | 378 | public override void SetVolumeDetect(int param) { |
394 | bool newValue = (param != 0); | 379 | bool newValue = (param != 0); |
395 | _isVolumeDetect = newValue; | 380 | if (_isVolumeDetect != newValue) |
396 | _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | ||
397 | { | 381 | { |
398 | SetObjectDynamic(); | 382 | _isVolumeDetect = newValue; |
399 | }); | 383 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() |
400 | return; | 384 | { |
385 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | ||
386 | SetObjectDynamic(true); | ||
387 | }); | ||
388 | } | ||
389 | return; | ||
401 | } | 390 | } |
402 | 391 | ||
403 | public override OMV.Vector3 Velocity { | 392 | public override OMV.Vector3 Velocity { |
404 | get { return _velocity; } | 393 | get { return _velocity; } |
405 | set { | 394 | set { |
406 | _velocity = value; | 395 | _velocity = value; |
407 | _scene.TaintedObject("BSPrim.setVelocity", delegate() | 396 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
408 | { | 397 | { |
409 | DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 398 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
410 | BulletSimAPI.SetLinearVelocity2(BSBody.Ptr, _velocity); | 399 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); |
411 | }); | 400 | }); |
412 | } | 401 | } |
413 | } | 402 | } |
414 | public override OMV.Vector3 Torque { | 403 | public override OMV.Vector3 Torque { |
415 | get { return _torque; } | 404 | get { return _torque; } |
416 | set { _torque = value; | 405 | set { _torque = value; |
417 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 406 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |
418 | } | 407 | } |
419 | } | 408 | } |
420 | public override float CollisionScore { | 409 | public override float CollisionScore { |
421 | get { return _collisionScore; } | 410 | get { return _collisionScore; } |
422 | set { _collisionScore = value; | 411 | set { _collisionScore = value; |
423 | } | 412 | } |
424 | } | 413 | } |
425 | public override OMV.Vector3 Acceleration { | 414 | public override OMV.Vector3 Acceleration { |
426 | get { return _acceleration; } | 415 | get { return _acceleration; } |
427 | set { _acceleration = value; } | 416 | set { _acceleration = value; } |
428 | } | 417 | } |
429 | public override OMV.Quaternion Orientation { | 418 | public override OMV.Quaternion Orientation { |
430 | get { | 419 | get { |
431 | if (!Linkset.IsRoot(this)) | 420 | if (!Linkset.IsRoot(this)) |
432 | { | 421 | { |
433 | // Children move around because tied to parent. Get a fresh value. | 422 | // Children move around because tied to parent. Get a fresh value. |
434 | _orientation = BulletSimAPI.GetOrientation2(BSBody.Ptr); | 423 | _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); |
435 | } | 424 | } |
436 | return _orientation; | 425 | return _orientation; |
437 | } | 426 | } |
438 | set { | 427 | set { |
439 | _orientation = value; | 428 | _orientation = value; |
440 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 429 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? |
441 | _scene.TaintedObject("BSPrim.setOrientation", delegate() | 430 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
442 | { | 431 | { |
443 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 432 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
444 | DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 433 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
445 | BulletSimAPI.SetTranslation2(BSBody.Ptr, _position, _orientation); | 434 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); |
446 | }); | 435 | }); |
447 | } | 436 | } |
448 | } | 437 | } |
449 | public override int PhysicsActorType { | 438 | public override int PhysicsActorType { |
450 | get { return _physicsActorType; } | 439 | get { return _physicsActorType; } |
451 | set { _physicsActorType = value; } | 440 | set { _physicsActorType = value; } |
452 | } | 441 | } |
453 | public override bool IsPhysical { | 442 | public override bool IsPhysical { |
454 | get { return _isPhysical; } | 443 | get { return _isPhysical; } |
455 | set { | 444 | set { |
456 | _isPhysical = value; | 445 | if (_isPhysical != value) |
457 | _scene.TaintedObject("BSPrim.setIsPhysical", delegate() | ||
458 | { | 446 | { |
459 | SetObjectDynamic(); | 447 | _isPhysical = value; |
460 | }); | 448 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
461 | } | 449 | { |
450 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | ||
451 | SetObjectDynamic(true); | ||
452 | }); | ||
453 | } | ||
454 | } | ||
462 | } | 455 | } |
463 | 456 | ||
464 | // An object is static (does not move) if selected or not physical | 457 | // An object is static (does not move) if selected or not physical |
@@ -468,53 +461,64 @@ public sealed class BSPrim : BSPhysObject | |||
468 | } | 461 | } |
469 | 462 | ||
470 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | 463 | // An object is solid if it's not phantom and if it's not doing VolumeDetect |
471 | private bool IsSolid | 464 | public bool IsSolid |
472 | { | 465 | { |
473 | get { return !IsPhantom && !_isVolumeDetect; } | 466 | get { return !IsPhantom && !_isVolumeDetect; } |
474 | } | 467 | } |
475 | 468 | ||
476 | // Make gravity work if the object is physical and not selected | 469 | // Make gravity work if the object is physical and not selected |
477 | // No locking here because only called when it is safe | 470 | // Called at taint-time!! |
471 | private void SetObjectDynamic(bool forceRebuild) | ||
472 | { | ||
473 | // Recreate the physical object if necessary | ||
474 | CreateGeomAndObject(forceRebuild); | ||
475 | } | ||
476 | |||
477 | // Convert the simulator's physical properties into settings on BulletSim objects. | ||
478 | // There are four flags we're interested in: | 478 | // There are four flags we're interested in: |
479 | // IsStatic: Object does not move, otherwise the object has mass and moves | 479 | // IsStatic: Object does not move, otherwise the object has mass and moves |
480 | // isSolid: other objects bounce off of this object | 480 | // isSolid: other objects bounce off of this object |
481 | // isVolumeDetect: other objects pass through but can generate collisions | 481 | // isVolumeDetect: other objects pass through but can generate collisions |
482 | // collisionEvents: whether this object returns collision events | 482 | // collisionEvents: whether this object returns collision events |
483 | private void SetObjectDynamic() | ||
484 | { | ||
485 | // If it's becoming dynamic, it will need hullness | ||
486 | VerifyCorrectPhysicalShape(); | ||
487 | UpdatePhysicalParameters(); | ||
488 | } | ||
489 | |||
490 | private void UpdatePhysicalParameters() | 483 | private void UpdatePhysicalParameters() |
491 | { | 484 | { |
492 | /* | 485 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); |
493 | // Bullet wants static objects to have a mass of zero | 486 | |
494 | float mass = IsStatic ? 0f : _mass; | 487 | // Mangling all the physical properties requires the object not be in the physical world. |
488 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | ||
489 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); | ||
495 | 490 | ||
496 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); | ||
497 | */ | ||
498 | BulletSimAPI.RemoveObjectFromWorld2(Scene.World.Ptr, BSBody.Ptr); | ||
499 | 491 | ||
500 | // Set up the object physicalness (does gravity and collisions move this object) | 492 | // Set up the object physicalness (does gravity and collisions move this object) |
501 | MakeDynamic(IsStatic); | 493 | MakeDynamic(IsStatic); |
502 | 494 | ||
503 | // Make solid or not (do things bounce off or pass through this object) | 495 | // Do any vehicle stuff |
504 | MakeSolid(IsSolid); | 496 | _vehicle.Refresh(); |
505 | 497 | ||
506 | // Arrange for collisions events if the simulator wants them | 498 | // Arrange for collision events if the simulator wants them |
507 | EnableCollisions(SubscribedEvents()); | 499 | EnableCollisions(SubscribedEvents()); |
508 | 500 | ||
509 | BulletSimAPI.AddObjectToWorld2(Scene.World.Ptr, BSBody.Ptr); | 501 | // Make solid or not (do things bounce off or pass through this object). |
502 | MakeSolid(IsSolid); | ||
503 | |||
504 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); | ||
505 | |||
506 | // Rebuild its shape | ||
507 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); | ||
508 | |||
509 | // Collision filter can be set only when the object is in the world | ||
510 | if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0) | ||
511 | { | ||
512 | BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask); | ||
513 | } | ||
510 | 514 | ||
511 | // Recompute any linkset parameters. | 515 | // Recompute any linkset parameters. |
512 | // When going from non-physical to physical, this re-enables the constraints that | 516 | // When going from non-physical to physical, this re-enables the constraints that |
513 | // had been automatically disabled when the mass was set to zero. | 517 | // had been automatically disabled when the mass was set to zero. |
514 | Linkset.Refresh(this); | 518 | Linkset.Refresh(this); |
515 | 519 | ||
516 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,static={1},solid={2},mass={3}, cf={4}", | 520 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", |
517 | LocalID, IsStatic, IsSolid, _mass, m_currentCollisionFlags); | 521 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); |
518 | } | 522 | } |
519 | 523 | ||
520 | // "Making dynamic" means changing to and from static. | 524 | // "Making dynamic" means changing to and from static. |
@@ -527,65 +531,86 @@ public sealed class BSPrim : BSPhysObject | |||
527 | if (makeStatic) | 531 | if (makeStatic) |
528 | { | 532 | { |
529 | // Become a Bullet 'static' object type | 533 | // Become a Bullet 'static' object type |
530 | m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); | 534 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
531 | // Stop all movement | 535 | // Stop all movement |
532 | BulletSimAPI.ClearAllForces2(BSBody.Ptr); | 536 | BulletSimAPI.ClearAllForces2(BSBody.ptr); |
533 | // Center of mass is at the center of the object | 537 | // Center of mass is at the center of the object |
534 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.Ptr, _position, _orientation); | 538 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation); |
535 | // Mass is zero which disables a bunch of physics stuff in Bullet | 539 | // Mass is zero which disables a bunch of physics stuff in Bullet |
536 | BulletSimAPI.SetMassProps2(BSBody.Ptr, 0f, OMV.Vector3.Zero); | 540 | BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); |
537 | // There is no inertia in a static object | 541 | // There is no inertia in a static object |
538 | BulletSimAPI.UpdateInertiaTensor2(BSBody.Ptr); | 542 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); |
539 | // There can be special things needed for implementing linksets | 543 | // There can be special things needed for implementing linksets |
540 | Linkset.MakeStatic(this); | 544 | Linkset.MakeStatic(this); |
541 | // The activation state is 'sleeping' so Bullet will not try to act on it | 545 | // The activation state is 'disabled' so Bullet will not try to act on it |
542 | BulletSimAPI.ForceActivationState2(BSBody.Ptr, ActivationState.ISLAND_SLEEPING); | 546 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); |
547 | |||
548 | BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | ||
549 | BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | ||
543 | } | 550 | } |
544 | else | 551 | else |
545 | { | 552 | { |
546 | // Not a Bullet static object | 553 | // Not a Bullet static object |
547 | m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); | 554 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
555 | |||
556 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | ||
557 | BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction); | ||
558 | BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution); | ||
548 | 559 | ||
549 | // Set various physical properties so internal things will get computed correctly as they are set | ||
550 | BulletSimAPI.SetFriction2(BSBody.Ptr, Scene.Params.defaultFriction); | ||
551 | BulletSimAPI.SetRestitution2(BSBody.Ptr, Scene.Params.defaultRestitution); | ||
552 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 560 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
553 | BulletSimAPI.SetInterpolationLinearVelocity2(BSBody.Ptr, OMV.Vector3.Zero); | 561 | BulletSimAPI.ClearAllForces2(BSBody.ptr); |
554 | BulletSimAPI.SetInterpolationAngularVelocity2(BSBody.Ptr, OMV.Vector3.Zero); | ||
555 | BulletSimAPI.SetInterpolationVelocity2(BSBody.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
556 | 562 | ||
557 | // A dynamic object has mass | 563 | // A dynamic object has mass |
558 | IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.Ptr); | 564 | IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); |
559 | OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Linkset.LinksetMass); | 565 | OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); |
560 | BulletSimAPI.SetMassProps2(BSBody.Ptr, _mass, inertia); | 566 | // OMV.Vector3 inertia = OMV.Vector3.Zero; |
561 | // Inertia is based on our new mass | 567 | BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); |
562 | BulletSimAPI.UpdateInertiaTensor2(BSBody.Ptr); | 568 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); |
563 | 569 | ||
564 | // Various values for simulation limits | 570 | // Various values for simulation limits |
565 | BulletSimAPI.SetDamping2(BSBody.Ptr, Scene.Params.linearDamping, Scene.Params.angularDamping); | 571 | BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); |
566 | BulletSimAPI.SetDeactivationTime2(BSBody.Ptr, Scene.Params.deactivationTime); | 572 | BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); |
567 | BulletSimAPI.SetSleepingThresholds2(BSBody.Ptr, Scene.Params.linearSleepingThreshold, Scene.Params.angularSleepingThreshold); | 573 | BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); |
568 | BulletSimAPI.SetContactProcessingThreshold2(BSBody.Ptr, Scene.Params.contactProcessingThreshold); | 574 | BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |
569 | 575 | ||
570 | // There can be special things needed for implementing linksets | 576 | // There can be special things needed for implementing linksets. |
571 | Linkset.MakeDynamic(this); | 577 | Linkset.MakeDynamic(this); |
572 | 578 | ||
573 | // Force activation of the object so Bullet will act on it. | 579 | // Force activation of the object so Bullet will act on it. |
574 | BulletSimAPI.Activate2(BSBody.Ptr, true); | 580 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
581 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
582 | BulletSimAPI.Activate2(BSBody.ptr, true); | ||
583 | |||
584 | BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | ||
585 | BSBody.collisionMask = CollisionFilterGroups.ObjectMask; | ||
575 | } | 586 | } |
576 | } | 587 | } |
577 | 588 | ||
578 | // "Making solid" means that other object will not pass through this object. | 589 | // "Making solid" means that other object will not pass through this object. |
590 | // To make transparent, we create a Bullet ghost object. | ||
591 | // Note: This expects to be called from the UpdatePhysicalParameters() routine as | ||
592 | // the functions after this one set up the state of a possibly newly created collision body. | ||
579 | private void MakeSolid(bool makeSolid) | 593 | private void MakeSolid(bool makeSolid) |
580 | { | 594 | { |
595 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr); | ||
581 | if (makeSolid) | 596 | if (makeSolid) |
582 | { | 597 | { |
583 | // Easy in Bullet -- just remove the object flag that controls collision response | 598 | // Verify the previous code created the correct shape for this type of thing. |
584 | m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 599 | if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) |
600 | { | ||
601 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
602 | } | ||
603 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
585 | } | 604 | } |
586 | else | 605 | else |
587 | { | 606 | { |
588 | m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 607 | if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) |
608 | { | ||
609 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
610 | } | ||
611 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
612 | BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | ||
613 | BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | ||
589 | } | 614 | } |
590 | } | 615 | } |
591 | 616 | ||
@@ -594,40 +619,40 @@ public sealed class BSPrim : BSPhysObject | |||
594 | { | 619 | { |
595 | if (wantsCollisionEvents) | 620 | if (wantsCollisionEvents) |
596 | { | 621 | { |
597 | m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 622 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
598 | } | 623 | } |
599 | else | 624 | else |
600 | { | 625 | { |
601 | m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 626 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
602 | } | 627 | } |
603 | } | 628 | } |
604 | 629 | ||
605 | // prims don't fly | 630 | // prims don't fly |
606 | public override bool Flying { | 631 | public override bool Flying { |
607 | get { return _flying; } | 632 | get { return _flying; } |
608 | set { | 633 | set { |
609 | _flying = value; | 634 | _flying = value; |
610 | } | 635 | } |
611 | } | 636 | } |
612 | public override bool SetAlwaysRun { | 637 | public override bool SetAlwaysRun { |
613 | get { return _setAlwaysRun; } | 638 | get { return _setAlwaysRun; } |
614 | set { _setAlwaysRun = value; } | 639 | set { _setAlwaysRun = value; } |
615 | } | 640 | } |
616 | public override bool ThrottleUpdates { | 641 | public override bool ThrottleUpdates { |
617 | get { return _throttleUpdates; } | 642 | get { return _throttleUpdates; } |
618 | set { _throttleUpdates = value; } | 643 | set { _throttleUpdates = value; } |
619 | } | 644 | } |
620 | public override bool IsColliding { | 645 | public override bool IsColliding { |
621 | get { return (_collidingStep == _scene.SimulationStep); } | 646 | get { return (CollidingStep == PhysicsScene.SimulationStep); } |
622 | set { _isColliding = value; } | 647 | set { _isColliding = value; } |
623 | } | 648 | } |
624 | public override bool CollidingGround { | 649 | public override bool CollidingGround { |
625 | get { return (_collidingGroundStep == _scene.SimulationStep); } | 650 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } |
626 | set { _collidingGround = value; } | 651 | set { _collidingGround = value; } |
627 | } | 652 | } |
628 | public override bool CollidingObj { | 653 | public override bool CollidingObj { |
629 | get { return _collidingObj; } | 654 | get { return _collidingObj; } |
630 | set { _collidingObj = value; } | 655 | set { _collidingObj = value; } |
631 | } | 656 | } |
632 | public bool IsPhantom { | 657 | public bool IsPhantom { |
633 | get { | 658 | get { |
@@ -637,10 +662,10 @@ public sealed class BSPrim : BSPhysObject | |||
637 | return false; | 662 | return false; |
638 | } | 663 | } |
639 | } | 664 | } |
640 | public override bool FloatOnWater { | 665 | public override bool FloatOnWater { |
641 | set { _floatOnWater = value; } | 666 | set { _floatOnWater = value; } |
642 | } | 667 | } |
643 | public override OMV.Vector3 RotationalVelocity { | 668 | public override OMV.Vector3 RotationalVelocity { |
644 | get { | 669 | get { |
645 | /* | 670 | /* |
646 | OMV.Vector3 pv = OMV.Vector3.Zero; | 671 | OMV.Vector3 pv = OMV.Vector3.Zero; |
@@ -652,61 +677,60 @@ public sealed class BSPrim : BSPhysObject | |||
652 | */ | 677 | */ |
653 | 678 | ||
654 | return _rotationalVelocity; | 679 | return _rotationalVelocity; |
655 | } | 680 | } |
656 | set { | 681 | set { |
657 | _rotationalVelocity = value; | 682 | _rotationalVelocity = value; |
658 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 683 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
659 | _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 684 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
660 | { | 685 | { |
661 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 686 | // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
662 | BulletSimAPI.SetAngularVelocity2(BSBody.Ptr, _rotationalVelocity); | 687 | BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); |
663 | }); | 688 | }); |
664 | } | 689 | } |
665 | } | 690 | } |
666 | public override bool Kinematic { | 691 | public override bool Kinematic { |
667 | get { return _kinematic; } | 692 | get { return _kinematic; } |
668 | set { _kinematic = value; | 693 | set { _kinematic = value; |
669 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); | 694 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); |
670 | } | 695 | } |
671 | } | 696 | } |
672 | public override float Buoyancy { | 697 | public override float Buoyancy { |
673 | get { return _buoyancy; } | 698 | get { return _buoyancy; } |
674 | set { | 699 | set { |
675 | _buoyancy = value; | 700 | _buoyancy = value; |
676 | _scene.TaintedObject("BSPrim.setBuoyancy", delegate() | 701 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
677 | { | 702 | { |
678 | DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 703 | // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
679 | // Buoyancy is faked by changing the gravity applied to the object | 704 | // Buoyancy is faked by changing the gravity applied to the object |
680 | float grav = Scene.Params.gravity * (1f - _buoyancy); | 705 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |
681 | BulletSimAPI.SetGravity2(BSBody.Ptr, new OMV.Vector3(0f, 0f, grav)); | 706 | BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); |
682 | // BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | ||
683 | }); | 707 | }); |
684 | } | 708 | } |
685 | } | 709 | } |
686 | 710 | ||
687 | // Used for MoveTo | 711 | // Used for MoveTo |
688 | public override OMV.Vector3 PIDTarget { | 712 | public override OMV.Vector3 PIDTarget { |
689 | set { _PIDTarget = value; } | 713 | set { _PIDTarget = value; } |
690 | } | 714 | } |
691 | public override bool PIDActive { | 715 | public override bool PIDActive { |
692 | set { _usePID = value; } | 716 | set { _usePID = value; } |
693 | } | 717 | } |
694 | public override float PIDTau { | 718 | public override float PIDTau { |
695 | set { _PIDTau = value; } | 719 | set { _PIDTau = value; } |
696 | } | 720 | } |
697 | 721 | ||
698 | // Used for llSetHoverHeight and maybe vehicle height | 722 | // Used for llSetHoverHeight and maybe vehicle height |
699 | // Hover Height will override MoveTo target's Z | 723 | // Hover Height will override MoveTo target's Z |
700 | public override bool PIDHoverActive { | 724 | public override bool PIDHoverActive { |
701 | set { _useHoverPID = value; } | 725 | set { _useHoverPID = value; } |
702 | } | 726 | } |
703 | public override float PIDHoverHeight { | 727 | public override float PIDHoverHeight { |
704 | set { _PIDHoverHeight = value; } | 728 | set { _PIDHoverHeight = value; } |
705 | } | 729 | } |
706 | public override PIDHoverType PIDHoverType { | 730 | public override PIDHoverType PIDHoverType { |
707 | set { _PIDHoverType = value; } | 731 | set { _PIDHoverType = value; } |
708 | } | 732 | } |
709 | public override float PIDHoverTau { | 733 | public override float PIDHoverTau { |
710 | set { _PIDHoverTao = value; } | 734 | set { _PIDHoverTao = value; } |
711 | } | 735 | } |
712 | 736 | ||
@@ -730,7 +754,7 @@ public sealed class BSPrim : BSPhysObject | |||
730 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 754 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
731 | return; | 755 | return; |
732 | } | 756 | } |
733 | _scene.TaintedObject("BSPrim.AddForce", delegate() | 757 | PhysicsScene.TaintedObject("BSPrim.AddForce", delegate() |
734 | { | 758 | { |
735 | OMV.Vector3 fSum = OMV.Vector3.Zero; | 759 | OMV.Vector3 fSum = OMV.Vector3.Zero; |
736 | lock (m_accumulatedForces) | 760 | lock (m_accumulatedForces) |
@@ -741,43 +765,19 @@ public sealed class BSPrim : BSPhysObject | |||
741 | } | 765 | } |
742 | m_accumulatedForces.Clear(); | 766 | m_accumulatedForces.Clear(); |
743 | } | 767 | } |
744 | DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); | 768 | // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); |
745 | // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. | 769 | // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. |
746 | BulletSimAPI.ApplyCentralForce2(BSBody.Ptr, fSum); | 770 | BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); |
747 | }); | 771 | }); |
748 | } | 772 | } |
749 | 773 | ||
750 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 774 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
751 | DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); | 775 | // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); |
752 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); | 776 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); |
753 | } | 777 | } |
754 | public override void SetMomentum(OMV.Vector3 momentum) { | 778 | public override void SetMomentum(OMV.Vector3 momentum) { |
755 | DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | 779 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); |
756 | } | 780 | } |
757 | public override void SubscribeEvents(int ms) { | ||
758 | _subscribedEventsMs = ms; | ||
759 | if (ms > 0) | ||
760 | { | ||
761 | // make sure first collision happens | ||
762 | _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; | ||
763 | |||
764 | Scene.TaintedObject("BSPrim.SubscribeEvents", delegate() | ||
765 | { | ||
766 | m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
767 | }); | ||
768 | } | ||
769 | } | ||
770 | public override void UnSubscribeEvents() { | ||
771 | _subscribedEventsMs = 0; | ||
772 | Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate() | ||
773 | { | ||
774 | m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
775 | }); | ||
776 | } | ||
777 | public override bool SubscribedEvents() { | ||
778 | return (_subscribedEventsMs > 0); | ||
779 | } | ||
780 | |||
781 | #region Mass Calculation | 781 | #region Mass Calculation |
782 | 782 | ||
783 | private float CalculateMass() | 783 | private float CalculateMass() |
@@ -787,8 +787,8 @@ public sealed class BSPrim : BSPhysObject | |||
787 | 787 | ||
788 | float returnMass = 0; | 788 | float returnMass = 0; |
789 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; | 789 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; |
790 | float hollowVolume = hollowAmount * hollowAmount; | 790 | float hollowVolume = hollowAmount * hollowAmount; |
791 | 791 | ||
792 | switch (_pbs.ProfileShape) | 792 | switch (_pbs.ProfileShape) |
793 | { | 793 | { |
794 | case ProfileShape.Square: | 794 | case ProfileShape.Square: |
@@ -824,16 +824,16 @@ public sealed class BSPrim : BSPhysObject | |||
824 | 824 | ||
825 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 825 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) |
826 | { | 826 | { |
827 | //a tube | 827 | //a tube |
828 | 828 | ||
829 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); | 829 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); |
830 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); | 830 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); |
831 | volume -= volume*tmp*tmp; | 831 | volume -= volume*tmp*tmp; |
832 | 832 | ||
833 | if (hollowAmount > 0.0) | 833 | if (hollowAmount > 0.0) |
834 | { | 834 | { |
835 | hollowVolume *= hollowAmount; | 835 | hollowVolume *= hollowAmount; |
836 | 836 | ||
837 | switch (_pbs.HollowShape) | 837 | switch (_pbs.HollowShape) |
838 | { | 838 | { |
839 | case HollowShape.Square: | 839 | case HollowShape.Square: |
@@ -892,7 +892,7 @@ public sealed class BSPrim : BSPhysObject | |||
892 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); | 892 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); |
893 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | 893 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); |
894 | volume *= (1.0f - tmp * tmp); | 894 | volume *= (1.0f - tmp * tmp); |
895 | 895 | ||
896 | if (hollowAmount > 0.0) | 896 | if (hollowAmount > 0.0) |
897 | { | 897 | { |
898 | 898 | ||
@@ -1071,302 +1071,17 @@ public sealed class BSPrim : BSPhysObject | |||
1071 | if (returnMass <= 0) | 1071 | if (returnMass <= 0) |
1072 | returnMass = 0.0001f; | 1072 | returnMass = 0.0001f; |
1073 | 1073 | ||
1074 | if (returnMass > _scene.MaximumObjectMass) | 1074 | if (returnMass > PhysicsScene.MaximumObjectMass) |
1075 | returnMass = _scene.MaximumObjectMass; | 1075 | returnMass = PhysicsScene.MaximumObjectMass; |
1076 | 1076 | ||
1077 | return returnMass; | 1077 | return returnMass; |
1078 | }// end CalculateMass | 1078 | }// end CalculateMass |
1079 | #endregion Mass Calculation | 1079 | #endregion Mass Calculation |
1080 | 1080 | ||
1081 | // Create the geometry information in Bullet for later use. | ||
1082 | // The objects needs a hull if it's physical otherwise a mesh is enough. | ||
1083 | // No locking here because this is done when we know physics is not simulating. | ||
1084 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. | ||
1085 | // Returns 'true' if the geometry was rebuilt. | ||
1086 | // Called at taint-time! | ||
1087 | private bool CreateGeom(bool forceRebuild) | ||
1088 | { | ||
1089 | bool ret = false; | ||
1090 | bool haveShape = false; | ||
1091 | |||
1092 | // If the prim attributes are simple, this could be a simple Bullet native shape | ||
1093 | if ((_pbs.SculptEntry && !Scene.ShouldMeshSculptedPrim) | ||
1094 | || (_pbs.ProfileBegin == 0 && _pbs.ProfileEnd == 0 | ||
1095 | && _pbs.ProfileHollow == 0 | ||
1096 | && _pbs.PathTwist == 0 && _pbs.PathTwistBegin == 0 | ||
1097 | && _pbs.PathBegin == 0 && _pbs.PathEnd == 0 | ||
1098 | && _pbs.PathTaperX == 0 && _pbs.PathTaperY == 0 | ||
1099 | && _pbs.PathScaleX == 100 && _pbs.PathScaleY == 100 | ||
1100 | && _pbs.PathShearX == 0 && _pbs.PathShearY == 0) ) | ||
1101 | { | ||
1102 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) | ||
1103 | { | ||
1104 | haveShape = true; | ||
1105 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) | ||
1106 | { | ||
1107 | DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild); | ||
1108 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | ||
1109 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
1110 | _scale = _size; | ||
1111 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
1112 | ret = true; | ||
1113 | } | ||
1114 | } | ||
1115 | else | ||
1116 | { | ||
1117 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size); | ||
1118 | haveShape = true; | ||
1119 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)) | ||
1120 | { | ||
1121 | DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild); | ||
1122 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | ||
1123 | _scale = _size; | ||
1124 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
1125 | ret = true; | ||
1126 | } | ||
1127 | } | ||
1128 | } | ||
1129 | // If a simple shape isn't happening, create a mesh and possibly a hull | ||
1130 | if (!haveShape) | ||
1131 | { | ||
1132 | if (IsPhysical) | ||
1133 | { | ||
1134 | if (forceRebuild || _hullKey == 0) | ||
1135 | { | ||
1136 | // physical objects require a hull for interaction. | ||
1137 | // This also creates the mesh if it doesn't already exist | ||
1138 | ret = CreateGeomHull(); | ||
1139 | } | ||
1140 | } | ||
1141 | else | ||
1142 | { | ||
1143 | if (forceRebuild || _meshKey == 0) | ||
1144 | { | ||
1145 | // Static (non-physical) objects only need a mesh for bumping into | ||
1146 | ret = CreateGeomMesh(); | ||
1147 | } | ||
1148 | } | ||
1149 | } | ||
1150 | return ret; | ||
1151 | } | ||
1152 | |||
1153 | // No locking here because this is done when we know physics is not simulating | ||
1154 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). | ||
1155 | // Called at taint-time! | ||
1156 | private bool CreateGeomMesh() | ||
1157 | { | ||
1158 | // level of detail based on size and type of the object | ||
1159 | float lod = _scene.MeshLOD; | ||
1160 | if (_pbs.SculptEntry) | ||
1161 | lod = _scene.SculptLOD; | ||
1162 | float maxAxis = Math.Max(_size.X, Math.Max(_size.Y, _size.Z)); | ||
1163 | if (maxAxis > _scene.MeshMegaPrimThreshold) | ||
1164 | lod = _scene.MeshMegaPrimLOD; | ||
1165 | |||
1166 | ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
1167 | // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey); | ||
1168 | |||
1169 | // if this new shape is the same as last time, don't recreate the mesh | ||
1170 | if (_meshKey == newMeshKey) return false; | ||
1171 | |||
1172 | DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey); | ||
1173 | // Since we're recreating new, get rid of any previously generated shape | ||
1174 | if (_meshKey != 0) | ||
1175 | { | ||
1176 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); | ||
1177 | DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey); | ||
1178 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | ||
1179 | _mesh = null; | ||
1180 | _meshKey = 0; | ||
1181 | } | ||
1182 | |||
1183 | _meshKey = newMeshKey; | ||
1184 | // always pass false for physicalness as this creates some sort of bounding box which we don't need | ||
1185 | _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false); | ||
1186 | |||
1187 | int[] indices = _mesh.getIndexListAsInt(); | ||
1188 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1189 | |||
1190 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
1191 | int vi = 0; | ||
1192 | foreach (OMV.Vector3 vv in vertices) | ||
1193 | { | ||
1194 | verticesAsFloats[vi++] = vv.X; | ||
1195 | verticesAsFloats[vi++] = vv.Y; | ||
1196 | verticesAsFloats[vi++] = vv.Z; | ||
1197 | } | ||
1198 | |||
1199 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
1200 | // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); | ||
1201 | BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, | ||
1202 | vertices.Count, verticesAsFloats); | ||
1203 | |||
1204 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; | ||
1205 | // meshes are already scaled by the meshmerizer | ||
1206 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1207 | return true; | ||
1208 | } | ||
1209 | |||
1210 | // No locking here because this is done when we know physics is not simulating | ||
1211 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). | ||
1212 | private bool CreateGeomHull() | ||
1213 | { | ||
1214 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | ||
1215 | ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
1216 | // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey); | ||
1217 | |||
1218 | // if the hull hasn't changed, don't rebuild it | ||
1219 | if (newHullKey == _hullKey) return false; | ||
1220 | |||
1221 | DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey); | ||
1222 | |||
1223 | // Since we're recreating new, get rid of any previously generated shape | ||
1224 | if (_hullKey != 0) | ||
1225 | { | ||
1226 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); | ||
1227 | DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey); | ||
1228 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); | ||
1229 | _hullKey = 0; | ||
1230 | } | ||
1231 | |||
1232 | _hullKey = newHullKey; | ||
1233 | |||
1234 | // Make sure the underlying mesh exists and is correct | ||
1235 | CreateGeomMesh(); | ||
1236 | |||
1237 | int[] indices = _mesh.getIndexListAsInt(); | ||
1238 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1239 | |||
1240 | //format conversion from IMesh format to DecompDesc format | ||
1241 | List<int> convIndices = new List<int>(); | ||
1242 | List<float3> convVertices = new List<float3>(); | ||
1243 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
1244 | { | ||
1245 | convIndices.Add(indices[ii]); | ||
1246 | } | ||
1247 | foreach (OMV.Vector3 vv in vertices) | ||
1248 | { | ||
1249 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
1250 | } | ||
1251 | |||
1252 | // setup and do convex hull conversion | ||
1253 | _hulls = new List<ConvexResult>(); | ||
1254 | DecompDesc dcomp = new DecompDesc(); | ||
1255 | dcomp.mIndices = convIndices; | ||
1256 | dcomp.mVertices = convVertices; | ||
1257 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
1258 | // create the hull into the _hulls variable | ||
1259 | convexBuilder.process(dcomp); | ||
1260 | |||
1261 | // Convert the vertices and indices for passing to unmanaged. | ||
1262 | // The hull information is passed as a large floating point array. | ||
1263 | // The format is: | ||
1264 | // convHulls[0] = number of hulls | ||
1265 | // convHulls[1] = number of vertices in first hull | ||
1266 | // convHulls[2] = hull centroid X coordinate | ||
1267 | // convHulls[3] = hull centroid Y coordinate | ||
1268 | // convHulls[4] = hull centroid Z coordinate | ||
1269 | // convHulls[5] = first hull vertex X | ||
1270 | // convHulls[6] = first hull vertex Y | ||
1271 | // convHulls[7] = first hull vertex Z | ||
1272 | // convHulls[8] = second hull vertex X | ||
1273 | // ... | ||
1274 | // convHulls[n] = number of vertices in second hull | ||
1275 | // convHulls[n+1] = second hull centroid X coordinate | ||
1276 | // ... | ||
1277 | // | ||
1278 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
1279 | // data structures that do not need to be converted in order to pass to Bullet. | ||
1280 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
1281 | int hullCount = _hulls.Count; | ||
1282 | int totalVertices = 1; // include one for the count of the hulls | ||
1283 | foreach (ConvexResult cr in _hulls) | ||
1284 | { | ||
1285 | totalVertices += 4; // add four for the vertex count and centroid | ||
1286 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
1287 | } | ||
1288 | float[] convHulls = new float[totalVertices]; | ||
1289 | |||
1290 | convHulls[0] = (float)hullCount; | ||
1291 | int jj = 1; | ||
1292 | foreach (ConvexResult cr in _hulls) | ||
1293 | { | ||
1294 | // copy vertices for index access | ||
1295 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
1296 | int kk = 0; | ||
1297 | foreach (float3 ff in cr.HullVertices) | ||
1298 | { | ||
1299 | verts[kk++] = ff; | ||
1300 | } | ||
1301 | |||
1302 | // add to the array one hull's worth of data | ||
1303 | convHulls[jj++] = cr.HullIndices.Count; | ||
1304 | convHulls[jj++] = 0f; // centroid x,y,z | ||
1305 | convHulls[jj++] = 0f; | ||
1306 | convHulls[jj++] = 0f; | ||
1307 | foreach (int ind in cr.HullIndices) | ||
1308 | { | ||
1309 | convHulls[jj++] = verts[ind].x; | ||
1310 | convHulls[jj++] = verts[ind].y; | ||
1311 | convHulls[jj++] = verts[ind].z; | ||
1312 | } | ||
1313 | } | ||
1314 | |||
1315 | // create the hull definition in Bullet | ||
1316 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); | ||
1317 | BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); | ||
1318 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; | ||
1319 | // meshes are already scaled by the meshmerizer | ||
1320 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1321 | DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID); | ||
1322 | return true; | ||
1323 | } | ||
1324 | |||
1325 | // Callback from convex hull creater with a newly created hull. | ||
1326 | // Just add it to the collection of hulls for this shape. | ||
1327 | private void HullReturn(ConvexResult result) | ||
1328 | { | ||
1329 | _hulls.Add(result); | ||
1330 | return; | ||
1331 | } | ||
1332 | |||
1333 | private void VerifyCorrectPhysicalShape() | ||
1334 | { | ||
1335 | if (!IsStatic) | ||
1336 | { | ||
1337 | // if not static, it will need a hull to efficiently collide with things | ||
1338 | if (_hullKey == 0) | ||
1339 | { | ||
1340 | CreateGeomAndObject(false); | ||
1341 | } | ||
1342 | |||
1343 | } | ||
1344 | } | ||
1345 | |||
1346 | // Create an object in Bullet if it has not already been created | ||
1347 | // No locking here because this is done when the physics engine is not simulating | ||
1348 | // Returns 'true' if an object was actually created. | ||
1349 | private bool CreateObject() | ||
1350 | { | ||
1351 | // this routine is called when objects are rebuilt. | ||
1352 | |||
1353 | // the mesh or hull must have already been created in Bullet | ||
1354 | ShapeData shape; | ||
1355 | FillShapeInfo(out shape); | ||
1356 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); | ||
1357 | bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape); | ||
1358 | |||
1359 | // the CreateObject() may have recreated the rigid body. Make sure we have the latest address. | ||
1360 | BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
1361 | BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr)); | ||
1362 | |||
1363 | return ret; | ||
1364 | } | ||
1365 | |||
1366 | // Copy prim's info into the BulletSim shape description structure | 1081 | // Copy prim's info into the BulletSim shape description structure |
1367 | public void FillShapeInfo(out ShapeData shape) | 1082 | public void FillShapeInfo(out ShapeData shape) |
1368 | { | 1083 | { |
1369 | shape.ID = _localID; | 1084 | shape.ID = LocalID; |
1370 | shape.Type = _shapeType; | 1085 | shape.Type = _shapeType; |
1371 | shape.Position = _position; | 1086 | shape.Position = _position; |
1372 | shape.Rotation = _orientation; | 1087 | shape.Rotation = _orientation; |
@@ -1380,22 +1095,39 @@ public sealed class BSPrim : BSPhysObject | |||
1380 | shape.Restitution = _restitution; | 1095 | shape.Restitution = _restitution; |
1381 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; | 1096 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; |
1382 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | 1097 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; |
1098 | shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue; | ||
1099 | shape.Size = _size; | ||
1383 | } | 1100 | } |
1384 | |||
1385 | // Rebuild the geometry and object. | 1101 | // Rebuild the geometry and object. |
1386 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1102 | // This is called when the shape changes so we need to recreate the mesh/hull. |
1387 | // No locking here because this is done when the physics engine is not simulating | 1103 | // Called at taint-time!!! |
1388 | private void CreateGeomAndObject(bool forceRebuild) | 1104 | private void CreateGeomAndObject(bool forceRebuild) |
1389 | { | 1105 | { |
1390 | // m_log.DebugFormat("{0}: CreateGeomAndObject. lID={1}, force={2}", LogHeader, _localID, forceRebuild); | 1106 | ShapeData shapeData; |
1391 | // Create the geometry that will make up the object | 1107 | FillShapeInfo(out shapeData); |
1392 | if (CreateGeom(forceRebuild)) | 1108 | |
1109 | // If this prim is part of a linkset, we must remove and restore the physical | ||
1110 | // links of the body is rebuilt. | ||
1111 | bool needToRestoreLinkset = false; | ||
1112 | |||
1113 | // Create the correct physical representation for this type of object. | ||
1114 | // Updates BSBody and BSShape with the new information. | ||
1115 | PhysicsScene.Shapes.GetBodyAndShape(forceRebuild, PhysicsScene.World, this, shapeData, _pbs, | ||
1116 | null, delegate(BulletBody dBody) | ||
1117 | { | ||
1118 | // Called if the current prim body is about to be destroyed. | ||
1119 | // Remove all the physical dependencies on the old body. | ||
1120 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | ||
1121 | }); | ||
1122 | |||
1123 | if (needToRestoreLinkset) | ||
1393 | { | 1124 | { |
1394 | // Create the object and place it into the world | 1125 | // If physical body dependencies were removed, restore them |
1395 | CreateObject(); | 1126 | Linkset.RestoreBodyDependencies(this); |
1396 | // Make sure the properties are set on the new object | ||
1397 | UpdatePhysicalParameters(); | ||
1398 | } | 1127 | } |
1128 | |||
1129 | // Make sure the properties are set on the new object | ||
1130 | UpdatePhysicalParameters(); | ||
1399 | return; | 1131 | return; |
1400 | } | 1132 | } |
1401 | 1133 | ||
@@ -1485,66 +1217,10 @@ public sealed class BSPrim : BSPhysObject | |||
1485 | { | 1217 | { |
1486 | // For debugging, we can also report the movement of children | 1218 | // For debugging, we can also report the movement of children |
1487 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1219 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
1488 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | 1220 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, |
1489 | entprop.Acceleration, entprop.RotationalVelocity); | 1221 | entprop.Acceleration, entprop.RotationalVelocity); |
1490 | } | 1222 | } |
1491 | */ | 1223 | */ |
1492 | } | 1224 | } |
1493 | |||
1494 | // I've collided with something | ||
1495 | // Called at taint time from within the Step() function | ||
1496 | CollisionEventUpdate collisionCollection; | ||
1497 | public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
1498 | { | ||
1499 | bool ret = false; | ||
1500 | |||
1501 | // The following lines make IsColliding() and IsCollidingGround() work | ||
1502 | _collidingStep = Scene.SimulationStep; | ||
1503 | if (collidingWith <= Scene.TerrainManager.HighestTerrainID) | ||
1504 | { | ||
1505 | _collidingGroundStep = Scene.SimulationStep; | ||
1506 | } | ||
1507 | |||
1508 | // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith); | ||
1509 | |||
1510 | // prims in the same linkset cannot collide with each other | ||
1511 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) | ||
1512 | { | ||
1513 | return ret; | ||
1514 | } | ||
1515 | |||
1516 | // if someone has subscribed for collision events.... | ||
1517 | if (SubscribedEvents()) { | ||
1518 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
1519 | int nowTime = Scene.SimulationNowTime; | ||
1520 | if (nowTime >= _nextCollisionOkTime) { | ||
1521 | _nextCollisionOkTime = nowTime + _subscribedEventsMs; | ||
1522 | |||
1523 | if (collisionCollection == null) | ||
1524 | collisionCollection = new CollisionEventUpdate(); | ||
1525 | collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
1526 | ret = true; | ||
1527 | } | ||
1528 | } | ||
1529 | return ret; | ||
1530 | } | ||
1531 | |||
1532 | // The scene is telling us it's time to pass our collected collisions into the simulator | ||
1533 | public override void SendCollisions() | ||
1534 | { | ||
1535 | if (collisionCollection != null && collisionCollection.Count > 0) | ||
1536 | { | ||
1537 | base.SendCollisionUpdate(collisionCollection); | ||
1538 | // The collisionCollection structure is passed around in the simulator. | ||
1539 | // Make sure we don't have a handle to that one and that a new one is used next time. | ||
1540 | collisionCollection = null; | ||
1541 | } | ||
1542 | } | ||
1543 | |||
1544 | // Invoke the detailed logger and output something if it's enabled. | ||
1545 | private void DetailLog(string msg, params Object[] args) | ||
1546 | { | ||
1547 | Scene.PhysicsLogging.Write(msg, args); | ||
1548 | } | ||
1549 | } | 1225 | } |
1550 | } | 1226 | } |