aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1364
1 files changed, 661 insertions, 703 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index aaa0d93..9c20004 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -24,9 +24,6 @@
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.
30using System; 27using System;
31using System.Reflection; 28using System.Reflection;
32using System.Collections.Generic; 29using System.Collections.Generic;
@@ -39,18 +36,32 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
39 36
40namespace OpenSim.Region.Physics.BulletSPlugin 37namespace OpenSim.Region.Physics.BulletSPlugin
41{ 38{
42
43 [Serializable] 39 [Serializable]
44public sealed class BSPrim : BSPhysObject 40public sealed class BSPrim : PhysicsActor
45{ 41{
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private static readonly string LogHeader = "[BULLETS PRIM]"; 43 private static readonly string LogHeader = "[BULLETS PRIM]";
48 44
49 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 45 private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); }
50 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. 46
47 private IMesh _mesh;
48 private PrimitiveBaseShape _pbs;
49 private ShapeData.PhysicsShapeType _shapeType;
50 private ulong _meshKey;
51 private ulong _hullKey;
52 private List<ConvexResult> _hulls;
53
54 private BSScene _scene;
55 public BSScene Scene { get { return _scene; } }
56 private String _avName;
57 private uint _localID = 0;
58
59 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
60 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
51 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 61 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
52 // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer 62 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
53 63
64 private bool _stopped;
54 private bool _grabbed; 65 private bool _grabbed;
55 private bool _isSelected; 66 private bool _isSelected;
56 private bool _isVolumeDetect; 67 private bool _isVolumeDetect;
@@ -78,6 +89,25 @@ public sealed class BSPrim : BSPhysObject
78 private bool _kinematic; 89 private bool _kinematic;
79 private float _buoyancy; 90 private float _buoyancy;
80 91
92 // Membership in a linkset is controlled by this class.
93 private BSLinkset _linkset;
94 public BSLinkset Linkset
95 {
96 get { return _linkset; }
97 set { _linkset = value; }
98 }
99
100 private int _subscribedEventsMs = 0;
101 private int _nextCollisionOkTime = 0;
102 long _collidingStep;
103 long _collidingGroundStep;
104
105 private BulletBody m_body;
106 public BulletBody Body {
107 get { return m_body; }
108 set { m_body = value; }
109 }
110
81 private BSDynamics _vehicle; 111 private BSDynamics _vehicle;
82 112
83 private OMV.Vector3 _PIDTarget; 113 private OMV.Vector3 _PIDTarget;
@@ -92,112 +122,108 @@ public sealed class BSPrim : BSPhysObject
92 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 122 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
93 { 123 {
94 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 124 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
95 base.BaseInitialize(parent_scene, localID, primName, "BSPrim"); 125 _localID = localID;
96 _physicsActorType = (int)ActorTypes.Prim; 126 _avName = primName;
127 _scene = parent_scene;
97 _position = pos; 128 _position = pos;
98 _size = size; 129 _size = size;
99 Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 130 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
100 _orientation = rotation; 131 _orientation = rotation;
101 _buoyancy = 1f; 132 _buoyancy = 1f;
102 _velocity = OMV.Vector3.Zero; 133 _velocity = OMV.Vector3.Zero;
103 _rotationalVelocity = OMV.Vector3.Zero; 134 _rotationalVelocity = OMV.Vector3.Zero;
104 BaseShape = pbs; 135 _hullKey = 0;
136 _meshKey = 0;
137 _pbs = pbs;
105 _isPhysical = pisPhysical; 138 _isPhysical = pisPhysical;
106 _isVolumeDetect = false; 139 _isVolumeDetect = false;
107 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 140 _subscribedEventsMs = 0;
108 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material 141 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
109 _restitution = PhysicsScene.Params.defaultRestitution; 142 _density = _scene.Params.defaultDensity; // TODO: compute based on object material
110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness 143 _restitution = _scene.Params.defaultRestitution;
144 _linkset = new BSLinkset(_scene, this); // a linkset of one
145 _vehicle = new BSDynamics(this); // add vehicleness
111 _mass = CalculateMass(); 146 _mass = CalculateMass();
112
113 // No body or shape yet
114 PhysBody = new BulletBody(LocalID, IntPtr.Zero);
115 PhysShape = new BulletShape(IntPtr.Zero);
116
117 DetailLog("{0},BSPrim.constructor,call", LocalID);
118 // do the actual object creation at taint time 147 // do the actual object creation at taint time
119 PhysicsScene.TaintedObject("BSPrim.create", delegate() 148 DetailLog("{0},BSPrim.constructor,call", LocalID);
149 _scene.TaintedObject("BSPrim.create", delegate()
120 { 150 {
121 CreateGeomAndObject(true); 151 RecreateGeomAndObject();
122 152
123 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 153 // Get the pointer to the physical body for this object.
154 // At the moment, we're still letting BulletSim manage the creation and destruction
155 // of the object. Someday we'll move that into the C# code.
156 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
124 }); 157 });
125 } 158 }
126 159
127 // called when this prim is being destroyed and we should free all the resources 160 // called when this prim is being destroyed and we should free all the resources
128 public override void Destroy() 161 public void Destroy()
129 { 162 {
130 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 163 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
131 164
132 // Undo any links between me and any other object 165 // Undo any links between me and any other object
133 BSPhysObject parentBefore = Linkset.LinksetRoot; 166 BSPrim parentBefore = _linkset.LinksetRoot;
134 int childrenBefore = Linkset.NumberOfChildren; 167 int childrenBefore = _linkset.NumberOfChildren;
135 168
136 Linkset = Linkset.RemoveMeFromLinkset(this); 169 _linkset = _linkset.RemoveMeFromLinkset(this);
137 170
138 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", 171 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
139 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 172 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren);
140 173
141 // Undo any vehicle properties 174 // Undo any vehicle properties
142 this.VehicleType = (int)Vehicle.TYPE_NONE; 175 this.VehicleType = (int)Vehicle.TYPE_NONE;
143 176
144 PhysicsScene.TaintedObject("BSPrim.destroy", delegate() 177 _scene.TaintedObject("BSPrim.destroy", delegate()
145 { 178 {
146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 179 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
147 // If there are physical body and shape, release my use of same. 180 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
148 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 181 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
149 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
150 }); 182 });
151 } 183 }
152 184
153 // No one uses this property. 185 public override bool Stopped {
154 public override bool Stopped { 186 get { return _stopped; }
155 get { return false; }
156 } 187 }
157 public override OMV.Vector3 Size { 188 public override OMV.Vector3 Size {
158 get { return _size; } 189 get { return _size; }
159 set { 190 set {
160 _size = value; 191 _size = value;
161 ForceBodyShapeRebuild(false); 192 _scene.TaintedObject("BSPrim.setSize", delegate()
162 } 193 {
194 _mass = CalculateMass(); // changing size changes the mass
195 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
196 // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
197 RecreateGeomAndObject();
198 });
199 }
163 } 200 }
164 // Scale is what we set in the physics engine. It is different than 'size' in that 201 public override PrimitiveBaseShape Shape {
165 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
166 public override OMV.Vector3 Scale { get; set; }
167
168 public override PrimitiveBaseShape Shape {
169 set { 202 set {
170 BaseShape = value; 203 _pbs = value;
171 ForceBodyShapeRebuild(false); 204 _scene.TaintedObject("BSPrim.setShape", delegate()
172 } 205 {
206 _mass = CalculateMass(); // changing the shape changes the mass
207 RecreateGeomAndObject();
208 });
209 }
173 } 210 }
174 // Whatever the linkset wants is what I want. 211 public override uint LocalID {
175 public override ShapeData.PhysicsShapeType PreferredPhysicalShape 212 set { _localID = value; }
176 { get { return Linkset.PreferredPhysicalShape(this); } } 213 get { return _localID; }
177
178 public override bool ForceBodyShapeRebuild(bool inTaintTime)
179 {
180 LastAssetBuildFailed = false;
181 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
182 {
183 _mass = CalculateMass(); // changing the shape changes the mass
184 CreateGeomAndObject(true);
185 });
186 return true;
187 } 214 }
188 public override bool Grabbed { 215 public override bool Grabbed {
189 set { _grabbed = value; 216 set { _grabbed = value;
190 } 217 }
191 } 218 }
192 public override bool Selected { 219 public override bool Selected {
193 set { 220 set {
194 _isSelected = value; 221 _isSelected = value;
195 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 222 _scene.TaintedObject("BSPrim.setSelected", delegate()
196 { 223 {
197 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 224 SetObjectDynamic();
198 SetObjectDynamic(false);
199 }); 225 });
200 } 226 }
201 } 227 }
202 public override void CrossingFailure() { return; } 228 public override void CrossingFailure() { return; }
203 229
@@ -206,255 +232,158 @@ public sealed class BSPrim : BSPhysObject
206 BSPrim parent = obj as BSPrim; 232 BSPrim parent = obj as BSPrim;
207 if (parent != null) 233 if (parent != null)
208 { 234 {
209 BSPhysObject parentBefore = Linkset.LinksetRoot; 235 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID);
210 int childrenBefore = Linkset.NumberOfChildren; 236 BSPrim parentBefore = _linkset.LinksetRoot;
237 int childrenBefore = _linkset.NumberOfChildren;
211 238
212 Linkset = parent.Linkset.AddMeToLinkset(this); 239 _linkset = parent.Linkset.AddMeToLinkset(this);
213 240
214 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 241 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
215 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 242 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren);
216 } 243 }
217 return; 244 return;
218 } 245 }
219 246
220 // delink me from my linkset 247 // delink me from my linkset
221 public override void delink() { 248 public override void delink() {
222 // TODO: decide if this parent checking needs to happen at taint time 249 // TODO: decide if this parent checking needs to happen at taint time
223 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 250 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
251 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
252 _linkset.LinksetRoot._avName+"/"+_linkset.LinksetRoot.LocalID.ToString());
224 253
225 BSPhysObject parentBefore = Linkset.LinksetRoot; 254 BSPrim parentBefore = _linkset.LinksetRoot;
226 int childrenBefore = Linkset.NumberOfChildren; 255 int childrenBefore = _linkset.NumberOfChildren;
256
257 _linkset = _linkset.RemoveMeFromLinkset(this);
227 258
228 Linkset = Linkset.RemoveMeFromLinkset(this); 259 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
229 260 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren);
230 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 261 return;
231 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
232 return;
233 } 262 }
234 263
235 // Set motion values to zero. 264 // Set motion values to zero.
236 // Do it to the properties so the values get set in the physics engine. 265 // Do it to the properties so the values get set in the physics engine.
237 // Push the setting of the values to the viewer. 266 // Push the setting of the values to the viewer.
238 // Called at taint time! 267 // Called at taint time!
239 public override void ZeroMotion() 268 public void ZeroMotion()
240 { 269 {
241 _velocity = OMV.Vector3.Zero; 270 _velocity = OMV.Vector3.Zero;
242 _acceleration = OMV.Vector3.Zero; 271 _acceleration = OMV.Vector3.Zero;
243 _rotationalVelocity = OMV.Vector3.Zero; 272 _rotationalVelocity = OMV.Vector3.Zero;
244 273
245 // Zero some other properties in the physics engine 274 // Zero some other properties directly into the physics engine
246 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 275 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero);
276 BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
277 BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
278 BulletSimAPI.ClearForces2(Body.Ptr);
247 } 279 }
248 280
249 public override void LockAngularMotion(OMV.Vector3 axis) 281 public override void LockAngularMotion(OMV.Vector3 axis)
250 { 282 {
251 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 283 // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
252 return; 284 return;
253 } 285 }
254 286
255 public override OMV.Vector3 RawPosition 287 public override OMV.Vector3 Position {
256 { 288 get {
257 get { return _position; } 289 if (!_linkset.IsRoot(this))
258 set { _position = value; } 290 // child prims move around based on their parent. Need to get the latest location
259 } 291 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
260 public override OMV.Vector3 Position {
261 get {
262 // child prims move around based on their parent. Need to get the latest location
263 if (!Linkset.IsRoot(this))
264 _position = Linkset.Position(this);
265 292
266 // don't do the GetObjectPosition for root elements because this function is called a zillion times 293 // don't do the GetObjectPosition for root elements because this function is called a zillion times
267 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 294 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
268 return _position; 295 return _position;
269 } 296 }
270 set { 297 set {
271 // If you must push the position into the physics engine, use ForcePosition.
272 if (_position == value)
273 {
274 return;
275 }
276 _position = value; 298 _position = value;
277 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 299 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
278 PositionSanityCheck(); 300 _scene.TaintedObject("BSPrim.setPosition", delegate()
279 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
280 { 301 {
281 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 302 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
282 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 303 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
283 ActivateIfPhysical(false);
284 });
285 }
286 }
287 public override OMV.Vector3 ForcePosition {
288 get {
289 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
290 return _position;
291 }
292 set {
293 _position = value;
294 PositionSanityCheck();
295 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
296 ActivateIfPhysical(false);
297 }
298 }
299
300 // Check that the current position is sane and, if not, modify the position to make it so.
301 // Check for being below terrain and being out of bounds.
302 // Returns 'true' of the position was made sane by some action.
303 private bool PositionSanityCheck()
304 {
305 bool ret = false;
306
307 // If totally below the ground, move the prim up
308 // TODO: figure out the right solution for this... only for dynamic objects?
309 /*
310 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
311 if (Position.Z < terrainHeight)
312 {
313 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
314 _position.Z = terrainHeight + 2.0f;
315 ret = true;
316 }
317 */
318 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
319 {
320 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
321 // TODO: a floating motor so object will bob in the water
322 if (Position.Z < waterHeight)
323 {
324 _position.Z = waterHeight;
325 ret = true;
326 }
327 }
328
329 // TODO: check for out of bounds
330 return ret;
331 }
332
333 // A version of the sanity check that also makes sure a new position value is
334 // pushed to the physics engine. This routine would be used by anyone
335 // who is not already pushing the value.
336 private bool PositionSanityCheck(bool inTaintTime)
337 {
338 bool ret = false;
339 if (PositionSanityCheck())
340 {
341 // The new position value must be pushed into the physics engine but we can't
342 // just assign to "Position" because of potential call loops.
343 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate()
344 {
345 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
346 ForcePosition = _position;
347 }); 304 });
348 ret = true; 305 }
349 }
350 return ret;
351 } 306 }
352 307
353 // Return the effective mass of the object. 308 // Return the effective mass of the object.
354 // If there are multiple items in the linkset, add them together for the root 309 // If there are multiple items in the linkset, add them together for the root
355 public override float Mass 310 public override float Mass
356 { 311 {
357 get 312 get
358 { 313 {
359 return Linkset.LinksetMass; 314 return _linkset.LinksetMass;
360 // return _mass;
361 } 315 }
362 } 316 }
363 317
364 // used when we only want this prim's mass and not the linkset thing 318 // used when we only want this prim's mass and not the linkset thing
365 public override float RawMass { 319 public float MassRaw { get { return _mass; } }
366 get { return _mass; }
367 }
368 // Set the physical mass to the passed mass.
369 // Note that this does not change _mass!
370 public override void UpdatePhysicalMassProperties(float physMass)
371 {
372 if (IsStatic)
373 {
374 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, OMV.Vector3.Zero);
375 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
376 }
377 else
378 {
379 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
380 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
381 // center of mass is at the zero of the object
382 BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
383 // BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
384 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, localInertia);
385 }
386 }
387 320
388 // Is this used? 321 // Is this used?
389 public override OMV.Vector3 CenterOfMass 322 public override OMV.Vector3 CenterOfMass
390 { 323 {
391 get { return Linkset.CenterOfMass; } 324 get { return _linkset.CenterOfMass; }
392 } 325 }
393 326
394 // Is this used? 327 // Is this used?
395 public override OMV.Vector3 GeometricCenter 328 public override OMV.Vector3 GeometricCenter
396 { 329 {
397 get { return Linkset.GeometricCenter; } 330 get { return _linkset.GeometricCenter; }
398 } 331 }
399 332
400 public override OMV.Vector3 Force { 333 public override OMV.Vector3 Force {
401 get { return _force; } 334 get { return _force; }
402 set { 335 set {
403 _force = value; 336 _force = value;
404 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 337 _scene.TaintedObject("BSPrim.setForce", delegate()
405 { 338 {
406 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 339 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
407 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 340 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
341 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
408 }); 342 });
409 } 343 }
410 } 344 }
411 345
412 public override int VehicleType { 346 public override int VehicleType {
413 get { 347 get {
414 return (int)_vehicle.Type; // if we are a vehicle, return that type 348 return (int)_vehicle.Type; // if we are a vehicle, return that type
415 } 349 }
416 set { 350 set {
417 Vehicle type = (Vehicle)value; 351 Vehicle type = (Vehicle)value;
418 352 BSPrim vehiclePrim = this;
419 // Tell the scene about the vehicle so it will get processing each frame. 353 _scene.TaintedObject("setVehicleType", delegate()
420 PhysicsScene.VehicleInSceneTypeChanged(this, type);
421
422 PhysicsScene.TaintedObject("setVehicleType", delegate()
423 { 354 {
424 // Done at taint time so we're sure the physics engine is not using the variables 355 // Done at taint time so we're sure the physics engine is not using the variables
425 // Vehicle code changes the parameters for this vehicle type. 356 // Vehicle code changes the parameters for this vehicle type.
426 _vehicle.ProcessTypeChange(type); 357 _vehicle.ProcessTypeChange(type);
427 ActivateIfPhysical(false); 358 // Tell the scene about the vehicle so it will get processing each frame.
359 _scene.VehicleInSceneTypeChanged(this, type);
428 }); 360 });
429 } 361 }
430 } 362 }
431 public override void VehicleFloatParam(int param, float value) 363 public override void VehicleFloatParam(int param, float value)
432 { 364 {
433 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 365 _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
434 { 366 {
435 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 367 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
436 ActivateIfPhysical(false);
437 }); 368 });
438 } 369 }
439 public override void VehicleVectorParam(int param, OMV.Vector3 value) 370 public override void VehicleVectorParam(int param, OMV.Vector3 value)
440 { 371 {
441 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 372 _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
442 { 373 {
443 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 374 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
444 ActivateIfPhysical(false);
445 }); 375 });
446 } 376 }
447 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 377 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
448 { 378 {
449 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 379 _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
450 { 380 {
451 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 381 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
452 ActivateIfPhysical(false);
453 }); 382 });
454 } 383 }
455 public override void VehicleFlags(int param, bool remove) 384 public override void VehicleFlags(int param, bool remove)
456 { 385 {
457 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 386 _scene.TaintedObject("BSPrim.VehicleFlags", delegate()
458 { 387 {
459 _vehicle.ProcessVehicleFlags(param, remove); 388 _vehicle.ProcessVehicleFlags(param, remove);
460 }); 389 });
@@ -462,355 +391,143 @@ public sealed class BSPrim : BSPhysObject
462 391
463 // Called each simulation step to advance vehicle characteristics. 392 // Called each simulation step to advance vehicle characteristics.
464 // Called from Scene when doing simulation step so we're in taint processing time. 393 // Called from Scene when doing simulation step so we're in taint processing time.
465 public override void StepVehicle(float timeStep) 394 public void StepVehicle(float timeStep)
466 { 395 {
467 if (IsPhysical && _vehicle.IsActive) 396 if (IsPhysical)
468 {
469 _vehicle.Step(timeStep); 397 _vehicle.Step(timeStep);
470 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
471 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
472 {
473 // This resets the interpolation values and recomputes the tensor variables
474 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
475 });
476 */
477 }
478 } 398 }
479 399
480 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 400 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
481 public override void SetVolumeDetect(int param) { 401 public override void SetVolumeDetect(int param) {
482 bool newValue = (param != 0); 402 bool newValue = (param != 0);
483 if (_isVolumeDetect != newValue) 403 _isVolumeDetect = newValue;
404 _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
484 { 405 {
485 _isVolumeDetect = newValue; 406 SetObjectDynamic();
486 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() 407 });
487 { 408 return;
488 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
489 SetObjectDynamic(true);
490 });
491 }
492 return;
493 } 409 }
494 public override OMV.Vector3 Velocity { 410
495 get { return _velocity; } 411 public override OMV.Vector3 Velocity {
412 get { return _velocity; }
496 set { 413 set {
497 _velocity = value; 414 _velocity = value;
498 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 415 _scene.TaintedObject("BSPrim.setVelocity", delegate()
499 { 416 {
500 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 417 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
501 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 418 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
502 }); 419 });
503 } 420 }
504 }
505 public override OMV.Vector3 ForceVelocity {
506 get { return _velocity; }
507 set {
508 _velocity = value;
509 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
510 }
511 } 421 }
512 public override OMV.Vector3 Torque { 422 public override OMV.Vector3 Torque {
513 get { return _torque; } 423 get { return _torque; }
514 set { 424 set { _torque = value;
515 _torque = value;
516 AddAngularForce(_torque, false, false);
517 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 425 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
518 } 426 }
519 } 427 }
520 public override float CollisionScore { 428 public override float CollisionScore {
521 get { return _collisionScore; } 429 get { return _collisionScore; }
522 set { _collisionScore = value; 430 set { _collisionScore = value;
523 } 431 }
524 } 432 }
525 public override OMV.Vector3 Acceleration { 433 public override OMV.Vector3 Acceleration {
526 get { return _acceleration; } 434 get { return _acceleration; }
527 set { _acceleration = value; } 435 set { _acceleration = value; }
528 } 436 }
529 public override OMV.Quaternion RawOrientation 437 public override OMV.Quaternion Orientation {
530 {
531 get { return _orientation; }
532 set { _orientation = value; }
533 }
534 public override OMV.Quaternion Orientation {
535 get { 438 get {
536 // Children move around because tied to parent. Get a fresh value. 439 if (!_linkset.IsRoot(this))
537 if (!Linkset.IsRoot(this))
538 { 440 {
539 _orientation = Linkset.Orientation(this); 441 // Children move around because tied to parent. Get a fresh value.
442 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
540 } 443 }
541 return _orientation; 444 return _orientation;
542 } 445 }
543 set { 446 set {
544 if (_orientation == value)
545 return;
546 _orientation = value; 447 _orientation = value;
547 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 448 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
548 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 449 _scene.TaintedObject("BSPrim.setOrientation", delegate()
549 { 450 {
550 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 451 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
551 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 452 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
552 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 453 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
553 }); 454 });
554 } 455 }
555 } 456 }
556 // Go directly to Bullet to get/set the value. 457 public override int PhysicsActorType {
557 public override OMV.Quaternion ForceOrientation 458 get { return _physicsActorType; }
558 { 459 set { _physicsActorType = value;
559 get 460 }
560 {
561 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
562 return _orientation;
563 }
564 set
565 {
566 _orientation = value;
567 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
568 }
569 } 461 }
570 public override int PhysicsActorType { 462 public override bool IsPhysical {
571 get { return _physicsActorType; } 463 get { return _isPhysical; }
572 set { _physicsActorType = value; }
573 }
574 public override bool IsPhysical {
575 get { return _isPhysical; }
576 set { 464 set {
577 if (_isPhysical != value) 465 _isPhysical = value;
466 _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
578 { 467 {
579 _isPhysical = value; 468 SetObjectDynamic();
580 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 469 });
581 { 470 }
582 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
583 SetObjectDynamic(true);
584 // whether phys-to-static or static-to-phys, the object is not moving.
585 ZeroMotion();
586 });
587 }
588 }
589 } 471 }
590 472
591 // An object is static (does not move) if selected or not physical 473 // An object is static (does not move) if selected or not physical
592 public override bool IsStatic 474 private bool IsStatic
593 { 475 {
594 get { return _isSelected || !IsPhysical; } 476 get { return _isSelected || !IsPhysical; }
595 } 477 }
596 478
597 // An object is solid if it's not phantom and if it's not doing VolumeDetect 479 // An object is solid if it's not phantom and if it's not doing VolumeDetect
598 public override bool IsSolid 480 private bool IsSolid
599 { 481 {
600 get { return !IsPhantom && !_isVolumeDetect; } 482 get { return !IsPhantom && !_isVolumeDetect; }
601 } 483 }
602 484
603 // Make gravity work if the object is physical and not selected 485 // Make gravity work if the object is physical and not selected
604 // Called at taint-time!! 486 // No locking here because only called when it is safe
605 private void SetObjectDynamic(bool forceRebuild) 487 private void SetObjectDynamic()
606 {
607 // Recreate the physical object if necessary
608 CreateGeomAndObject(forceRebuild);
609 }
610
611 // Convert the simulator's physical properties into settings on BulletSim objects.
612 // There are four flags we're interested in:
613 // IsStatic: Object does not move, otherwise the object has mass and moves
614 // isSolid: other objects bounce off of this object
615 // isVolumeDetect: other objects pass through but can generate collisions
616 // collisionEvents: whether this object returns collision events
617 private void UpdatePhysicalParameters()
618 {
619 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
620
621 // Mangling all the physical properties requires the object not be in the physical world.
622 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
623 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
624
625 // Set up the object physicalness (does gravity and collisions move this object)
626 MakeDynamic(IsStatic);
627
628 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
629 _vehicle.Refresh();
630
631 // Arrange for collision events if the simulator wants them
632 EnableCollisions(SubscribedEvents());
633
634 // Make solid or not (do things bounce off or pass through this object).
635 MakeSolid(IsSolid);
636
637 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
638
639 // Rebuild its shape
640 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
641
642 // Collision filter can be set only when the object is in the world
643 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
644 {
645 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
646 }
647
648 // Recompute any linkset parameters.
649 // When going from non-physical to physical, this re-enables the constraints that
650 // had been automatically disabled when the mass was set to zero.
651 Linkset.Refresh(this);
652
653 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
654 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
655 }
656
657 // "Making dynamic" means changing to and from static.
658 // When static, gravity does not effect the object and it is fixed in space.
659 // When dynamic, the object can fall and be pushed by others.
660 // This is independent of its 'solidness' which controls what passes through
661 // this object and what interacts with it.
662 private void MakeDynamic(bool makeStatic)
663 { 488 {
664 if (makeStatic) 489 // RA: remove this for the moment.
665 { 490 // The problem is that dynamic objects are hulls so if we are becoming physical
666 // Become a Bullet 'static' object type 491 // the shape has to be checked and possibly built.
667 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 492 // Maybe a VerifyCorrectPhysicalShape() routine?
668 // Stop all movement 493 // RecreateGeomAndObject();
669 ZeroMotion();
670 // Center of mass is at the center of the object
671 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
672 // Mass is zero which disables a bunch of physics stuff in Bullet
673 UpdatePhysicalMassProperties(0f);
674 // Set collision detection parameters
675 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
676 {
677 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
678 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
679 }
680 // There can be special things needed for implementing linksets
681 Linkset.MakeStatic(this);
682 // The activation state is 'disabled' so Bullet will not try to act on it.
683 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
684 // Start it out sleeping and physical actions could wake it up.
685 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
686
687 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
688 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
689 }
690 else
691 {
692 // Not a Bullet static object
693 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
694
695 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
696 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
697 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
698
699 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
700 // Since this can be called multiple times, only zero forces when becoming physical
701 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
702 494
703 // For good measure, make sure the transform is set through to the motion state 495 // Bullet wants static objects to have a mass of zero
704 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 496 float mass = IsStatic ? 0f : _mass;
705 497
706 // Center of mass is at the center of the object 498 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
707 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
708
709 // A dynamic object has mass
710 UpdatePhysicalMassProperties(RawMass);
711
712 // Set collision detection parameters
713 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
714 {
715 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
716 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
717 }
718
719 // Various values for simulation limits
720 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
721 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
722 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
723 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
724
725 // There might be special things needed for implementing linksets.
726 Linkset.MakeDynamic(this);
727
728 // Force activation of the object so Bullet will act on it.
729 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
730 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
731 // BulletSimAPI.Activate2(BSBody.ptr, true);
732
733 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
734 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
735 }
736 }
737
738 // "Making solid" means that other object will not pass through this object.
739 // To make transparent, we create a Bullet ghost object.
740 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
741 // the functions after this one set up the state of a possibly newly created collision body.
742 private void MakeSolid(bool makeSolid)
743 {
744 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
745 if (makeSolid)
746 {
747 // Verify the previous code created the correct shape for this type of thing.
748 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
749 {
750 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
751 }
752 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
753 }
754 else
755 {
756 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
757 {
758 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
759 }
760 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
761 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
762 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
763 }
764 }
765 499
766 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so 500 // recompute any linkset parameters
767 // they need waking up when parameters are changed. 501 _linkset.Refresh(this);
768 // Called in taint-time!!
769 private void ActivateIfPhysical(bool forceIt)
770 {
771 if (IsPhysical)
772 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
773 }
774 502
775 // Turn on or off the flag controlling whether collision events are returned to the simulator. 503 CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr);
776 private void EnableCollisions(bool wantsCollisionEvents) 504 // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf);
777 {
778 if (wantsCollisionEvents)
779 {
780 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
781 }
782 else
783 {
784 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
785 }
786 } 505 }
787 506
788 // prims don't fly 507 // prims don't fly
789 public override bool Flying { 508 public override bool Flying {
790 get { return _flying; } 509 get { return _flying; }
791 set { 510 set { _flying = value; }
792 _flying = value;
793 }
794 } 511 }
795 public override bool SetAlwaysRun { 512 public override bool SetAlwaysRun {
796 get { return _setAlwaysRun; } 513 get { return _setAlwaysRun; }
797 set { _setAlwaysRun = value; } 514 set { _setAlwaysRun = value; }
798 } 515 }
799 public override bool ThrottleUpdates { 516 public override bool ThrottleUpdates {
800 get { return _throttleUpdates; } 517 get { return _throttleUpdates; }
801 set { _throttleUpdates = value; } 518 set { _throttleUpdates = value; }
802 } 519 }
803 public override bool IsColliding { 520 public override bool IsColliding {
804 get { return (CollidingStep == PhysicsScene.SimulationStep); } 521 get { return (_collidingStep == _scene.SimulationStep); }
805 set { _isColliding = value; } 522 set { _isColliding = value; }
806 } 523 }
807 public override bool CollidingGround { 524 public override bool CollidingGround {
808 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } 525 get { return (_collidingGroundStep == _scene.SimulationStep); }
809 set { _collidingGround = value; } 526 set { _collidingGround = value; }
810 } 527 }
811 public override bool CollidingObj { 528 public override bool CollidingObj {
812 get { return _collidingObj; } 529 get { return _collidingObj; }
813 set { _collidingObj = value; } 530 set { _collidingObj = value; }
814 } 531 }
815 public bool IsPhantom { 532 public bool IsPhantom {
816 get { 533 get {
@@ -820,19 +537,10 @@ public sealed class BSPrim : BSPhysObject
820 return false; 537 return false;
821 } 538 }
822 } 539 }
823 public override bool FloatOnWater { 540 public override bool FloatOnWater {
824 set { 541 set { _floatOnWater = value; }
825 _floatOnWater = value;
826 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
827 {
828 if (_floatOnWater)
829 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
830 else
831 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
832 });
833 }
834 } 542 }
835 public override OMV.Vector3 RotationalVelocity { 543 public override OMV.Vector3 RotationalVelocity {
836 get { 544 get {
837 /* 545 /*
838 OMV.Vector3 pv = OMV.Vector3.Zero; 546 OMV.Vector3 pv = OMV.Vector3.Zero;
@@ -844,76 +552,58 @@ public sealed class BSPrim : BSPhysObject
844 */ 552 */
845 553
846 return _rotationalVelocity; 554 return _rotationalVelocity;
847 } 555 }
848 set { 556 set {
849 _rotationalVelocity = value; 557 _rotationalVelocity = value;
850 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 558 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
851 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 559 _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
852 { 560 {
853 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 561 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
854 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 562 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
855 }); 563 });
856 } 564 }
857 }
858 public override OMV.Vector3 ForceRotationalVelocity {
859 get {
860 return _rotationalVelocity;
861 }
862 set {
863 _rotationalVelocity = value;
864 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
865 }
866 } 565 }
867 public override bool Kinematic { 566 public override bool Kinematic {
868 get { return _kinematic; } 567 get { return _kinematic; }
869 set { _kinematic = value; 568 set { _kinematic = value;
870 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); 569 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
871 } 570 }
872 } 571 }
873 public override float Buoyancy { 572 public override float Buoyancy {
874 get { return _buoyancy; } 573 get { return _buoyancy; }
875 set { 574 set {
876 _buoyancy = value; 575 _buoyancy = value;
877 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 576 _scene.TaintedObject("BSPrim.setBuoyancy", delegate()
878 { 577 {
879 ForceBuoyancy = _buoyancy; 578 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
579 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
880 }); 580 });
881 } 581 }
882 }
883 public override float ForceBuoyancy {
884 get { return _buoyancy; }
885 set {
886 _buoyancy = value;
887 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
888 // Buoyancy is faked by changing the gravity applied to the object
889 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
890 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
891 }
892 } 582 }
893 583
894 // Used for MoveTo 584 // Used for MoveTo
895 public override OMV.Vector3 PIDTarget { 585 public override OMV.Vector3 PIDTarget {
896 set { _PIDTarget = value; } 586 set { _PIDTarget = value; }
897 } 587 }
898 public override bool PIDActive { 588 public override bool PIDActive {
899 set { _usePID = value; } 589 set { _usePID = value; }
900 } 590 }
901 public override float PIDTau { 591 public override float PIDTau {
902 set { _PIDTau = value; } 592 set { _PIDTau = value; }
903 } 593 }
904 594
905 // Used for llSetHoverHeight and maybe vehicle height 595 // Used for llSetHoverHeight and maybe vehicle height
906 // Hover Height will override MoveTo target's Z 596 // Hover Height will override MoveTo target's Z
907 public override bool PIDHoverActive { 597 public override bool PIDHoverActive {
908 set { _useHoverPID = value; } 598 set { _useHoverPID = value; }
909 } 599 }
910 public override float PIDHoverHeight { 600 public override float PIDHoverHeight {
911 set { _PIDHoverHeight = value; } 601 set { _PIDHoverHeight = value; }
912 } 602 }
913 public override PIDHoverType PIDHoverType { 603 public override PIDHoverType PIDHoverType {
914 set { _PIDHoverType = value; } 604 set { _PIDHoverType = value; }
915 } 605 }
916 public override float PIDHoverTau { 606 public override float PIDHoverTau {
917 set { _PIDHoverTao = value; } 607 set { _PIDHoverTao = value; }
918 } 608 }
919 609
@@ -925,9 +615,6 @@ public sealed class BSPrim : BSPhysObject
925 615
926 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); 616 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
927 public override void AddForce(OMV.Vector3 force, bool pushforce) { 617 public override void AddForce(OMV.Vector3 force, bool pushforce) {
928 AddForce(force, pushforce, false);
929 }
930 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
931 // for an object, doesn't matter if force is a pushforce or not 618 // for an object, doesn't matter if force is a pushforce or not
932 if (force.IsFinite()) 619 if (force.IsFinite())
933 { 620 {
@@ -937,78 +624,56 @@ public sealed class BSPrim : BSPhysObject
937 } 624 }
938 else 625 else
939 { 626 {
940 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 627 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
941 return; 628 return;
942 } 629 }
943 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 630 _scene.TaintedObject("BSPrim.AddForce", delegate()
944 { 631 {
945 OMV.Vector3 fSum = OMV.Vector3.Zero; 632 OMV.Vector3 fSum = OMV.Vector3.Zero;
946 lock (m_accumulatedForces) 633 lock (m_accumulatedForces)
947 { 634 {
948 // Sum the accumulated additional forces for one big force to apply once.
949 foreach (OMV.Vector3 v in m_accumulatedForces) 635 foreach (OMV.Vector3 v in m_accumulatedForces)
950 { 636 {
951 fSum += v; 637 fSum += v;
952 } 638 }
953 m_accumulatedForces.Clear(); 639 m_accumulatedForces.Clear();
954 } 640 }
955 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 641 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force);
956 if (fSum != OMV.Vector3.Zero) 642 BulletSimAPI.AddObjectForce2(Body.Ptr, fSum);
957 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
958 }); 643 });
959 } 644 }
960 645
961 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); 646 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
962 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 647 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
963 AddAngularForce(force, pushforce, false); 648 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
964 } 649 }
965 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) 650 public override void SetMomentum(OMV.Vector3 momentum) {
966 { 651 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
967 if (force.IsFinite()) 652 }
968 { 653 public override void SubscribeEvents(int ms) {
969 // _force += force; 654 _subscribedEventsMs = ms;
970 lock (m_accumulatedAngularForces) 655 if (ms > 0)
971 m_accumulatedAngularForces.Add(new OMV.Vector3(force));
972 }
973 else
974 {
975 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
976 return;
977 }
978 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
979 { 656 {
980 OMV.Vector3 fSum = OMV.Vector3.Zero; 657 // make sure first collision happens
981 lock (m_accumulatedAngularForces) 658 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
982 { 659
983 // Sum the accumulated additional forces for one big force to apply once. 660 Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
984 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
985 {
986 fSum += v;
987 }
988 m_accumulatedAngularForces.Clear();
989 }
990 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
991 if (fSum != OMV.Vector3.Zero)
992 { 661 {
993 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); 662 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
994 _torque = fSum; 663 });
995 } 664 }
996 });
997 } 665 }
998 // A torque impulse. 666 public override void UnSubscribeEvents() {
999 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 667 _subscribedEventsMs = 0;
1000 { 668 Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
1001 OMV.Vector3 applyImpulse = impulse;
1002 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1003 { 669 {
1004 DetailLog("{0},BSPrim.ApplyTorqueImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 670 BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1005 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1006 }); 671 });
1007 } 672 }
1008 673 public override bool SubscribedEvents() {
1009 public override void SetMomentum(OMV.Vector3 momentum) { 674 return (_subscribedEventsMs > 0);
1010 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1011 } 675 }
676
1012 #region Mass Calculation 677 #region Mass Calculation
1013 678
1014 private float CalculateMass() 679 private float CalculateMass()
@@ -1017,19 +682,19 @@ public sealed class BSPrim : BSPhysObject
1017 float tmp; 682 float tmp;
1018 683
1019 float returnMass = 0; 684 float returnMass = 0;
1020 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; 685 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
1021 float hollowVolume = hollowAmount * hollowAmount; 686 float hollowVolume = hollowAmount * hollowAmount;
1022 687
1023 switch (BaseShape.ProfileShape) 688 switch (_pbs.ProfileShape)
1024 { 689 {
1025 case ProfileShape.Square: 690 case ProfileShape.Square:
1026 // default box 691 // default box
1027 692
1028 if (BaseShape.PathCurve == (byte)Extrusion.Straight) 693 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1029 { 694 {
1030 if (hollowAmount > 0.0) 695 if (hollowAmount > 0.0)
1031 { 696 {
1032 switch (BaseShape.HollowShape) 697 switch (_pbs.HollowShape)
1033 { 698 {
1034 case HollowShape.Square: 699 case HollowShape.Square:
1035 case HollowShape.Same: 700 case HollowShape.Same:
@@ -1053,19 +718,19 @@ public sealed class BSPrim : BSPhysObject
1053 } 718 }
1054 } 719 }
1055 720
1056 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) 721 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1057 { 722 {
1058 //a tube 723 //a tube
1059 724
1060 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); 725 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
1061 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); 726 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
1062 volume -= volume*tmp*tmp; 727 volume -= volume*tmp*tmp;
1063 728
1064 if (hollowAmount > 0.0) 729 if (hollowAmount > 0.0)
1065 { 730 {
1066 hollowVolume *= hollowAmount; 731 hollowVolume *= hollowAmount;
1067 732
1068 switch (BaseShape.HollowShape) 733 switch (_pbs.HollowShape)
1069 { 734 {
1070 case HollowShape.Square: 735 case HollowShape.Square:
1071 case HollowShape.Same: 736 case HollowShape.Same:
@@ -1090,13 +755,13 @@ public sealed class BSPrim : BSPhysObject
1090 755
1091 case ProfileShape.Circle: 756 case ProfileShape.Circle:
1092 757
1093 if (BaseShape.PathCurve == (byte)Extrusion.Straight) 758 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1094 { 759 {
1095 volume *= 0.78539816339f; // elipse base 760 volume *= 0.78539816339f; // elipse base
1096 761
1097 if (hollowAmount > 0.0) 762 if (hollowAmount > 0.0)
1098 { 763 {
1099 switch (BaseShape.HollowShape) 764 switch (_pbs.HollowShape)
1100 { 765 {
1101 case HollowShape.Same: 766 case HollowShape.Same:
1102 case HollowShape.Circle: 767 case HollowShape.Circle:
@@ -1118,19 +783,19 @@ public sealed class BSPrim : BSPhysObject
1118 } 783 }
1119 } 784 }
1120 785
1121 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) 786 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1122 { 787 {
1123 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); 788 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
1124 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); 789 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1125 volume *= (1.0f - tmp * tmp); 790 volume *= (1.0f - tmp * tmp);
1126 791
1127 if (hollowAmount > 0.0) 792 if (hollowAmount > 0.0)
1128 { 793 {
1129 794
1130 // calculate the hollow volume by it's shape compared to the prim shape 795 // calculate the hollow volume by it's shape compared to the prim shape
1131 hollowVolume *= hollowAmount; 796 hollowVolume *= hollowAmount;
1132 797
1133 switch (BaseShape.HollowShape) 798 switch (_pbs.HollowShape)
1134 { 799 {
1135 case HollowShape.Same: 800 case HollowShape.Same:
1136 case HollowShape.Circle: 801 case HollowShape.Circle:
@@ -1154,7 +819,7 @@ public sealed class BSPrim : BSPhysObject
1154 break; 819 break;
1155 820
1156 case ProfileShape.HalfCircle: 821 case ProfileShape.HalfCircle:
1157 if (BaseShape.PathCurve == (byte)Extrusion.Curve1) 822 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1158 { 823 {
1159 volume *= 0.52359877559829887307710723054658f; 824 volume *= 0.52359877559829887307710723054658f;
1160 } 825 }
@@ -1162,7 +827,7 @@ public sealed class BSPrim : BSPhysObject
1162 827
1163 case ProfileShape.EquilateralTriangle: 828 case ProfileShape.EquilateralTriangle:
1164 829
1165 if (BaseShape.PathCurve == (byte)Extrusion.Straight) 830 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1166 { 831 {
1167 volume *= 0.32475953f; 832 volume *= 0.32475953f;
1168 833
@@ -1170,7 +835,7 @@ public sealed class BSPrim : BSPhysObject
1170 { 835 {
1171 836
1172 // calculate the hollow volume by it's shape compared to the prim shape 837 // calculate the hollow volume by it's shape compared to the prim shape
1173 switch (BaseShape.HollowShape) 838 switch (_pbs.HollowShape)
1174 { 839 {
1175 case HollowShape.Same: 840 case HollowShape.Same:
1176 case HollowShape.Triangle: 841 case HollowShape.Triangle:
@@ -1195,11 +860,11 @@ public sealed class BSPrim : BSPhysObject
1195 volume *= (1.0f - hollowVolume); 860 volume *= (1.0f - hollowVolume);
1196 } 861 }
1197 } 862 }
1198 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) 863 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1199 { 864 {
1200 volume *= 0.32475953f; 865 volume *= 0.32475953f;
1201 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); 866 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
1202 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); 867 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1203 volume *= (1.0f - tmp * tmp); 868 volume *= (1.0f - tmp * tmp);
1204 869
1205 if (hollowAmount > 0.0) 870 if (hollowAmount > 0.0)
@@ -1207,7 +872,7 @@ public sealed class BSPrim : BSPhysObject
1207 872
1208 hollowVolume *= hollowAmount; 873 hollowVolume *= hollowAmount;
1209 874
1210 switch (BaseShape.HollowShape) 875 switch (_pbs.HollowShape)
1211 { 876 {
1212 case HollowShape.Same: 877 case HollowShape.Same:
1213 case HollowShape.Triangle: 878 case HollowShape.Triangle:
@@ -1247,26 +912,26 @@ public sealed class BSPrim : BSPhysObject
1247 float profileBegin; 912 float profileBegin;
1248 float profileEnd; 913 float profileEnd;
1249 914
1250 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) 915 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
1251 { 916 {
1252 taperX1 = BaseShape.PathScaleX * 0.01f; 917 taperX1 = _pbs.PathScaleX * 0.01f;
1253 if (taperX1 > 1.0f) 918 if (taperX1 > 1.0f)
1254 taperX1 = 2.0f - taperX1; 919 taperX1 = 2.0f - taperX1;
1255 taperX = 1.0f - taperX1; 920 taperX = 1.0f - taperX1;
1256 921
1257 taperY1 = BaseShape.PathScaleY * 0.01f; 922 taperY1 = _pbs.PathScaleY * 0.01f;
1258 if (taperY1 > 1.0f) 923 if (taperY1 > 1.0f)
1259 taperY1 = 2.0f - taperY1; 924 taperY1 = 2.0f - taperY1;
1260 taperY = 1.0f - taperY1; 925 taperY = 1.0f - taperY1;
1261 } 926 }
1262 else 927 else
1263 { 928 {
1264 taperX = BaseShape.PathTaperX * 0.01f; 929 taperX = _pbs.PathTaperX * 0.01f;
1265 if (taperX < 0.0f) 930 if (taperX < 0.0f)
1266 taperX = -taperX; 931 taperX = -taperX;
1267 taperX1 = 1.0f - taperX; 932 taperX1 = 1.0f - taperX;
1268 933
1269 taperY = BaseShape.PathTaperY * 0.01f; 934 taperY = _pbs.PathTaperY * 0.01f;
1270 if (taperY < 0.0f) 935 if (taperY < 0.0f)
1271 taperY = -taperY; 936 taperY = -taperY;
1272 taperY1 = 1.0f - taperY; 937 taperY1 = 1.0f - taperY;
@@ -1276,18 +941,20 @@ public sealed class BSPrim : BSPhysObject
1276 941
1277 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); 942 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1278 943
1279 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; 944 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
1280 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; 945 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
1281 volume *= (pathEnd - pathBegin); 946 volume *= (pathEnd - pathBegin);
1282 947
1283 // this is crude aproximation 948 // this is crude aproximation
1284 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; 949 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
1285 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; 950 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
1286 volume *= (profileEnd - profileBegin); 951 volume *= (profileEnd - profileBegin);
1287 952
1288 returnMass = _density * volume; 953 returnMass = _density * volume;
1289 954
1290 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. 955 /*
956 * This change means each object keeps its own mass and the Mass property
957 * will return the sum if we're part of a linkset.
1291 if (IsRootOfLinkset) 958 if (IsRootOfLinkset)
1292 { 959 {
1293 foreach (BSPrim prim in _childrenPrims) 960 foreach (BSPrim prim in _childrenPrims)
@@ -1300,42 +967,296 @@ public sealed class BSPrim : BSPhysObject
1300 if (returnMass <= 0) 967 if (returnMass <= 0)
1301 returnMass = 0.0001f; 968 returnMass = 0.0001f;
1302 969
1303 if (returnMass > PhysicsScene.MaximumObjectMass) 970 if (returnMass > _scene.MaximumObjectMass)
1304 returnMass = PhysicsScene.MaximumObjectMass; 971 returnMass = _scene.MaximumObjectMass;
1305 972
1306 return returnMass; 973 return returnMass;
1307 }// end CalculateMass 974 }// end CalculateMass
1308 #endregion Mass Calculation 975 #endregion Mass Calculation
1309 976
1310 // Rebuild the geometry and object. 977 // Create the geometry information in Bullet for later use
1311 // This is called when the shape changes so we need to recreate the mesh/hull. 978 // The objects needs a hull if it's physical otherwise a mesh is enough
1312 // Called at taint-time!!! 979 // No locking here because this is done when we know physics is not simulating
1313 private void CreateGeomAndObject(bool forceRebuild) 980 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
981 // Returns 'true' if the geometry was rebuilt
982 private bool CreateGeom(bool forceRebuild)
1314 { 983 {
1315 // If this prim is part of a linkset, we must remove and restore the physical 984 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
1316 // links if the body is rebuilt. 985 bool ret = false;
1317 bool needToRestoreLinkset = false; 986 if (!_scene.NeedsMeshing(_pbs))
1318
1319 // Create the correct physical representation for this type of object.
1320 // Updates BSBody and BSShape with the new information.
1321 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1322 // Returns 'true' if either the body or the shape was changed.
1323 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1324 { 987 {
1325 // Called if the current prim body is about to be destroyed. 988 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
1326 // Remove all the physical dependencies on the old body. 989 {
1327 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 990 // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
1328 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 991 // {
1329 }); 992 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
993 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
994 {
995 // DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
996 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
997 // Bullet native objects are scaled by the Bullet engine so pass the size in
998 _scale = _size;
999 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1000 ret = true;
1001 }
1002 // }
1003 }
1004 else
1005 {
1006 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
1007 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
1008 {
1009 // DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
1010 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
1011 _scale = _size;
1012 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1013 ret = true;
1014 }
1015 }
1016 }
1017 else
1018 {
1019 if (IsPhysical)
1020 {
1021 if (forceRebuild || _hullKey == 0)
1022 {
1023 // physical objects require a hull for interaction.
1024 // This will create the mesh if it doesn't already exist
1025 CreateGeomHull();
1026 ret = true;
1027 }
1028 }
1029 else
1030 {
1031 if (forceRebuild || _meshKey == 0)
1032 {
1033 // Static (non-physical) objects only need a mesh for bumping into
1034 CreateGeomMesh();
1035 ret = true;
1036 }
1037 }
1038 }
1039 return ret;
1040 }
1041
1042 // No locking here because this is done when we know physics is not simulating
1043 private void CreateGeomMesh()
1044 {
1045 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1046 ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
1047 // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
1048
1049 // if this new shape is the same as last time, don't recreate the mesh
1050 if (_meshKey == newMeshKey) return;
1051
1052 // DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey);
1053 // Since we're recreating new, get rid of any previously generated shape
1054 if (_meshKey != 0)
1055 {
1056 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1057 // DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
1058 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1059 _mesh = null;
1060 _meshKey = 0;
1061 }
1062
1063 _meshKey = newMeshKey;
1064 // always pass false for physicalness as this creates some sort of bounding box which we don't need
1065 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
1066
1067 int[] indices = _mesh.getIndexListAsInt();
1068 List<OMV.Vector3> vertices = _mesh.getVertexList();
1069
1070 float[] verticesAsFloats = new float[vertices.Count * 3];
1071 int vi = 0;
1072 foreach (OMV.Vector3 vv in vertices)
1073 {
1074 verticesAsFloats[vi++] = vv.X;
1075 verticesAsFloats[vi++] = vv.Y;
1076 verticesAsFloats[vi++] = vv.Z;
1077 }
1078
1079 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
1080 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
1081 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
1082 vertices.Count, verticesAsFloats);
1083
1084 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
1085 // meshes are already scaled by the meshmerizer
1086 _scale = new OMV.Vector3(1f, 1f, 1f);
1087 // DetailLog("{0},BSPrim.CreateGeomMesh,done", LocalID);
1088 return;
1089 }
1090
1091 // No locking here because this is done when we know physics is not simulating
1092 private void CreateGeomHull()
1093 {
1094 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1095 ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod);
1096 // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey);
1097
1098 // if the hull hasn't changed, don't rebuild it
1099 if (newHullKey == _hullKey) return;
1330 1100
1331 if (needToRestoreLinkset) 1101 // DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey);
1102
1103 // Since we're recreating new, get rid of any previously generated shape
1104 if (_hullKey != 0)
1332 { 1105 {
1333 // If physical body dependencies were removed, restore them 1106 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1334 Linkset.RestoreBodyDependencies(this); 1107 // DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey);
1108 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1109 _hullKey = 0;
1110 }
1111
1112 _hullKey = newHullKey;
1113
1114 // Make sure the underlying mesh exists and is correct
1115 CreateGeomMesh();
1116
1117 int[] indices = _mesh.getIndexListAsInt();
1118 List<OMV.Vector3> vertices = _mesh.getVertexList();
1119
1120 //format conversion from IMesh format to DecompDesc format
1121 List<int> convIndices = new List<int>();
1122 List<float3> convVertices = new List<float3>();
1123 for (int ii = 0; ii < indices.GetLength(0); ii++)
1124 {
1125 convIndices.Add(indices[ii]);
1126 }
1127 foreach (OMV.Vector3 vv in vertices)
1128 {
1129 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
1130 }
1131
1132 // setup and do convex hull conversion
1133 _hulls = new List<ConvexResult>();
1134 DecompDesc dcomp = new DecompDesc();
1135 dcomp.mIndices = convIndices;
1136 dcomp.mVertices = convVertices;
1137 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
1138 // create the hull into the _hulls variable
1139 convexBuilder.process(dcomp);
1140
1141 // Convert the vertices and indices for passing to unmanaged.
1142 // The hull information is passed as a large floating point array.
1143 // The format is:
1144 // convHulls[0] = number of hulls
1145 // convHulls[1] = number of vertices in first hull
1146 // convHulls[2] = hull centroid X coordinate
1147 // convHulls[3] = hull centroid Y coordinate
1148 // convHulls[4] = hull centroid Z coordinate
1149 // convHulls[5] = first hull vertex X
1150 // convHulls[6] = first hull vertex Y
1151 // convHulls[7] = first hull vertex Z
1152 // convHulls[8] = second hull vertex X
1153 // ...
1154 // convHulls[n] = number of vertices in second hull
1155 // convHulls[n+1] = second hull centroid X coordinate
1156 // ...
1157 //
1158 // TODO: is is very inefficient. Someday change the convex hull generator to return
1159 // data structures that do not need to be converted in order to pass to Bullet.
1160 // And maybe put the values directly into pinned memory rather than marshaling.
1161 int hullCount = _hulls.Count;
1162 int totalVertices = 1; // include one for the count of the hulls
1163 foreach (ConvexResult cr in _hulls)
1164 {
1165 totalVertices += 4; // add four for the vertex count and centroid
1166 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
1167 }
1168 float[] convHulls = new float[totalVertices];
1169
1170 convHulls[0] = (float)hullCount;
1171 int jj = 1;
1172 foreach (ConvexResult cr in _hulls)
1173 {
1174 // copy vertices for index access
1175 float3[] verts = new float3[cr.HullVertices.Count];
1176 int kk = 0;
1177 foreach (float3 ff in cr.HullVertices)
1178 {
1179 verts[kk++] = ff;
1180 }
1181
1182 // add to the array one hull's worth of data
1183 convHulls[jj++] = cr.HullIndices.Count;
1184 convHulls[jj++] = 0f; // centroid x,y,z
1185 convHulls[jj++] = 0f;
1186 convHulls[jj++] = 0f;
1187 foreach (int ind in cr.HullIndices)
1188 {
1189 convHulls[jj++] = verts[ind].x;
1190 convHulls[jj++] = verts[ind].y;
1191 convHulls[jj++] = verts[ind].z;
1192 }
1335 } 1193 }
1336 1194
1337 // Make sure the properties are set on the new object 1195 // create the hull definition in Bullet
1338 UpdatePhysicalParameters(); 1196 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1197 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1198 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1199 // meshes are already scaled by the meshmerizer
1200 _scale = new OMV.Vector3(1f, 1f, 1f);
1201 // DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID);
1202 return;
1203 }
1204
1205 // Callback from convex hull creater with a newly created hull.
1206 // Just add it to the collection of hulls for this shape.
1207 private void HullReturn(ConvexResult result)
1208 {
1209 _hulls.Add(result);
1210 return;
1211 }
1212
1213 // Create an object in Bullet if it has not already been created
1214 // No locking here because this is done when the physics engine is not simulating
1215 // Returns 'true' if an object was actually created.
1216 private bool CreateObject()
1217 {
1218 // this routine is called when objects are rebuilt.
1219
1220 // the mesh or hull must have already been created in Bullet
1221 ShapeData shape;
1222 FillShapeInfo(out shape);
1223 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1224 bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
1225
1226 // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
1227 Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
1228
1229 return ret;
1230 }
1231
1232 // Copy prim's info into the BulletSim shape description structure
1233 public void FillShapeInfo(out ShapeData shape)
1234 {
1235 shape.ID = _localID;
1236 shape.Type = _shapeType;
1237 shape.Position = _position;
1238 shape.Rotation = _orientation;
1239 shape.Velocity = _velocity;
1240 shape.Scale = _scale;
1241 shape.Mass = _isPhysical ? _mass : 0f;
1242 shape.Buoyancy = _buoyancy;
1243 shape.HullKey = _hullKey;
1244 shape.MeshKey = _meshKey;
1245 shape.Friction = _friction;
1246 shape.Restitution = _restitution;
1247 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1248 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1249 }
1250
1251
1252 // Rebuild the geometry and object.
1253 // This is called when the shape changes so we need to recreate the mesh/hull.
1254 // No locking here because this is done when the physics engine is not simulating
1255 private void RecreateGeomAndObject()
1256 {
1257 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID);
1258 if (CreateGeom(true))
1259 CreateObject();
1339 return; 1260 return;
1340 } 1261 }
1341 1262
@@ -1356,7 +1277,7 @@ public sealed class BSPrim : BSPhysObject
1356 const float ACCELERATION_TOLERANCE = 0.01f; 1277 const float ACCELERATION_TOLERANCE = 0.01f;
1357 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1278 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1358 1279
1359 public override void UpdateProperties(EntityProperties entprop) 1280 public void UpdateProperties(EntityProperties entprop)
1360 { 1281 {
1361 /* 1282 /*
1362 UpdatedProperties changed = 0; 1283 UpdatedProperties changed = 0;
@@ -1404,7 +1325,7 @@ public sealed class BSPrim : BSPhysObject
1404 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1325 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1405 1326
1406 // Updates only for individual prims and for the root object of a linkset. 1327 // Updates only for individual prims and for the root object of a linkset.
1407 if (Linkset.IsRoot(this)) 1328 if (_linkset.IsRoot(this))
1408 { 1329 {
1409 // Assign to the local variables so the normal set action does not happen 1330 // Assign to the local variables so the normal set action does not happen
1410 _position = entprop.Position; 1331 _position = entprop.Position;
@@ -1413,32 +1334,69 @@ public sealed class BSPrim : BSPhysObject
1413 _acceleration = entprop.Acceleration; 1334 _acceleration = entprop.Acceleration;
1414 _rotationalVelocity = entprop.RotationalVelocity; 1335 _rotationalVelocity = entprop.RotationalVelocity;
1415 1336
1416 // remember the current and last set values 1337 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1417 LastEntityProperties = CurrentEntityProperties; 1338 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1418 CurrentEntityProperties = entprop; 1339 // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1419 1340 // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1420 PositionSanityCheck(true);
1421
1422 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1423 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1424 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1425
1426 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1427 1341
1428 base.RequestPhysicsterseUpdate(); 1342 base.RequestPhysicsterseUpdate();
1429 } 1343 }
1430 /* 1344 /*
1431 else 1345 else
1432 { 1346 {
1433 // For debugging, report the movement of children 1347 // For debugging, we also report the movement of children
1434 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1348 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1435 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1349 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1436 entprop.Acceleration, entprop.RotationalVelocity); 1350 entprop.Acceleration, entprop.RotationalVelocity);
1437 } 1351 }
1438 */ 1352 */
1353 }
1354
1355 // I've collided with something
1356 CollisionEventUpdate collisionCollection;
1357 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1358 {
1359 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1360
1361 // The following lines make IsColliding() and IsCollidingGround() work
1362 _collidingStep = _scene.SimulationStep;
1363 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1364 {
1365 _collidingGroundStep = _scene.SimulationStep;
1366 }
1367
1368 // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
1369
1370 // if someone is subscribed to collision events....
1371 if (_subscribedEventsMs != 0) {
1372 // throttle the collisions to the number of milliseconds specified in the subscription
1373 int nowTime = _scene.SimulationNowTime;
1374 if (nowTime >= _nextCollisionOkTime) {
1375 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
1439 1376
1440 // The linkset implimentation might want to know about this. 1377 if (collisionCollection == null)
1441 Linkset.UpdateProperties(this); 1378 collisionCollection = new CollisionEventUpdate();
1379 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1380 }
1381 }
1382 }
1383
1384 // The scene is telling us it's time to pass our collected collisions into the simulator
1385 public void SendCollisions()
1386 {
1387 if (collisionCollection != null && collisionCollection.Count > 0)
1388 {
1389 base.SendCollisionUpdate(collisionCollection);
1390 // The collisionCollection structure is passed around in the simulator.
1391 // Make sure we don't have a handle to that one and that a new one is used next time.
1392 collisionCollection = null;
1393 }
1394 }
1395
1396 // Invoke the detailed logger and output something if it's enabled.
1397 private void DetailLog(string msg, params Object[] args)
1398 {
1399 Scene.PhysicsLogging.Write(msg, args);
1442 } 1400 }
1443} 1401}
1444} 1402}