aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs58
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs672
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs45
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs621
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs112
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs393
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs385
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs238
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1269
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs858
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs833
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs492
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs727
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs4
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs12
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs17
17 files changed, 4569 insertions, 2171 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
index 683bc51..3306a97 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
@@ -34,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public class BS6DofConstraint : BSConstraint 35public class BS6DofConstraint : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
37 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
38 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
39 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
@@ -44,11 +48,14 @@ public class BS6DofConstraint : BSConstraint
44 m_body1 = obj1; 48 m_body1 = obj1;
45 m_body2 = obj2; 49 m_body2 = obj2;
46 m_constraint = new BulletConstraint( 50 m_constraint = new BulletConstraint(
47 BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
48 frame1, frame1rot, 52 frame1, frame1rot,
49 frame2, frame2rot, 53 frame2, frame2rot,
50 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
51 m_enabled = true; 55 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
52 } 59 }
53 60
54 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 61 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
@@ -58,11 +65,36 @@ public class BS6DofConstraint : BSConstraint
58 m_world = world; 65 m_world = world;
59 m_body1 = obj1; 66 m_body1 = obj1;
60 m_body2 = obj2; 67 m_body2 = obj2;
61 m_constraint = new BulletConstraint( 68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
62 BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 69 {
63 joinPoint, 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
64 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 71 BSScene.DetailLogZero, world.worldID,
65 m_enabled = true; 72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 "[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
75 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
76 m_enabled = false;
77 }
78 else
79 {
80 m_constraint = new BulletConstraint(
81 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
82 joinPoint,
83 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
84 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
85 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
86 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
87 if (m_constraint.ptr == IntPtr.Zero)
88 {
89 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
90 LogHeader, obj1.ID, obj2.ID);
91 m_enabled = false;
92 }
93 else
94 {
95 m_enabled = true;
96 }
97 }
66 } 98 }
67 99
68 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 100 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
@@ -70,7 +102,7 @@ public class BS6DofConstraint : BSConstraint
70 bool ret = false; 102 bool ret = false;
71 if (m_enabled) 103 if (m_enabled)
72 { 104 {
73 BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot); 105 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
74 ret = true; 106 ret = true;
75 } 107 }
76 return ret; 108 return ret;
@@ -81,9 +113,9 @@ public class BS6DofConstraint : BSConstraint
81 bool ret = false; 113 bool ret = false;
82 if (m_enabled) 114 if (m_enabled)
83 { 115 {
84 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
85 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
86 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 118 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
87 ret = true; 119 ret = true;
88 } 120 }
89 return ret; 121 return ret;
@@ -94,7 +126,7 @@ public class BS6DofConstraint : BSConstraint
94 bool ret = false; 126 bool ret = false;
95 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 127 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
96 if (m_enabled) 128 if (m_enabled)
97 ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff); 129 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
98 return ret; 130 return ret;
99 } 131 }
100 132
@@ -103,7 +135,7 @@ public class BS6DofConstraint : BSConstraint
103 bool ret = false; 135 bool ret = false;
104 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 136 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
105 if (m_enabled) 137 if (m_enabled)
106 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce); 138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
107 return ret; 139 return ret;
108 } 140 }
109 141
@@ -111,7 +143,7 @@ public class BS6DofConstraint : BSConstraint
111 { 143 {
112 bool ret = false; 144 bool ret = false;
113 if (m_enabled) 145 if (m_enabled)
114 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold); 146 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
115 return ret; 147 return ret;
116 } 148 }
117} 149}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index e2f7af9..a041ba8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -28,62 +28,48 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSCharacter : PhysicsActor 37public class BSCharacter : BSPhysObject
38{ 38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]"; 40 private static readonly string LogHeader = "[BULLETS CHAR]";
41 41
42 private BSScene _scene;
43 public BSScene Scene { get { return _scene; } }
44 private String _avName;
45 // private bool _stopped; 42 // private bool _stopped;
46 private Vector3 _size; 43 private OMV.Vector3 _size;
47 private Vector3 _scale;
48 private PrimitiveBaseShape _pbs;
49 private uint _localID = 0;
50 private bool _grabbed; 44 private bool _grabbed;
51 private bool _selected; 45 private bool _selected;
52 private Vector3 _position; 46 private OMV.Vector3 _position;
53 private float _mass; 47 private float _mass;
54 public float _density; 48 private float _avatarDensity;
55 public float _avatarVolume; 49 private float _avatarVolume;
56 private Vector3 _force; 50 private OMV.Vector3 _force;
57 private Vector3 _velocity; 51 private OMV.Vector3 _velocity;
58 private Vector3 _torque; 52 private OMV.Vector3 _torque;
59 private float _collisionScore; 53 private float _collisionScore;
60 private Vector3 _acceleration; 54 private OMV.Vector3 _acceleration;
61 private Quaternion _orientation; 55 private OMV.Quaternion _orientation;
62 private int _physicsActorType; 56 private int _physicsActorType;
63 private bool _isPhysical; 57 private bool _isPhysical;
64 private bool _flying; 58 private bool _flying;
65 private bool _setAlwaysRun; 59 private bool _setAlwaysRun;
66 private bool _throttleUpdates; 60 private bool _throttleUpdates;
67 private bool _isColliding; 61 private bool _isColliding;
68 private long _collidingStep;
69 private bool _collidingGround;
70 private long _collidingGroundStep;
71 private bool _collidingObj; 62 private bool _collidingObj;
72 private bool _floatOnWater; 63 private bool _floatOnWater;
73 private Vector3 _rotationalVelocity; 64 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic; 65 private bool _kinematic;
75 private float _buoyancy; 66 private float _buoyancy;
76 67
77 private BulletBody m_body; 68 // The friction and velocity of the avatar is modified depending on whether walking or not.
78 public BulletBody Body { 69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
79 get { return m_body; } 70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
80 set { m_body = value; }
81 }
82
83 private int _subscribedEventsMs = 0;
84 private int _nextCollisionOkTime = 0;
85 71
86 private Vector3 _PIDTarget; 72 private OMV.Vector3 _PIDTarget;
87 private bool _usePID; 73 private bool _usePID;
88 private float _PIDTau; 74 private float _PIDTau;
89 private bool _useHoverPID; 75 private bool _useHoverPID;
@@ -91,332 +77,504 @@ public class BSCharacter : PhysicsActor
91 private PIDHoverType _PIDHoverType; 77 private PIDHoverType _PIDHoverType;
92 private float _PIDHoverTao; 78 private float _PIDHoverTao;
93 79
94 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) 80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
95 { 81 {
96 _localID = localID; 82 base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
97 _avName = avName; 83 _physicsActorType = (int)ActorTypes.Agent;
98 _scene = parent_scene;
99 _position = pos; 84 _position = pos;
100 _size = size; 85 _size = size;
101 _flying = isFlying; 86 _flying = isFlying;
102 _orientation = Quaternion.Identity; 87 _orientation = OMV.Quaternion.Identity;
103 _velocity = Vector3.Zero; 88 _velocity = OMV.Vector3.Zero;
89 _appliedVelocity = OMV.Vector3.Zero;
104 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
92 _avatarDensity = PhysicsScene.Params.avatarDensity;
93
105 // The dimensions of the avatar capsule are kept in the scale. 94 // The dimensions of the avatar capsule are kept in the scale.
106 // Physics creates a unit capsule which is scaled by the physics engine. 95 // Physics creates a unit capsule which is scaled by the physics engine.
107 _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); 96 ComputeAvatarScale(_size);
108 _density = _scene.Params.avatarDensity; 97 // set _avatarVolume and _mass based on capsule size, _density and Scale
109 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 98 ComputeAvatarVolumeAndMass();
99 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
100 LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
110 101
111 ShapeData shapeData = new ShapeData(); 102 ShapeData shapeData = new ShapeData();
112 shapeData.ID = _localID; 103 shapeData.ID = LocalID;
113 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; 104 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
114 shapeData.Position = _position; 105 shapeData.Position = _position;
115 shapeData.Rotation = _orientation; 106 shapeData.Rotation = _orientation;
116 shapeData.Velocity = _velocity; 107 shapeData.Velocity = _velocity;
117 shapeData.Scale = _scale; 108 shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1>
109 shapeData.Scale = Scale;
118 shapeData.Mass = _mass; 110 shapeData.Mass = _mass;
119 shapeData.Buoyancy = _buoyancy; 111 shapeData.Buoyancy = _buoyancy;
120 shapeData.Static = ShapeData.numericFalse; 112 shapeData.Static = ShapeData.numericFalse;
121 shapeData.Friction = _scene.Params.avatarFriction; 113 shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
122 shapeData.Restitution = _scene.Params.avatarRestitution; 114 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
123 115
124 // do actual create at taint time 116 // do actual create at taint time
125 _scene.TaintedObject("BSCharacter.create", delegate() 117 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
126 { 118 {
127 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); 119 DetailLog("{0},BSCharacter.create,taint", LocalID);
120 // New body and shape into BSBody and BSShape
121 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
128 122
129 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); 123 SetPhysicalProperties();
130 // avatars get all collisions no matter what
131 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
132 }); 124 });
133
134 return; 125 return;
135 } 126 }
136 127
137 // called when this character is being destroyed and the resources should be released 128 // called when this character is being destroyed and the resources should be released
138 public void Destroy() 129 public override void Destroy()
139 { 130 {
140 // DetailLog("{0},BSCharacter.Destroy", LocalID); 131 DetailLog("{0},BSCharacter.Destroy", LocalID);
141 _scene.TaintedObject("BSCharacter.destroy", delegate() 132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
142 { 133 {
143 BulletSimAPI.DestroyObject(_scene.WorldID, _localID); 134 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
135 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
144 }); 136 });
145 } 137 }
146 138
139 private void SetPhysicalProperties()
140 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
142
143 ZeroMotion();
144 ForcePosition = _position;
145 // Set the velocity and compute the proper friction
146 ForceVelocity = _velocity;
147
148 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
149 BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
150 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
151 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
152 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
153 {
154 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
155 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
156 }
157
158 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
159 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
160
161 // Make so capsule does not fall over
162 BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero);
163
164 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
165
166 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
167
168 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
169 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION);
170 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
171
172 // Do this after the object has been added to the world
173 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
174 (uint)CollisionFilterGroups.AvatarFilter,
175 (uint)CollisionFilterGroups.AvatarMask);
176 }
177
147 public override void RequestPhysicsterseUpdate() 178 public override void RequestPhysicsterseUpdate()
148 { 179 {
149 base.RequestPhysicsterseUpdate(); 180 base.RequestPhysicsterseUpdate();
150 } 181 }
151 // No one calls this method so I don't know what it could possibly mean 182 // No one calls this method so I don't know what it could possibly mean
152 public override bool Stopped { 183 public override bool Stopped { get { return false; } }
153 get { return false; } 184
154 } 185 public override OMV.Vector3 Size {
155 public override Vector3 Size {
156 get 186 get
157 { 187 {
158 // Avatar capsule size is kept in the scale parameter. 188 // Avatar capsule size is kept in the scale parameter.
159 return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 189 // return _size;
190 return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z);
160 } 191 }
161 192
162 set { 193 set {
163 // When an avatar's size is set, only the height is changed 194 // When an avatar's size is set, only the height is changed.
164 // and that really only depends on the radius.
165 _size = value; 195 _size = value;
166 _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 196 ComputeAvatarScale(_size);
167
168 // TODO: something has to be done with the avatar's vertical position
169
170 ComputeAvatarVolumeAndMass(); 197 ComputeAvatarVolumeAndMass();
198 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
199 LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
171 200
172 _scene.TaintedObject("BSCharacter.setSize", delegate() 201 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
173 { 202 {
174 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); 203 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
204 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
205 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
175 }); 206 });
176 207
177 }
178 }
179 public override PrimitiveBaseShape Shape {
180 set { _pbs = value;
181 }
182 }
183 public override uint LocalID {
184 set { _localID = value;
185 } 208 }
186 get { return _localID; }
187 } 209 }
188 public override bool Grabbed { 210
189 set { _grabbed = value; 211 public override OMV.Vector3 Scale { get; set; }
190 } 212
213 public override PrimitiveBaseShape Shape
214 {
215 set { BaseShape = value; }
216 }
217
218 public override bool Grabbed {
219 set { _grabbed = value; }
191 } 220 }
192 public override bool Selected { 221 public override bool Selected {
193 set { _selected = value; 222 set { _selected = value; }
194 }
195 } 223 }
196 public override void CrossingFailure() { return; } 224 public override void CrossingFailure() { return; }
197 public override void link(PhysicsActor obj) { return; } 225 public override void link(PhysicsActor obj) { return; }
198 public override void delink() { return; } 226 public override void delink() { return; }
199 public override void LockAngularMotion(Vector3 axis) { return; }
200 227
201 public override Vector3 Position { 228 // Set motion values to zero.
229 // Do it to the properties so the values get set in the physics engine.
230 // Push the setting of the values to the viewer.
231 // Called at taint time!
232 public override void ZeroMotion()
233 {
234 _velocity = OMV.Vector3.Zero;
235 _acceleration = OMV.Vector3.Zero;
236 _rotationalVelocity = OMV.Vector3.Zero;
237
238 // Zero some other properties directly into the physics engine
239 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
240 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
241 BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
242 BulletSimAPI.ClearForces2(BSBody.ptr);
243 }
244
245 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
246
247 public override OMV.Vector3 Position {
202 get { 248 get {
203 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 249 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
204 return _position; 250 return _position;
205 } 251 }
206 set { 252 set {
207 _position = value; 253 _position = value;
208 PositionSanityCheck(); 254 PositionSanityCheck();
209 255
210 _scene.TaintedObject("BSCharacter.setPosition", delegate() 256 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
211 { 257 {
212 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 258 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
213 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 259 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
214 }); 260 });
215 } 261 }
262 }
263 public override OMV.Vector3 ForcePosition {
264 get {
265 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
266 return _position;
267 }
268 set {
269 _position = value;
270 PositionSanityCheck();
271 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
272 }
216 } 273 }
217 274
275
218 // Check that the current position is sane and, if not, modify the position to make it so. 276 // Check that the current position is sane and, if not, modify the position to make it so.
219 // Check for being below terrain and being out of bounds. 277 // Check for being below terrain or on water.
220 // Returns 'true' of the position was made sane by some action. 278 // Returns 'true' of the position was made sane by some action.
221 private bool PositionSanityCheck() 279 private bool PositionSanityCheck()
222 { 280 {
223 bool ret = false; 281 bool ret = false;
224 282
225 // If below the ground, move the avatar up 283 // If below the ground, move the avatar up
226 float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); 284 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
227 if (_position.Z < terrainHeight) 285 if (Position.Z < terrainHeight)
228 { 286 {
229 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); 287 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
230 _position.Z = terrainHeight + 2.0f; 288 _position.Z = terrainHeight + 2.0f;
231 ret = true; 289 ret = true;
232 } 290 }
291 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
292 {
293 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
294 if (Position.Z < waterHeight)
295 {
296 _position.Z = waterHeight;
297 ret = true;
298 }
299 }
233 300
234 // TODO: check for out of bounds 301 // TODO: check for out of bounds
235
236 return ret; 302 return ret;
237 } 303 }
238 304
239 public override float Mass { 305 // A version of the sanity check that also makes sure a new position value is
240 get { 306 // pushed back to the physics engine. This routine would be used by anyone
241 return _mass; 307 // who is not already pushing the value.
242 } 308 private bool PositionSanityCheck(bool inTaintTime)
309 {
310 bool ret = false;
311 if (PositionSanityCheck())
312 {
313 // The new position value must be pushed into the physics engine but we can't
314 // just assign to "Position" because of potential call loops.
315 BSScene.TaintCallback sanityOperation = delegate()
316 {
317 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
318 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
319 };
320 if (inTaintTime)
321 sanityOperation();
322 else
323 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
324 ret = true;
325 }
326 return ret;
243 } 327 }
244 public override Vector3 Force { 328
245 get { return _force; } 329 public override float Mass { get { return _mass; } }
330
331 // used when we only want this prim's mass and not the linkset thing
332 public override float MassRaw { get {return _mass; } }
333
334 public override OMV.Vector3 Force {
335 get { return _force; }
246 set { 336 set {
247 _force = value; 337 _force = value;
248 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 338 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
249 Scene.TaintedObject("BSCharacter.SetForce", delegate() 339 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
250 { 340 {
251 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 341 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
252 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); 342 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
253 }); 343 });
254 } 344 }
255 } 345 }
256 346
257 public override int VehicleType { 347 // Avatars don't do vehicles
258 get { return 0; } 348 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
259 set { return; }
260 }
261 public override void VehicleFloatParam(int param, float value) { } 349 public override void VehicleFloatParam(int param, float value) { }
262 public override void VehicleVectorParam(int param, Vector3 value) {} 350 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
263 public override void VehicleRotationParam(int param, Quaternion rotation) { } 351 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
264 public override void VehicleFlags(int param, bool remove) { } 352 public override void VehicleFlags(int param, bool remove) { }
265 353
266 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 354 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
267 public override void SetVolumeDetect(int param) { return; } 355 public override void SetVolumeDetect(int param) { return; }
268 356
269 public override Vector3 GeometricCenter { get { return Vector3.Zero; } } 357 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
270 public override Vector3 CenterOfMass { get { return Vector3.Zero; } } 358 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
271 public override Vector3 Velocity { 359 public override OMV.Vector3 Velocity {
272 get { return _velocity; } 360 get { return _velocity; }
273 set { 361 set {
274 _velocity = value; 362 _velocity = value;
275 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 363 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
276 _scene.TaintedObject("BSCharacter.setVelocity", delegate() 364 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
277 { 365 {
278 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 366 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
279 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); 367 ForceVelocity = _velocity;
280 }); 368 });
281 } 369 }
282 } 370 }
283 public override Vector3 Torque { 371 public override OMV.Vector3 ForceVelocity {
284 get { return _torque; } 372 get { return _velocity; }
285 set { _torque = value; 373 set {
286 } 374 // Depending on whether the avatar is moving or not, change the friction
375 // to keep the avatar from slipping around
376 if (_velocity.Length() == 0)
377 {
378 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
379 {
380 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
381 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
382 }
383 }
384 else
385 {
386 if (_currentFriction != PhysicsScene.Params.avatarFriction)
387 {
388 _currentFriction = PhysicsScene.Params.avatarFriction;
389 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
390 }
391 }
392 _velocity = value;
393 // Remember the set velocity so we can suppress the reduction by friction, ...
394 _appliedVelocity = value;
395
396 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
397 BulletSimAPI.Activate2(BSBody.ptr, true);
398 }
287 } 399 }
288 public override float CollisionScore { 400 public override OMV.Vector3 Torque {
289 get { return _collisionScore; } 401 get { return _torque; }
290 set { _collisionScore = value; 402 set { _torque = value;
291 } 403 }
404 }
405 public override float CollisionScore {
406 get { return _collisionScore; }
407 set { _collisionScore = value;
408 }
292 } 409 }
293 public override Vector3 Acceleration { 410 public override OMV.Vector3 Acceleration {
294 get { return _acceleration; } 411 get { return _acceleration; }
295 set { _acceleration = value; } 412 set { _acceleration = value; }
296 } 413 }
297 public override Quaternion Orientation { 414 public override OMV.Quaternion Orientation {
298 get { return _orientation; } 415 get { return _orientation; }
299 set { 416 set {
300 _orientation = value; 417 _orientation = value;
301 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 418 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
302 _scene.TaintedObject("BSCharacter.setOrientation", delegate() 419 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
303 { 420 {
304 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 421 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
305 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 422 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
306 }); 423 });
307 } 424 }
425 }
426 // Go directly to Bullet to get/set the value.
427 public override OMV.Quaternion ForceOrientation
428 {
429 get
430 {
431 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
432 return _orientation;
433 }
434 set
435 {
436 _orientation = value;
437 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
438 }
308 } 439 }
309 public override int PhysicsActorType { 440 public override int PhysicsActorType {
310 get { return _physicsActorType; } 441 get { return _physicsActorType; }
311 set { _physicsActorType = value; 442 set { _physicsActorType = value;
312 } 443 }
313 } 444 }
314 public override bool IsPhysical { 445 public override bool IsPhysical {
315 get { return _isPhysical; } 446 get { return _isPhysical; }
316 set { _isPhysical = value; 447 set { _isPhysical = value;
317 } 448 }
449 }
450 public override bool IsSolid {
451 get { return true; }
318 } 452 }
319 public override bool Flying { 453 public override bool IsStatic {
320 get { return _flying; } 454 get { return false; }
455 }
456 public override bool Flying {
457 get { return _flying; }
321 set { 458 set {
322 if (_flying != value) 459 _flying = value;
323 { 460 // simulate flying by changing the effect of gravity
324 _flying = value; 461 Buoyancy = ComputeBuoyancyFromFlying(_flying);
325 // simulate flying by changing the effect of gravity 462 }
326 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
327 }
328 }
329 } 463 }
464 // Flying is implimented by changing the avatar's buoyancy.
465 // Would this be done better with a vehicle type?
330 private float ComputeBuoyancyFromFlying(bool ifFlying) { 466 private float ComputeBuoyancyFromFlying(bool ifFlying) {
331 return ifFlying ? 1f : 0f; 467 return ifFlying ? 1f : 0f;
332 } 468 }
333 public override bool 469 public override bool
334 SetAlwaysRun { 470 SetAlwaysRun {
335 get { return _setAlwaysRun; } 471 get { return _setAlwaysRun; }
336 set { _setAlwaysRun = value; } 472 set { _setAlwaysRun = value; }
337 } 473 }
338 public override bool ThrottleUpdates { 474 public override bool ThrottleUpdates {
339 get { return _throttleUpdates; } 475 get { return _throttleUpdates; }
340 set { _throttleUpdates = value; } 476 set { _throttleUpdates = value; }
341 } 477 }
342 public override bool IsColliding { 478 public override bool IsColliding {
343 get { return (_collidingStep == _scene.SimulationStep); } 479 get { return (CollidingStep == PhysicsScene.SimulationStep); }
344 set { _isColliding = value; } 480 set { _isColliding = value; }
345 } 481 }
346 public override bool CollidingGround { 482 public override bool CollidingGround {
347 get { return (_collidingGroundStep == _scene.SimulationStep); } 483 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
348 set { _collidingGround = value; } 484 set { CollidingGround = value; }
349 } 485 }
350 public override bool CollidingObj { 486 public override bool CollidingObj {
351 get { return _collidingObj; } 487 get { return _collidingObj; }
352 set { _collidingObj = value; } 488 set { _collidingObj = value; }
353 } 489 }
354 public override bool FloatOnWater { 490 public override bool FloatOnWater {
355 set { _floatOnWater = value; } 491 set {
492 _floatOnWater = value;
493 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
494 {
495 if (_floatOnWater)
496 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
497 else
498 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
499 });
500 }
501 }
502 public override OMV.Vector3 RotationalVelocity {
503 get { return _rotationalVelocity; }
504 set { _rotationalVelocity = value; }
356 } 505 }
357 public override Vector3 RotationalVelocity { 506 public override OMV.Vector3 ForceRotationalVelocity {
358 get { return _rotationalVelocity; } 507 get { return _rotationalVelocity; }
359 set { _rotationalVelocity = value; } 508 set { _rotationalVelocity = value; }
360 } 509 }
361 public override bool Kinematic { 510 public override bool Kinematic {
362 get { return _kinematic; } 511 get { return _kinematic; }
363 set { _kinematic = value; } 512 set { _kinematic = value; }
364 } 513 }
365 // neg=fall quickly, 0=1g, 1=0g, pos=float up 514 // neg=fall quickly, 0=1g, 1=0g, pos=float up
366 public override float Buoyancy { 515 public override float Buoyancy {
367 get { return _buoyancy; } 516 get { return _buoyancy; }
368 set { _buoyancy = value; 517 set { _buoyancy = value;
369 _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() 518 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
370 { 519 {
371 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 520 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
372 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); 521 ForceBuoyancy = _buoyancy;
373 }); 522 });
374 } 523 }
524 }
525 public override float ForceBuoyancy {
526 get { return _buoyancy; }
527 set { _buoyancy = value;
528 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
529 // Buoyancy is faked by changing the gravity applied to the object
530 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
531 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
532 }
375 } 533 }
376 534
377 // Used for MoveTo 535 // Used for MoveTo
378 public override Vector3 PIDTarget { 536 public override OMV.Vector3 PIDTarget {
379 set { _PIDTarget = value; } 537 set { _PIDTarget = value; }
380 } 538 }
381 public override bool PIDActive { 539 public override bool PIDActive {
382 set { _usePID = value; } 540 set { _usePID = value; }
383 } 541 }
384 public override float PIDTau { 542 public override float PIDTau {
385 set { _PIDTau = value; } 543 set { _PIDTau = value; }
386 } 544 }
387 545
388 // Used for llSetHoverHeight and maybe vehicle height 546 // Used for llSetHoverHeight and maybe vehicle height
389 // Hover Height will override MoveTo target's Z 547 // Hover Height will override MoveTo target's Z
390 public override bool PIDHoverActive { 548 public override bool PIDHoverActive {
391 set { _useHoverPID = value; } 549 set { _useHoverPID = value; }
392 } 550 }
393 public override float PIDHoverHeight { 551 public override float PIDHoverHeight {
394 set { _PIDHoverHeight = value; } 552 set { _PIDHoverHeight = value; }
395 } 553 }
396 public override PIDHoverType PIDHoverType { 554 public override PIDHoverType PIDHoverType {
397 set { _PIDHoverType = value; } 555 set { _PIDHoverType = value; }
398 } 556 }
399 public override float PIDHoverTau { 557 public override float PIDHoverTau {
400 set { _PIDHoverTao = value; } 558 set { _PIDHoverTao = value; }
401 } 559 }
402 560
403 // For RotLookAt 561 // For RotLookAt
404 public override Quaternion APIDTarget { set { return; } } 562 public override OMV.Quaternion APIDTarget { set { return; } }
405 public override bool APIDActive { set { return; } } 563 public override bool APIDActive { set { return; } }
406 public override float APIDStrength { set { return; } } 564 public override float APIDStrength { set { return; } }
407 public override float APIDDamping { set { return; } } 565 public override float APIDDamping { set { return; } }
408 566
409 public override void AddForce(Vector3 force, bool pushforce) { 567 public override void AddForce(OMV.Vector3 force, bool pushforce) {
410 if (force.IsFinite()) 568 if (force.IsFinite())
411 { 569 {
412 _force.X += force.X; 570 _force.X += force.X;
413 _force.Y += force.Y; 571 _force.Y += force.Y;
414 _force.Z += force.Z; 572 _force.Z += force.Z;
415 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 573 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
416 _scene.TaintedObject("BSCharacter.AddForce", delegate() 574 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
417 { 575 {
418 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 576 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
419 BulletSimAPI.AddObjectForce2(Body.Ptr, _force); 577 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
420 }); 578 });
421 } 579 }
422 else 580 else
@@ -426,129 +584,75 @@ public class BSCharacter : PhysicsActor
426 //m_lastUpdateSent = false; 584 //m_lastUpdateSent = false;
427 } 585 }
428 586
429 public override void AddAngularForce(Vector3 force, bool pushforce) { 587 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
430 } 588 }
431 public override void SetMomentum(Vector3 momentum) { 589 public override void SetMomentum(OMV.Vector3 momentum) {
432 } 590 }
433 591
434 // Turn on collision events at a rate no faster than one every the given milliseconds 592 private void ComputeAvatarScale(OMV.Vector3 size)
435 public override void SubscribeEvents(int ms) { 593 {
436 _subscribedEventsMs = ms; 594 // The 'size' given by the simulator is the mid-point of the avatar
437 if (ms > 0) 595 // and X and Y are unspecified.
438 {
439 // make sure first collision happens
440 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
441 596
442 Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() 597 OMV.Vector3 newScale = OMV.Vector3.Zero;
443 { 598 newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
444 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 599 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
445 }); 600
446 } 601 // From the total height, remove the capsule half spheres that are at each end
447 } 602 newScale.Z = size.Z- (newScale.X + newScale.Y);
448 // Stop collision events 603 Scale = newScale;
449 public override void UnSubscribeEvents() {
450 _subscribedEventsMs = 0;
451 // Avatars get all their collision events
452 // Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
453 // {
454 // BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
455 // });
456 }
457 // Return 'true' if someone has subscribed to events
458 public override bool SubscribedEvents() {
459 return (_subscribedEventsMs > 0);
460 } 604 }
461 605
462 // set _avatarVolume and _mass based on capsule size, _density and _scale 606 // set _avatarVolume and _mass based on capsule size, _density and Scale
463 private void ComputeAvatarVolumeAndMass() 607 private void ComputeAvatarVolumeAndMass()
464 { 608 {
465 _avatarVolume = (float)( 609 _avatarVolume = (float)(
466 Math.PI 610 Math.PI
467 * _scale.X 611 * Scale.X
468 * _scale.Y // the area of capsule cylinder 612 * Scale.Y // the area of capsule cylinder
469 * _scale.Z // times height of capsule cylinder 613 * Scale.Z // times height of capsule cylinder
470 + 1.33333333f 614 + 1.33333333f
471 * Math.PI 615 * Math.PI
472 * _scale.X 616 * Scale.X
473 * Math.Min(_scale.X, _scale.Y) 617 * Math.Min(Scale.X, Scale.Y)
474 * _scale.Y // plus the volume of the capsule end caps 618 * Scale.Y // plus the volume of the capsule end caps
475 ); 619 );
476 _mass = _density * _avatarVolume; 620 _mass = _avatarDensity * _avatarVolume;
477 } 621 }
478 622
479 // The physics engine says that properties have updated. Update same and inform 623 // The physics engine says that properties have updated. Update same and inform
480 // the world that things have changed. 624 // the world that things have changed.
481 public void UpdateProperties(EntityProperties entprop) 625 public override void UpdateProperties(EntityProperties entprop)
482 { 626 {
483 _position = entprop.Position; 627 _position = entprop.Position;
484 _orientation = entprop.Rotation; 628 _orientation = entprop.Rotation;
485 _velocity = entprop.Velocity; 629 _velocity = entprop.Velocity;
486 _acceleration = entprop.Acceleration; 630 _acceleration = entprop.Acceleration;
487 _rotationalVelocity = entprop.RotationalVelocity; 631 _rotationalVelocity = entprop.RotationalVelocity;
488 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 632 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
489 // base.RequestPhysicsterseUpdate(); 633 PositionSanityCheck(true);
490 634
491 /* 635 // remember the current and last set values
492 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 636 LastEntityProperties = CurrentEntityProperties;
493 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 637 CurrentEntityProperties = entprop;
494 entprop.Acceleration, entprop.RotationalVelocity);
495 */
496 }
497
498 // Called by the scene when a collision with this object is reported
499 // The collision, if it should be reported to the character, is placed in a collection
500 // that will later be sent to the simulator when SendCollisions() is called.
501 CollisionEventUpdate collisionCollection = null;
502 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
503 {
504 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
505 638
506 // The following makes IsColliding() and IsCollidingGround() work 639 if (entprop.Velocity != LastEntityProperties.Velocity)
507 _collidingStep = _scene.SimulationStep;
508 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
509 { 640 {
510 _collidingGroundStep = _scene.SimulationStep; 641 // Changes in the velocity are suppressed in avatars.
642 // That's just the way they are defined.
643 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
644 _velocity = avVel;
645 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
511 } 646 }
512 // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
513 647
514 // throttle collisions to the rate specified in the subscription 648 // Tell the linkset about value changes
515 if (_subscribedEventsMs != 0) { 649 Linkset.UpdateProperties(this);
516 int nowTime = _scene.SimulationNowTime;
517 if (nowTime >= _nextCollisionOkTime) {
518 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
519 650
520 if (collisionCollection == null) 651 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
521 collisionCollection = new CollisionEventUpdate(); 652 // base.RequestPhysicsterseUpdate();
522 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
523 }
524 }
525 }
526 653
527 public void SendCollisions() 654 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
528 { 655 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
529 /*
530 if (collisionCollection != null && collisionCollection.Count > 0)
531 {
532 base.SendCollisionUpdate(collisionCollection);
533 collisionCollection = null;
534 }
535 */
536 // Kludge to make a collision call even if there are no collisions.
537 // This causes the avatar animation to get updated.
538 if (collisionCollection == null)
539 collisionCollection = new CollisionEventUpdate();
540 base.SendCollisionUpdate(collisionCollection);
541 // If there were any collisions in the collection, make sure we don't use the
542 // same instance next time.
543 if (collisionCollection.Count > 0)
544 collisionCollection = null;
545 // End kludge
546 }
547
548 // Invoke the detailed logger and output something if it's enabled.
549 private void DetailLog(string msg, params Object[] args)
550 {
551 Scene.PhysicsLogging.Write(msg, args);
552 } 656 }
553} 657}
554} 658}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 25084d8..f017cdd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
37 protected BulletSim m_world; 39 protected BulletSim m_world;
38 protected BulletBody m_body1; 40 protected BulletBody m_body1;
39 protected BulletBody m_body2; 41 protected BulletBody m_body2;
@@ -48,22 +50,31 @@ public abstract class BSConstraint : IDisposable
48 { 50 {
49 if (m_enabled) 51 if (m_enabled)
50 { 52 {
51 // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
53 m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
54 m_constraint.Ptr = System.IntPtr.Zero;
55 m_enabled = false; 53 m_enabled = false;
54 if (m_constraint.ptr != IntPtr.Zero)
55 {
56 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
57 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
58 BSScene.DetailLogZero,
59 m_body1.ID, m_body1.ptr.ToString("X"),
60 m_body2.ID, m_body2.ptr.ToString("X"),
61 success);
62 m_constraint.ptr = System.IntPtr.Zero;
63 }
56 } 64 }
57 } 65 }
58 66
59 public BulletBody Body1 { get { return m_body1; } } 67 public BulletBody Body1 { get { return m_body1; } }
60 public BulletBody Body2 { get { return m_body2; } } 68 public BulletBody Body2 { get { return m_body2; } }
69 public BulletConstraint Constraint { get { return m_constraint; } }
70 public abstract ConstraintType Type { get; }
71
61 72
62 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
63 { 74 {
64 bool ret = false; 75 bool ret = false;
65 if (m_enabled) 76 if (m_enabled)
66 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); 77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
67 return ret; 78 return ret;
68 } 79 }
69 80
@@ -71,7 +82,18 @@ public abstract class BSConstraint : IDisposable
71 { 82 {
72 bool ret = false; 83 bool ret = false;
73 if (m_enabled) 84 if (m_enabled)
74 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); 85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
86 return ret;
87 }
88
89 public virtual bool SetSolverIterations(float cnt)
90 {
91 bool ret = false;
92 if (m_enabled)
93 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
95 ret = true;
96 }
75 return ret; 97 return ret;
76 } 98 }
77 99
@@ -81,7 +103,7 @@ public abstract class BSConstraint : IDisposable
81 if (m_enabled) 103 if (m_enabled)
82 { 104 {
83 // Recompute the internal transforms 105 // Recompute the internal transforms
84 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); 106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
85 ret = true; 107 ret = true;
86 } 108 }
87 return ret; 109 return ret;
@@ -97,13 +119,14 @@ public abstract class BSConstraint : IDisposable
97 ret = CalculateTransforms(); 119 ret = CalculateTransforms();
98 if (ret) 120 if (ret)
99 { 121 {
100 // m_world.scene.PhysicsLogging.Write("{0},BSConstraint.RecomputeConstraintVariables,taint,enabling,A={1},B={2}", 122 // Setting an object's mass to zero (making it static like when it's selected)
101 // BSScene.DetailLogZero, Body1.ID, Body2.ID); 123 // automatically disables the constraints.
102 BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); 124 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
103 } 126 }
104 else 127 else
105 { 128 {
106 m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
107 } 130 }
108 } 131 }
109 return ret; 132 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5a9f135..117c878 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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 27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system. 29 * call the BulletSim system.
@@ -54,17 +54,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public class BSDynamics
56 { 56 {
57 private int frcount = 0; // Used to limit dynamics debug output to 57 private BSScene PhysicsScene { get; set; }
58 // every 100th frame 58 // the prim this dynamic controller belongs to
59 59 private BSPrim Prim { get; set; }
60 private BSPrim m_prim; // the prim this dynamic controller belongs to
61 60
62 // Vehicle properties 61 // Vehicle properties
63 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind 62 public Vehicle Type { get; set; }
64 public Vehicle Type 63
65 {
66 get { return m_type; }
67 }
68 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier 64 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
69 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: 65 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
70 // HOVER_TERRAIN_ONLY 66 // HOVER_TERRAIN_ONLY
@@ -74,13 +70,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
74 // HOVER_UP_ONLY 70 // HOVER_UP_ONLY
75 // LIMIT_MOTOR_UP 71 // LIMIT_MOTOR_UP
76 // LIMIT_ROLL_ONLY 72 // LIMIT_ROLL_ONLY
77 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
78 private Vector3 m_BlockingEndPoint = Vector3.Zero; 73 private Vector3 m_BlockingEndPoint = Vector3.Zero;
79 private Quaternion m_RollreferenceFrame = Quaternion.Identity; 74 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
80 // Linear properties 75 // Linear properties
81 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 76 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
82 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
83 private Vector3 m_dir = Vector3.Zero; // velocity applied to body 78 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
84 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 79 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
85 private float m_linearMotorDecayTimescale = 0; 80 private float m_linearMotorDecayTimescale = 0;
86 private float m_linearMotorTimescale = 0; 81 private float m_linearMotorTimescale = 0;
@@ -97,7 +92,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
97 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 92 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
98 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 93 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
99 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 94 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
100 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
101 96
102 //Deflection properties 97 //Deflection properties
103 // private float m_angularDeflectionEfficiency = 0; 98 // private float m_angularDeflectionEfficiency = 0;
@@ -124,86 +119,74 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 private float m_verticalAttractionEfficiency = 1.0f; // damped 119 private float m_verticalAttractionEfficiency = 1.0f; // damped
125 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 120 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
126 121
127 public BSDynamics(BSPrim myPrim) 122 public BSDynamics(BSScene myScene, BSPrim myPrim)
128 { 123 {
129 m_prim = myPrim; 124 PhysicsScene = myScene;
130 m_type = Vehicle.TYPE_NONE; 125 Prim = myPrim;
126 Type = Vehicle.TYPE_NONE;
131 } 127 }
132 128
133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep) 129 // Return 'true' if this vehicle is doing vehicle things
130 public bool IsActive
134 { 131 {
135 DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 132 get { return Type != Vehicle.TYPE_NONE; }
133 }
134
135 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
136 {
137 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
136 switch (pParam) 138 switch (pParam)
137 { 139 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 140 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
139 if (pValue < 0.01f) pValue = 0.01f; 141 // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
140 // m_angularDeflectionEfficiency = pValue;
141 break; 142 break;
142 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
143 if (pValue < 0.01f) pValue = 0.01f; 144 // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
144 // m_angularDeflectionTimescale = pValue;
145 break; 145 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 if (pValue < 0.01f) pValue = 0.01f; 147 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
148 m_angularMotorDecayTimescale = pValue;
149 break; 148 break;
150 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 149 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
151 if (pValue < 0.01f) pValue = 0.01f; 150 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
152 m_angularMotorTimescale = pValue;
153 break; 151 break;
154 case Vehicle.BANKING_EFFICIENCY: 152 case Vehicle.BANKING_EFFICIENCY:
155 if (pValue < 0.01f) pValue = 0.01f; 153 // m_bankingEfficiency = Math.Max(pValue, 0.01f);
156 // m_bankingEfficiency = pValue;
157 break; 154 break;
158 case Vehicle.BANKING_MIX: 155 case Vehicle.BANKING_MIX:
159 if (pValue < 0.01f) pValue = 0.01f; 156 // m_bankingMix = Math.Max(pValue, 0.01f);
160 // m_bankingMix = pValue;
161 break; 157 break;
162 case Vehicle.BANKING_TIMESCALE: 158 case Vehicle.BANKING_TIMESCALE:
163 if (pValue < 0.01f) pValue = 0.01f; 159 // m_bankingTimescale = Math.Max(pValue, 0.01f);
164 // m_bankingTimescale = pValue;
165 break; 160 break;
166 case Vehicle.BUOYANCY: 161 case Vehicle.BUOYANCY:
167 if (pValue < -1f) pValue = -1f; 162 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f));
168 if (pValue > 1f) pValue = 1f;
169 m_VehicleBuoyancy = pValue;
170 break; 163 break;
171// case Vehicle.HOVER_EFFICIENCY: 164// case Vehicle.HOVER_EFFICIENCY:
172// if (pValue < 0f) pValue = 0f; 165// m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f));
173// if (pValue > 1f) pValue = 1f;
174// m_VhoverEfficiency = pValue;
175// break; 166// break;
176 case Vehicle.HOVER_HEIGHT: 167 case Vehicle.HOVER_HEIGHT:
177 m_VhoverHeight = pValue; 168 m_VhoverHeight = pValue;
178 break; 169 break;
179 case Vehicle.HOVER_TIMESCALE: 170 case Vehicle.HOVER_TIMESCALE:
180 if (pValue < 0.01f) pValue = 0.01f; 171 m_VhoverTimescale = Math.Max(pValue, 0.01f);
181 m_VhoverTimescale = pValue;
182 break; 172 break;
183 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 173 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
184 if (pValue < 0.01f) pValue = 0.01f; 174 // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
185 // m_linearDeflectionEfficiency = pValue;
186 break; 175 break;
187 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 176 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
188 if (pValue < 0.01f) pValue = 0.01f; 177 // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
189 // m_linearDeflectionTimescale = pValue;
190 break; 178 break;
191 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 179 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
192 if (pValue < 0.01f) pValue = 0.01f; 180 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
193 m_linearMotorDecayTimescale = pValue;
194 break; 181 break;
195 case Vehicle.LINEAR_MOTOR_TIMESCALE: 182 case Vehicle.LINEAR_MOTOR_TIMESCALE:
196 if (pValue < 0.01f) pValue = 0.01f; 183 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
197 m_linearMotorTimescale = pValue;
198 break; 184 break;
199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 185 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
200 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable 186 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
201 if (pValue > 1.0f) pValue = 1.0f;
202 m_verticalAttractionEfficiency = pValue;
203 break; 187 break;
204 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 188 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
205 if (pValue < 0.01f) pValue = 0.01f; 189 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
206 m_verticalAttractionTimescale = pValue;
207 break; 190 break;
208 191
209 // These are vector properties but the engine lets you use a single float value to 192 // These are vector properties but the engine lets you use a single float value to
@@ -229,9 +212,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
229 } 212 }
230 }//end ProcessFloatVehicleParam 213 }//end ProcessFloatVehicleParam
231 214
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep) 215 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
233 { 216 {
234 DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 217 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
235 switch (pParam) 218 switch (pParam)
236 { 219 {
237 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 220 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@@ -266,7 +249,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
266 249
267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 250 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
268 { 251 {
269 DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 252 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
270 switch (pParam) 253 switch (pParam)
271 { 254 {
272 case Vehicle.REFERENCE_FRAME: 255 case Vehicle.REFERENCE_FRAME:
@@ -280,166 +263,29 @@ namespace OpenSim.Region.Physics.BulletSPlugin
280 263
281 internal void ProcessVehicleFlags(int pParam, bool remove) 264 internal void ProcessVehicleFlags(int pParam, bool remove)
282 { 265 {
283 DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); 266 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
267 VehicleFlag parm = (VehicleFlag)pParam;
284 if (remove) 268 if (remove)
285 { 269 {
286 if (pParam == -1) 270 if (pParam == -1)
287 { 271 {
288 m_flags = (VehicleFlag)0; 272 m_flags = (VehicleFlag)0;
289 m_Hoverflags = (VehicleFlag)0;
290 return;
291 }
292 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
293 {
294 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
295 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
296 }
297 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
298 {
299 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
300 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
301 }
302 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
303 {
304 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
305 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
306 }
307 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
308 {
309 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
310 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
311 }
312 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
313 {
314 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
315 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
316 }
317 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
318 {
319 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
320 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
321 } 273 }
322 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) 274 else
323 {
324 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
325 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
326 }
327 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
328 {
329 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
330 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
331 }
332 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
333 {
334 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
335 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
336 }
337 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
338 {
339 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
340 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
341 }
342 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
343 {
344 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
345 m_flags &= ~(VehicleFlag.NO_X);
346 }
347 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
348 {
349 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
350 m_flags &= ~(VehicleFlag.NO_Y);
351 }
352 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
353 {
354 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
355 m_flags &= ~(VehicleFlag.NO_Z);
356 }
357 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
358 {
359 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
360 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
361 }
362 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
363 {
364 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
365 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
366 }
367 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
368 { 275 {
369 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) 276 m_flags &= ~parm;
370 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
371 } 277 }
372 } 278 }
373 else 279 else {
374 { 280 m_flags |= parm;
375 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
376 {
377 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
378 }
379 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
380 {
381 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
382 }
383 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
384 {
385 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
386 }
387 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
388 {
389 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
390 }
391 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
392 {
393 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
394 }
395 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
396 {
397 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
398 }
399 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
400 {
401 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
402 }
403 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
404 {
405 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
406 }
407 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
408 {
409 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
410 }
411 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
412 {
413 m_flags |= (VehicleFlag.NO_X);
414 }
415 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
416 {
417 m_flags |= (VehicleFlag.NO_Y);
418 }
419 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
420 {
421 m_flags |= (VehicleFlag.NO_Z);
422 }
423 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
424 {
425 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
426 }
427 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
428 {
429 m_flags |= (VehicleFlag.NO_DEFLECTION);
430 }
431 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
432 {
433 m_flags |= (VehicleFlag.LOCK_ROTATION);
434 }
435 } 281 }
436 }//end ProcessVehicleFlags 282 }//end ProcessVehicleFlags
437 283
438 internal void ProcessTypeChange(Vehicle pType) 284 internal void ProcessTypeChange(Vehicle pType)
439 { 285 {
440 DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); 286 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
441 // Set Defaults For Type 287 // Set Defaults For Type
442 m_type = pType; 288 Type = pType;
443 switch (pType) 289 switch (pType)
444 { 290 {
445 case Vehicle.TYPE_NONE: 291 case Vehicle.TYPE_NONE:
@@ -478,10 +324,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
478 // m_bankingMix = 1; 324 // m_bankingMix = 1;
479 // m_bankingTimescale = 10; 325 // m_bankingTimescale = 10;
480 // m_referenceFrame = Quaternion.Identity; 326 // m_referenceFrame = Quaternion.Identity;
481 m_Hoverflags &= 327 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
328 m_flags &=
482 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 329 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
483 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 330 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
484 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
485 break; 331 break;
486 case Vehicle.TYPE_CAR: 332 case Vehicle.TYPE_CAR:
487 m_linearFrictionTimescale = new Vector3(100, 2, 1000); 333 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
@@ -506,10 +352,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
506 // m_bankingMix = 1; 352 // m_bankingMix = 1;
507 // m_bankingTimescale = 1; 353 // m_bankingTimescale = 1;
508 // m_referenceFrame = Quaternion.Identity; 354 // m_referenceFrame = Quaternion.Identity;
509 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
510 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | 356 | VehicleFlag.LIMIT_ROLL_ONLY
511 VehicleFlag.LIMIT_MOTOR_UP); 357 | VehicleFlag.LIMIT_MOTOR_UP);
512 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); 358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
359 m_flags |= (VehicleFlag.HOVER_UP_ONLY);
513 break; 360 break;
514 case Vehicle.TYPE_BOAT: 361 case Vehicle.TYPE_BOAT:
515 m_linearFrictionTimescale = new Vector3(10, 3, 2); 362 m_linearFrictionTimescale = new Vector3(10, 3, 2);
@@ -534,12 +381,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
534 // m_bankingMix = 0.8f; 381 // m_bankingMix = 0.8f;
535 // m_bankingTimescale = 1; 382 // m_bankingTimescale = 1;
536 // m_referenceFrame = Quaternion.Identity; 383 // m_referenceFrame = Quaternion.Identity;
537 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
538 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 385 | VehicleFlag.HOVER_GLOBAL_HEIGHT
539 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); 386 | VehicleFlag.LIMIT_ROLL_ONLY
540 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 387 | VehicleFlag.HOVER_UP_ONLY);
541 VehicleFlag.LIMIT_MOTOR_UP); 388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
542 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); 389 | VehicleFlag.LIMIT_MOTOR_UP
390 | VehicleFlag.HOVER_WATER_ONLY);
543 break; 391 break;
544 case Vehicle.TYPE_AIRPLANE: 392 case Vehicle.TYPE_AIRPLANE:
545 m_linearFrictionTimescale = new Vector3(200, 10, 5); 393 m_linearFrictionTimescale = new Vector3(200, 10, 5);
@@ -564,9 +412,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
564 // m_bankingMix = 0.7f; 412 // m_bankingMix = 0.7f;
565 // m_bankingTimescale = 2; 413 // m_bankingTimescale = 2;
566 // m_referenceFrame = Quaternion.Identity; 414 // m_referenceFrame = Quaternion.Identity;
567 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 415 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
568 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 416 | VehicleFlag.HOVER_TERRAIN_ONLY
569 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); 417 | VehicleFlag.HOVER_GLOBAL_HEIGHT
418 | VehicleFlag.HOVER_UP_ONLY
419 | VehicleFlag.NO_DEFLECTION_UP
420 | VehicleFlag.LIMIT_MOTOR_UP);
570 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 421 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
571 break; 422 break;
572 case Vehicle.TYPE_BALLOON: 423 case Vehicle.TYPE_BALLOON:
@@ -592,50 +443,67 @@ namespace OpenSim.Region.Physics.BulletSPlugin
592 // m_bankingMix = 0.7f; 443 // m_bankingMix = 0.7f;
593 // m_bankingTimescale = 5; 444 // m_bankingTimescale = 5;
594 // m_referenceFrame = Quaternion.Identity; 445 // m_referenceFrame = Quaternion.Identity;
595 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 446 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
596 VehicleFlag.HOVER_UP_ONLY); 447 | VehicleFlag.HOVER_TERRAIN_ONLY
597 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); 448 | VehicleFlag.HOVER_UP_ONLY
598 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 449 | VehicleFlag.NO_DEFLECTION_UP
599 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); 450 | VehicleFlag.LIMIT_MOTOR_UP);
451 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
452 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
600 break; 453 break;
601 } 454 }
602 }//end SetDefaultsForType 455 }//end SetDefaultsForType
603 456
604 internal void Step(float pTimestep) 457 // Some of the properties of this prim may have changed.
458 // Do any updating needed for a vehicle
459 public void Refresh()
605 { 460 {
606 if (m_type == Vehicle.TYPE_NONE) return; 461 if (!IsActive)
462 return;
463
464 // Set the prim's inertia to zero. The vehicle code handles that and this
465 // removes the motion and torque actions introduced by Bullet.
466 Vector3 inertia = Vector3.Zero;
467 // comment out for DEBUG test
468 // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
469 // BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
470 }
607 471
608 frcount++; // used to limit debug comment output 472 // One step of the vehicle properties for the next 'pTimestep' seconds.
609 if (frcount > 100) 473 internal void Step(float pTimestep)
610 frcount = 0; 474 {
475 if (!IsActive) return;
611 476
612 MoveLinear(pTimestep); 477 MoveLinear(pTimestep);
613 MoveAngular(pTimestep); 478 MoveAngular(pTimestep);
614 LimitRotation(pTimestep); 479 LimitRotation(pTimestep);
615 480
616 DetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 481 // remember the position so next step we can limit absolute movement effects
617 m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); 482 m_lastPositionVector = Prim.ForcePosition;
483
484 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
485 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
618 }// end Step 486 }// end Step
619 487
488 // Apply the effect of the linear motor.
489 // Also does hover and float.
620 private void MoveLinear(float pTimestep) 490 private void MoveLinear(float pTimestep)
621 { 491 {
622 // requested m_linearMotorDirection is significant 492 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
623 // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) 493 // m_lastLinearVelocityVector is the speed we are moving in that direction
624 if (m_linearMotorDirection.LengthSquared() > 0.0001f) 494 if (m_linearMotorDirection.LengthSquared() > 0.001f)
625 { 495 {
626 Vector3 origDir = m_linearMotorDirection; 496 Vector3 origDir = m_linearMotorDirection;
627 Vector3 origVel = m_lastLinearVelocityVector; 497 Vector3 origVel = m_lastLinearVelocityVector;
628 498
629 // add drive to body 499 // add drive to body
630 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); 500 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep);
631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale); 501 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep);
632 // lastLinearVelocityVector is the current body velocity vector? 502 // lastLinearVelocityVector is the current body velocity vector
633 // RA: Not sure what the *10 is for. A correction for pTimestep? 503 // RA: Not sure what the *10 is for. A correction for pTimestep?
634 // m_lastLinearVelocityVector += (addAmount*10); 504 // m_lastLinearVelocityVector += (addAmount*10);
635 m_lastLinearVelocityVector += addAmount; 505 m_lastLinearVelocityVector += addAmount;
636 506
637 // This will work temporarily, but we really need to compare speed on an axis
638 // KF: Limit body velocity to applied velocity?
639 // Limit the velocity vector to less than the last set linear motor direction 507 // Limit the velocity vector to less than the last set linear motor direction
640 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 508 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
641 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 509 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
@@ -644,124 +512,87 @@ namespace OpenSim.Region.Physics.BulletSPlugin
644 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) 512 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
645 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; 513 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
646 514
515 /*
647 // decay applied velocity 516 // decay applied velocity
648 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); 517 Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep);
518 // (RA: do not know where the 0.5f comes from)
649 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 519 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
650
651 /*
652 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale;
653 m_lastLinearVelocityVector += addAmount;
654
655 float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale);
656 m_linearMotorDirection *= decayfraction;
657
658 */ 520 */
521 float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep));
522 m_linearMotorDirection *= keepfraction;
659 523
660 DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}", 524 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
661 m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector); 525 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
662 } 526 }
663 else 527 else
664 { 528 {
665 // if what remains of applied is small, zero it. 529 // if what remains of direction is very small, zero it.
666 // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
667 // m_lastLinearVelocityVector = Vector3.Zero;
668 m_linearMotorDirection = Vector3.Zero; 530 m_linearMotorDirection = Vector3.Zero;
669 m_lastLinearVelocityVector = Vector3.Zero; 531 m_lastLinearVelocityVector = Vector3.Zero;
532 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
670 } 533 }
671 534
672 // convert requested object velocity to world-referenced vector 535 // convert requested object velocity to object relative vector
673 Quaternion rotq = m_prim.Orientation; 536 Quaternion rotq = Prim.ForceOrientation;
674 m_dir = m_lastLinearVelocityVector * rotq; 537 m_newVelocity = m_lastLinearVelocityVector * rotq;
675 538
676 // Add the various forces into m_dir which will be our new direction vector (velocity) 539 // Add the various forces into m_dir which will be our new direction vector (velocity)
677 540
678 // add Gravity and Buoyancy 541 // add Gravity and Buoyancy
679 // KF: So far I have found no good method to combine a script-requested
680 // .Z velocity and gravity. Therefore only 0g will used script-requested
681 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
682 Vector3 grav = Vector3.Zero;
683 // There is some gravity, make a gravity force vector that is applied after object velocity. 542 // There is some gravity, make a gravity force vector that is applied after object velocity.
684 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 543 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
685 grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy); 544 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy));
545
546 /*
547 * RA: Not sure why one would do this
686 // Preserve the current Z velocity 548 // Preserve the current Z velocity
687 Vector3 vel_now = m_prim.Velocity; 549 Vector3 vel_now = m_prim.Velocity;
688 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 550 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
551 */
689 552
690 Vector3 pos = m_prim.Position; 553 Vector3 pos = Prim.ForcePosition;
691 Vector3 posChange = pos;
692// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); 554// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
693 double Zchange = Math.Abs(posChange.Z);
694 if (m_BlockingEndPoint != Vector3.Zero)
695 {
696 bool changed = false;
697 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
698 {
699 pos.X -= posChange.X + 1;
700 changed = true;
701 }
702 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
703 {
704 pos.Y -= posChange.Y + 1;
705 changed = true;
706 }
707 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
708 {
709 pos.Z -= posChange.Z + 1;
710 changed = true;
711 }
712 if (pos.X <= 0)
713 {
714 pos.X += posChange.X + 1;
715 changed = true;
716 }
717 if (pos.Y <= 0)
718 {
719 pos.Y += posChange.Y + 1;
720 changed = true;
721 }
722 if (changed)
723 {
724 m_prim.Position = pos;
725 DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
726 m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
727 }
728 }
729 555
730 // If below the terrain, move us above the ground a little. 556 // If below the terrain, move us above the ground a little.
731 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) 557 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
558 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
559 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
560 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
561 // if (rotatedSize.Z < terrainHeight)
562 if (pos.Z < terrainHeight)
732 { 563 {
733 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; 564 pos.Z = terrainHeight + 2;
734 m_prim.Position = pos; 565 Prim.ForcePosition = pos;
735 DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); 566 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
736 } 567 }
737 568
738 // Check if hovering 569 // Check if hovering
739 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 570 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
740 { 571 {
741 // We should hover, get the target height 572 // We should hover, get the target height
742 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) 573 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
743 { 574 {
744 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight; 575 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
745 } 576 }
746 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 577 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
747 { 578 {
748 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 579 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight;
749 } 580 }
750 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 581 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
751 { 582 {
752 m_VhoverTargetHeight = m_VhoverHeight; 583 m_VhoverTargetHeight = m_VhoverHeight;
753 } 584 }
754 585
755 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) 586 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
756 { 587 {
757 // If body is aready heigher, use its height as target height 588 // If body is aready heigher, use its height as target height
758 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; 589 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
759 } 590 }
760 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 591 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
761 { 592 {
762 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 593 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
763 { 594 {
764 m_prim.Position = pos; 595 Prim.ForcePosition = pos;
765 } 596 }
766 } 597 }
767 else 598 else
@@ -770,85 +601,99 @@ namespace OpenSim.Region.Physics.BulletSPlugin
770 // Replace Vertical speed with correction figure if significant 601 // Replace Vertical speed with correction figure if significant
771 if (Math.Abs(herr0) > 0.01f) 602 if (Math.Abs(herr0) > 0.01f)
772 { 603 {
773 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 604 m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
774 //KF: m_VhoverEfficiency is not yet implemented 605 //KF: m_VhoverEfficiency is not yet implemented
775 } 606 }
776 else 607 else
777 { 608 {
778 m_dir.Z = 0f; 609 m_newVelocity.Z = 0f;
779 } 610 }
780 } 611 }
781 612
782 DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight); 613 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
614 }
783 615
784// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped 616 Vector3 posChange = pos - m_lastPositionVector;
785// m_VhoverTimescale = 0f; // time to acheive height 617 if (m_BlockingEndPoint != Vector3.Zero)
786// pTimestep is time since last frame,in secs 618 {
619 bool changed = false;
620 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
621 {
622 pos.X -= posChange.X + 1;
623 changed = true;
624 }
625 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
626 {
627 pos.Y -= posChange.Y + 1;
628 changed = true;
629 }
630 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
631 {
632 pos.Z -= posChange.Z + 1;
633 changed = true;
634 }
635 if (pos.X <= 0)
636 {
637 pos.X += posChange.X + 1;
638 changed = true;
639 }
640 if (pos.Y <= 0)
641 {
642 pos.Y += posChange.Y + 1;
643 changed = true;
644 }
645 if (changed)
646 {
647 Prim.ForcePosition = pos;
648 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
649 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
650 }
787 } 651 }
788 652
653 // Limit absolute vertical change
654 float Zchange = Math.Abs(posChange.Z);
789 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 655 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
790 { 656 {
791 //Start Experimental Values
792 if (Zchange > .3) 657 if (Zchange > .3)
793 {
794 grav.Z = (float)(grav.Z * 3); 658 grav.Z = (float)(grav.Z * 3);
795 }
796 if (Zchange > .15) 659 if (Zchange > .15)
797 {
798 grav.Z = (float)(grav.Z * 2); 660 grav.Z = (float)(grav.Z * 2);
799 }
800 if (Zchange > .75) 661 if (Zchange > .75)
801 {
802 grav.Z = (float)(grav.Z * 1.5); 662 grav.Z = (float)(grav.Z * 1.5);
803 }
804 if (Zchange > .05) 663 if (Zchange > .05)
805 {
806 grav.Z = (float)(grav.Z * 1.25); 664 grav.Z = (float)(grav.Z * 1.25);
807 }
808 if (Zchange > .025) 665 if (Zchange > .025)
809 {
810 grav.Z = (float)(grav.Z * 1.125); 666 grav.Z = (float)(grav.Z * 1.125);
811 } 667 float postemp = (pos.Z - terrainHeight);
812 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
813 float postemp = (pos.Z - terraintemp);
814 if (postemp > 2.5f) 668 if (postemp > 2.5f)
815 {
816 grav.Z = (float)(grav.Z * 1.037125); 669 grav.Z = (float)(grav.Z * 1.037125);
817 } 670 VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav);
818 DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
819 //End Experimental Values
820 } 671 }
672
673 // If not changing some axis, reduce out velocity
821 if ((m_flags & (VehicleFlag.NO_X)) != 0) 674 if ((m_flags & (VehicleFlag.NO_X)) != 0)
822 { 675 m_newVelocity.X = 0;
823 m_dir.X = 0;
824 }
825 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 676 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
826 { 677 m_newVelocity.Y = 0;
827 m_dir.Y = 0;
828 }
829 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 678 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
830 { 679 m_newVelocity.Z = 0;
831 m_dir.Z = 0;
832 }
833
834 m_lastPositionVector = m_prim.Position;
835 680
836 // Apply velocity 681 // Apply velocity
837 m_prim.Velocity = m_dir; 682 Prim.ForceVelocity = m_newVelocity;
838 // apply gravity force 683 // apply gravity force
839 // Why is this set here? The physics engine already does gravity. 684 // Why is this set here? The physics engine already does gravity.
840 // m_prim.AddForce(grav, false); 685 Prim.AddForce(grav, false, true);
841 // m_prim.Force = grav;
842 686
843 // Apply friction 687 // Apply friction
844 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); 688 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
845 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; 689 m_lastLinearVelocityVector *= keepFraction;
846 690
847 DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}", 691 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
848 m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount); 692 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
849 693
850 } // end MoveLinear() 694 } // end MoveLinear()
851 695
696 // Apply the effect of the angular motor.
852 private void MoveAngular(float pTimestep) 697 private void MoveAngular(float pTimestep)
853 { 698 {
854 // m_angularMotorDirection // angular velocity requested by LSL motor 699 // m_angularMotorDirection // angular velocity requested by LSL motor
@@ -860,7 +705,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
860 // m_lastAngularVelocity // what was last applied to body 705 // m_lastAngularVelocity // what was last applied to body
861 706
862 // Get what the body is doing, this includes 'external' influences 707 // Get what the body is doing, this includes 'external' influences
863 Vector3 angularVelocity = m_prim.RotationalVelocity; 708 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
864 709
865 if (m_angularMotorApply > 0) 710 if (m_angularMotorApply > 0)
866 { 711 {
@@ -868,48 +713,58 @@ namespace OpenSim.Region.Physics.BulletSPlugin
868 // a newly set velocity, this routine steps the value from the previous 713 // a newly set velocity, this routine steps the value from the previous
869 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). 714 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
870 // There are m_angularMotorApply steps. 715 // There are m_angularMotorApply steps.
871 Vector3 origAngularVelocity = m_angularMotorVelocity; 716 Vector3 origVel = m_angularMotorVelocity;
717 Vector3 origDir = m_angularMotorDirection;
718
872 // ramp up to new value 719 // ramp up to new value
873 // current velocity += error / (time to get there / step interval) 720 // new velocity += error / ( time to get there / step interval)
874 // requested speed - last motor speed 721 // requested speed - last motor speed
875 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 722 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
876 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 723 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
877 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); 724 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
878 725
879 DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}", 726 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}",
880 m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); 727 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
881 728
882 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected 729 m_angularMotorApply--;
883 // velocity may still be acheived.
884 } 730 }
885 else 731 else
886 { 732 {
887 // No motor recently applied, keep the body velocity 733 // No motor recently applied, keep the body velocity
888 // and decay the velocity 734 // and decay the velocity
889 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 735 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
736 if (m_angularMotorVelocity.LengthSquared() < 0.00001)
737 m_angularMotorVelocity = Vector3.Zero;
890 } // end motor section 738 } // end motor section
891 739
892 // Vertical attractor section 740 // Vertical attractor section
893 Vector3 vertattr = Vector3.Zero; 741 Vector3 vertattr = Vector3.Zero;
894 if (m_verticalAttractionTimescale < 300) 742 Vector3 deflection = Vector3.Zero;
743 Vector3 banking = Vector3.Zero;
744
745 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
895 { 746 {
896 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); 747 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
748 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
749
897 // get present body rotation 750 // get present body rotation
898 Quaternion rotq = m_prim.Orientation; 751 Quaternion rotq = Prim.ForceOrientation;
899 // make a vector pointing up 752 // vector pointing up
900 Vector3 verterr = Vector3.Zero; 753 Vector3 verterr = Vector3.Zero;
901 verterr.Z = 1.0f; 754 verterr.Z = 1.0f;
755
902 // rotate it to Body Angle 756 // rotate it to Body Angle
903 verterr = verterr * rotq; 757 verterr = verterr * rotq;
904 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. 758 // verterr.X and .Y are the World error amounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
905 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go 759 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
906 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. 760 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
761
762 // Error is 0 (no error) to +/- 2 (max error)
907 if (verterr.Z < 0.0f) 763 if (verterr.Z < 0.0f)
908 { 764 {
909 verterr.X = 2.0f - verterr.X; 765 verterr.X = 2.0f - verterr.X;
910 verterr.Y = 2.0f - verterr.Y; 766 verterr.Y = 2.0f - verterr.Y;
911 } 767 }
912 // Error is 0 (no error) to +/- 2 (max error)
913 // scale it by VAservo 768 // scale it by VAservo
914 verterr = verterr * VAservo; 769 verterr = verterr * VAservo;
915 770
@@ -924,12 +779,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
924 vertattr.X += bounce * angularVelocity.X; 779 vertattr.X += bounce * angularVelocity.X;
925 vertattr.Y += bounce * angularVelocity.Y; 780 vertattr.Y += bounce * angularVelocity.Y;
926 781
927 DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 782 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
928 m_prim.LocalID, verterr, bounce, vertattr); 783 Prim.LocalID, verterr, bounce, vertattr);
929 784
930 } // else vertical attractor is off 785 } // else vertical attractor is off
931 786
932 // m_lastVertAttractor = vertattr; 787 m_lastVertAttractor = vertattr;
933 788
934 // Bank section tba 789 // Bank section tba
935 790
@@ -937,18 +792,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
937 792
938 // Sum velocities 793 // Sum velocities
939 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 794 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
940 795
941 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 796 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
942 { 797 {
943 m_lastAngularVelocity.X = 0; 798 m_lastAngularVelocity.X = 0;
944 m_lastAngularVelocity.Y = 0; 799 m_lastAngularVelocity.Y = 0;
945 DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 800 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
946 } 801 }
947 802
948 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 803 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
949 { 804 {
950 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 805 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
951 DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 806 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
952 } 807 }
953 808
954 // apply friction 809 // apply friction
@@ -956,14 +811,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
956 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 811 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
957 812
958 // Apply to the body 813 // Apply to the body
959 m_prim.RotationalVelocity = m_lastAngularVelocity; 814 Prim.ForceRotationalVelocity = m_lastAngularVelocity;
960 815
961 DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); 816 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
962 } //end MoveAngular 817 } //end MoveAngular
963 818
964 internal void LimitRotation(float timestep) 819 internal void LimitRotation(float timestep)
965 { 820 {
966 Quaternion rotq = m_prim.Orientation; 821 Quaternion rotq = Prim.ForceOrientation;
967 Quaternion m_rot = rotq; 822 Quaternion m_rot = rotq;
968 bool changed = false; 823 bool changed = false;
969 if (m_RollreferenceFrame != Quaternion.Identity) 824 if (m_RollreferenceFrame != Quaternion.Identity)
@@ -996,23 +851,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
996 m_rot.Y = 0; 851 m_rot.Y = 0;
997 changed = true; 852 changed = true;
998 } 853 }
999 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 854 if (changed)
1000 { 855 {
1001 m_rot.X = 0; 856 Prim.ForceOrientation = m_rot;
1002 m_rot.Y = 0; 857 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1003 changed = true;
1004 } 858 }
1005 if (changed)
1006 m_prim.Orientation = m_rot;
1007 859
1008 DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
1009 } 860 }
1010 861
1011 // Invoke the detailed logger and output something if it's enabled. 862 // Invoke the detailed logger and output something if it's enabled.
1012 private void DetailLog(string msg, params Object[] args) 863 private void VDetailLog(string msg, params Object[] args)
1013 { 864 {
1014 if (m_prim.Scene.VehicleLoggingEnabled) 865 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1015 m_prim.Scene.PhysicsLogging.Write(msg, args); 866 Prim.PhysicsScene.DetailLog(msg, args);
1016 } 867 }
1017 } 868 }
1018} 869}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
index d68048b..7c8a215 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
@@ -1,55 +1,57 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35class BSHingeConstraint : BSConstraint 35class BSHingeConstraint : BSConstraint
36{ 36{
37 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 Vector3 pivotInA, Vector3 pivotInB, 38
39 Vector3 axisInA, Vector3 axisInB, 39 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
40 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 40 Vector3 pivotInA, Vector3 pivotInB,
41 { 41 Vector3 axisInA, Vector3 axisInB,
42 m_world = world; 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 m_body1 = obj1; 43 {
44 m_body2 = obj2; 44 m_world = world;
45 m_constraint = new BulletConstraint( 45 m_body1 = obj1;
46 BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 46 m_body2 = obj2;
47 pivotInA, pivotInB, 47 m_constraint = new BulletConstraint(
48 axisInA, axisInB, 48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 49 pivotInA, pivotInB,
50 m_enabled = true; 50 axisInA, axisInB,
51 } 51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 52 m_enabled = true;
53} 53 }
54 54
55} 55}
56
57}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 087b9bb..c984824 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,29 +32,56 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public abstract class BSLinkset
36{ 36{
37 private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 private BSPrim m_linksetRoot; 39 // Create the correct type of linkset for this child
40 public BSPrim LinksetRoot { get { return m_linksetRoot; } } 40 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
41 {
42 BSLinkset ret = null;
43 /*
44 if (parent.IsPhysical)
45 ret = new BSLinksetConstraints(physScene, parent);
46 else
47 ret = new BSLinksetManual(physScene, parent);
48 */
49
50 // at the moment, there is only one
51 ret = new BSLinksetConstraints(physScene, parent);
52
53 return ret;
54 }
55
56 public BSPhysObject LinksetRoot { get; protected set; }
57
58 public BSScene PhysicsScene { get; private set; }
41 59
42 private BSScene m_physicsScene; 60 static int m_nextLinksetID = 1;
43 public BSScene PhysicsScene { get { return m_physicsScene; } } 61 public int LinksetID { get; private set; }
44 62
45 // The children under the root in this linkset 63 // The children under the root in this linkset.
46 private List<BSPrim> m_children; 64 // There are two lists of children: the current children at runtime
65 // and the children at taint-time. For instance, if you delink a
66 // child from the linkset, the child is removed from m_children
67 // but the constraint won't be removed until taint time.
68 // Two lists lets this track the 'current' children and
69 // the physical 'taint' children separately.
70 // After taint processing and before the simulation step, these
71 // two lists must be the same.
72 protected HashSet<BSPhysObject> m_children;
73 protected HashSet<BSPhysObject> m_taintChildren;
47 74
48 // We lock the diddling of linkset classes to prevent any badness. 75 // We lock the diddling of linkset classes to prevent any badness.
49 // This locks the modification of the instances of this class. Changes 76 // This locks the modification of the instances of this class. Changes
50 // to the physical representation is done via the tainting mechenism. 77 // to the physical representation is done via the tainting mechenism.
51 private object m_linksetActivityLock = new Object(); 78 protected object m_linksetActivityLock = new Object();
52 79
53 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 80 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
54 private float m_mass; 81 protected float m_mass;
55 public float LinksetMass 82 public float LinksetMass
56 { 83 {
57 get 84 get
58 { 85 {
59 m_mass = ComputeLinksetMass(); 86 m_mass = ComputeLinksetMass();
60 return m_mass; 87 return m_mass;
@@ -71,23 +98,31 @@ public class BSLinkset
71 get { return ComputeLinksetGeometricCenter(); } 98 get { return ComputeLinksetGeometricCenter(); }
72 } 99 }
73 100
74 public BSLinkset(BSScene scene, BSPrim parent) 101 protected void Initialize(BSScene scene, BSPhysObject parent)
75 { 102 {
76 // A simple linkset of one (no children) 103 // A simple linkset of one (no children)
77 m_physicsScene = scene; 104 LinksetID = m_nextLinksetID++;
78 m_linksetRoot = parent; 105 // We create LOTS of linksets.
79 m_children = new List<BSPrim>(); 106 if (m_nextLinksetID <= 0)
107 m_nextLinksetID = 1;
108 PhysicsScene = scene;
109 LinksetRoot = parent;
110 m_children = new HashSet<BSPhysObject>();
111 m_taintChildren = new HashSet<BSPhysObject>();
80 m_mass = parent.MassRaw; 112 m_mass = parent.MassRaw;
81 } 113 }
82 114
83 // Link to a linkset where the child knows the parent. 115 // Link to a linkset where the child knows the parent.
84 // Parent changing should not happen so do some sanity checking. 116 // Parent changing should not happen so do some sanity checking.
85 // We return the parent's linkset so the child can track its membership. 117 // We return the parent's linkset so the child can track its membership.
86 public BSLinkset AddMeToLinkset(BSPrim child) 118 // Called at runtime.
119 public BSLinkset AddMeToLinkset(BSPhysObject child)
87 { 120 {
88 lock (m_linksetActivityLock) 121 lock (m_linksetActivityLock)
89 { 122 {
90 AddChildToLinkset(child); 123 // Don't add the root to its own linkset
124 if (!IsRoot(child))
125 AddChildToLinkset(child);
91 } 126 }
92 return this; 127 return this;
93 } 128 }
@@ -95,36 +130,28 @@ public class BSLinkset
95 // Remove a child from a linkset. 130 // Remove a child from a linkset.
96 // Returns a new linkset for the child which is a linkset of one (just the 131 // Returns a new linkset for the child which is a linkset of one (just the
97 // orphened child). 132 // orphened child).
98 public BSLinkset RemoveMeFromLinkset(BSPrim child) 133 // Called at runtime.
134 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
99 { 135 {
100 lock (m_linksetActivityLock) 136 lock (m_linksetActivityLock)
101 { 137 {
102 if (IsRoot(child)) 138 if (IsRoot(child))
103 { 139 {
104 // if root of linkset, take the linkset apart 140 // Cannot remove the root from a linkset.
105 while (m_children.Count > 0) 141 return this;
106 {
107 // Note that we don't do a foreach because the remove routine
108 // takes it out of the list.
109 RemoveChildFromOtherLinkset(m_children[0]);
110 }
111 m_children.Clear(); // just to make sure
112 }
113 else
114 {
115 // Just removing a child from an existing linkset
116 RemoveChildFromLinkset(child);
117 } 142 }
143
144 RemoveChildFromLinkset(child);
118 } 145 }
119 146
120 // The child is down to a linkset of just itself 147 // The child is down to a linkset of just itself
121 return new BSLinkset(PhysicsScene, child); 148 return BSLinkset.Factory(PhysicsScene, child);
122 } 149 }
123 150
124 // Return 'true' if the passed object is the root object of this linkset 151 // Return 'true' if the passed object is the root object of this linkset
125 public bool IsRoot(BSPrim requestor) 152 public bool IsRoot(BSPhysObject requestor)
126 { 153 {
127 return (requestor.LocalID == m_linksetRoot.LocalID); 154 return (requestor.LocalID == LinksetRoot.LocalID);
128 } 155 }
129 156
130 public int NumberOfChildren { get { return m_children.Count; } } 157 public int NumberOfChildren { get { return m_children.Count; } }
@@ -133,12 +160,15 @@ public class BSLinkset
133 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 160 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
134 161
135 // Return 'true' if this child is in this linkset 162 // Return 'true' if this child is in this linkset
136 public bool HasChild(BSPrim child) 163 public bool HasChild(BSPhysObject child)
137 { 164 {
138 bool ret = false; 165 bool ret = false;
139 lock (m_linksetActivityLock) 166 lock (m_linksetActivityLock)
140 { 167 {
141 foreach (BSPrim bp in m_children) 168 if (m_children.Contains(child))
169 ret = true;
170 /*
171 foreach (BSPhysObject bp in m_children)
142 { 172 {
143 if (child.LocalID == bp.LocalID) 173 if (child.LocalID == bp.LocalID)
144 { 174 {
@@ -146,28 +176,73 @@ public class BSLinkset
146 break; 176 break;
147 } 177 }
148 } 178 }
179 */
149 } 180 }
150 return ret; 181 return ret;
151 } 182 }
152 183
153 private float ComputeLinksetMass() 184 // When physical properties are changed the linkset needs to recalculate
185 // its internal properties.
186 // May be called at runtime or taint-time (just pass the appropriate flag).
187 public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
188
189 // The object is going dynamic (physical). Do any setup necessary
190 // for a dynamic linkset.
191 // Only the state of the passed object can be modified. The rest of the linkset
192 // has not yet been fully constructed.
193 // Return 'true' if any properties updated on the passed object.
194 // Called at taint-time!
195 public abstract bool MakeDynamic(BSPhysObject child);
196
197 // The object is going static (non-physical). Do any setup necessary
198 // for a static linkset.
199 // Return 'true' if any properties updated on the passed object.
200 // Called at taint-time!
201 public abstract bool MakeStatic(BSPhysObject child);
202
203 // Called when a parameter update comes from the physics engine for any object
204 // of the linkset is received.
205 // Called at taint-time!!
206 public abstract void UpdateProperties(BSPhysObject physObject);
207
208 // Routine used when rebuilding the body of the root of the linkset
209 // Destroy all the constraints have have been made to root.
210 // This is called when the root body is changing.
211 // Returns 'true' of something was actually removed and would need restoring
212 // Called at taint-time!!
213 public abstract bool RemoveBodyDependencies(BSPrim child);
214
215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
216 // this routine will restore the removed constraints.
217 // Called at taint-time!!
218 public abstract void RestoreBodyDependencies(BSPrim child);
219
220 // ================================================================
221 // Below this point is internal magic
222
223 protected virtual float ComputeLinksetMass()
154 { 224 {
155 float mass = m_linksetRoot.MassRaw; 225 float mass;
156 foreach (BSPrim bp in m_children) 226 lock (m_linksetActivityLock)
157 { 227 {
158 mass += bp.MassRaw; 228 mass = LinksetRoot.MassRaw;
229 foreach (BSPhysObject bp in m_taintChildren)
230 {
231 mass += bp.MassRaw;
232 }
159 } 233 }
160 return mass; 234 return mass;
161 } 235 }
162 236
163 private OMV.Vector3 ComputeLinksetCenterOfMass() 237 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
164 { 238 {
165 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; 239 OMV.Vector3 com;
166 float totalMass = m_linksetRoot.MassRaw;
167
168 lock (m_linksetActivityLock) 240 lock (m_linksetActivityLock)
169 { 241 {
170 foreach (BSPrim bp in m_children) 242 com = LinksetRoot.Position * LinksetRoot.MassRaw;
243 float totalMass = LinksetRoot.MassRaw;
244
245 foreach (BSPhysObject bp in m_taintChildren)
171 { 246 {
172 com += bp.Position * bp.MassRaw; 247 com += bp.Position * bp.MassRaw;
173 totalMass += bp.MassRaw; 248 totalMass += bp.MassRaw;
@@ -179,241 +254,43 @@ public class BSLinkset
179 return com; 254 return com;
180 } 255 }
181 256
182 private OMV.Vector3 ComputeLinksetGeometricCenter() 257 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
183 { 258 {
184 OMV.Vector3 com = m_linksetRoot.Position; 259 OMV.Vector3 com;
185
186 lock (m_linksetActivityLock) 260 lock (m_linksetActivityLock)
187 { 261 {
188 foreach (BSPrim bp in m_children) 262 com = LinksetRoot.Position;
263
264 foreach (BSPhysObject bp in m_taintChildren)
189 { 265 {
190 com += bp.Position * bp.MassRaw; 266 com += bp.Position * bp.MassRaw;
191 } 267 }
192 com /= (m_children.Count + 1); 268 com /= (m_taintChildren.Count + 1);
193 } 269 }
194 270
195 return com; 271 return com;
196 } 272 }
197 273
198 // When physical properties are changed the linkset needs to recalculate
199 // its internal properties.
200 public void Refresh(BSPrim requestor)
201 {
202 // If there are no children, there aren't any constraints to recompute
203 if (!HasAnyChildren)
204 return;
205
206 // Only the root does the recomputation
207 if (IsRoot(requestor))
208 {
209 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
210 {
211 RecomputeLinksetConstraintVariables();
212 });
213 }
214 }
215
216 // Call each of the constraints that make up this linkset and recompute the
217 // various transforms and variables. Used when objects are added or removed
218 // from a linkset to make sure the constraints know about the new mass and
219 // geometry.
220 // Must only be called at taint time!!
221 private bool RecomputeLinksetConstraintVariables()
222 {
223 float linksetMass = LinksetMass;
224 lock (m_linksetActivityLock)
225 {
226 foreach (BSPrim child in m_children)
227 {
228 BSConstraint constrain;
229 if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.Body, child.Body, out constrain))
230 {
231 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
232 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
233 constrain.RecomputeConstraintVariables(linksetMass);
234 }
235 else
236 {
237 // Non-fatal error that can happen when children are being added to the linkset but
238 // their constraints have not been created yet.
239 // Caused by the fact that m_children is built at run time but building constraints
240 // happens at taint time.
241 // m_physicsScene.Logger.ErrorFormat("[BULLETSIM LINKSET] RecomputeLinksetConstraintVariables: constraint not found for root={0}, child={1}",
242 // m_linksetRoot.Body.ID, child.Body.ID);
243 }
244 }
245 }
246 return false;
247 }
248
249 // I am the root of a linkset and a new child is being added 274 // I am the root of a linkset and a new child is being added
250 // Called while LinkActivity is locked. 275 // Called while LinkActivity is locked.
251 private void AddChildToLinkset(BSPrim child) 276 protected abstract void AddChildToLinkset(BSPhysObject child);
252 {
253 if (!HasChild(child))
254 {
255 m_children.Add(child);
256
257 BSPrim rootx = LinksetRoot; // capture the root as of now
258 BSPrim childx = child;
259 m_physicsScene.TaintedObject("AddChildToLinkset", delegate()
260 {
261 // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
262 // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
263 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child
264 });
265 }
266 return;
267 }
268 277
269 // Forcefully removing a child from a linkset. 278 // Forcefully removing a child from a linkset.
270 // This is not being called by the child so we have to make sure the child doesn't think 279 // This is not being called by the child so we have to make sure the child doesn't think
271 // it's still connected to the linkset. 280 // it's still connected to the linkset.
272 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 281 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
273 // has to be updated also (like pointer to prim's parent). 282 // also has to be updated (like pointer to prim's parent).
274 private void RemoveChildFromOtherLinkset(BSPrim pchild) 283 protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
275 {
276 pchild.Linkset = new BSLinkset(m_physicsScene, pchild);
277 RemoveChildFromLinkset(pchild);
278 }
279 284
280 // I am the root of a linkset and one of my children is being removed. 285 // I am the root of a linkset and one of my children is being removed.
281 // Safe to call even if the child is not really in my linkset. 286 // Safe to call even if the child is not really in my linkset.
282 private void RemoveChildFromLinkset(BSPrim child) 287 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
283 {
284 if (m_children.Remove(child))
285 {
286 BSPrim rootx = LinksetRoot; // capture the root as of now
287 BSPrim childx = child;
288 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
289 {
290 // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
291 // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
292
293 PhysicallyUnlinkAChildFromRoot(rootx, childx);
294 });
295
296 RecomputeLinksetConstraintVariables();
297 }
298 else
299 {
300 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
301 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
302 }
303 return;
304 }
305
306 // Create a constraint between me (root of linkset) and the passed prim (the child).
307 // Called at taint time!
308 private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim)
309 {
310 // Zero motion for children so they don't interpolate
311 childPrim.ZeroMotion();
312
313 // Relative position normalized to the root prim
314 // Essentually a vector pointing from center of rootPrim to center of childPrim
315 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
316
317 // real world coordinate of midpoint between the two objects
318 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
319
320 // create a constraint that allows no freedom of movement between the two objects
321 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
322 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
323 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}",
324 rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint);
325 BS6DofConstraint constrain = new BS6DofConstraint(
326 m_physicsScene.World, rootPrim.Body, childPrim.Body,
327 midPoint,
328 true,
329 true
330 );
331 /* NOTE: attempt to build constraint with full frame computation, etc.
332 * Using the midpoint is easier since it lets the Bullet code use the transforms
333 * of the objects.
334 * Code left here as an example.
335 // ==================================================================================
336 // relative position normalized to the root prim
337 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
338 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
339
340 // relative rotation of the child to the parent
341 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
342 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
343
344 // create a constraint that allows no freedom of movement between the two objects
345 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
346 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
347 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
348 BS6DofConstraint constrain = new BS6DofConstraint(
349 PhysicsScene.World, rootPrim.Body, childPrim.Body,
350 OMV.Vector3.Zero,
351 OMV.Quaternion.Inverse(rootPrim.Orientation),
352 OMV.Vector3.Zero,
353 OMV.Quaternion.Inverse(childPrim.Orientation),
354 // A point half way between the parent and child
355 // childRelativePosition/2,
356 // childRelativeRotation,
357 // childRelativePosition/2,
358 // inverseChildRelativeRotation,
359 true,
360 true
361 );
362 // ==================================================================================
363 */
364
365 m_physicsScene.Constraints.AddConstraint(constrain);
366
367 // zero linear and angular limits makes the objects unable to move in relation to each other
368 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
369 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
370
371 // tweek the constraint to increase stability
372 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
373 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
374 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
375 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
376 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
377
378 RecomputeLinksetConstraintVariables();
379 }
380
381 // Remove linkage between myself and a particular child
382 // Called at taint time!
383 private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim)
384 {
385 // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
386 // LogHeader, rootPrim.LocalID, childPrim.LocalID);
387 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
388
389 // Find the constraint for this link and get rid of it from the overall collection and from my list
390 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body);
391
392 // Make the child refresh its location
393 BulletSimAPI.PushUpdate2(childPrim.Body.Ptr);
394 }
395
396 // Remove linkage between myself and any possible children I might have
397 // Called at taint time!
398 private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim)
399 {
400 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
401 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
402
403 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body);
404 }
405
406 // Invoke the detailed logger and output something if it's enabled.
407 private void DebugLog(string msg, params Object[] args)
408 {
409 if (m_physicsScene.ShouldDebugLog)
410 m_physicsScene.Logger.DebugFormat(msg, args);
411 }
412 288
413 // Invoke the detailed logger and output something if it's enabled. 289 // Invoke the detailed logger and output something if it's enabled.
414 private void DetailLog(string msg, params Object[] args) 290 protected void DetailLog(string msg, params Object[] args)
415 { 291 {
416 m_physicsScene.PhysicsLogging.Write(msg, args); 292 if (PhysicsScene.PhysicsLogging.Enabled)
293 PhysicsScene.DetailLog(msg, args);
417 } 294 }
418 295
419} 296}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000..8a750b5
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,385 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties.
46 // May be called at runtime or taint-time (just pass the appropriate flag).
47 public override void Refresh(BSPhysObject requestor, bool inTaintTime)
48 {
49 // If there are no children or not root, I am not the one that recomputes the constraints
50 if (!HasAnyChildren || !IsRoot(requestor))
51 return;
52
53 BSScene.TaintCallback refreshOperation = delegate()
54 {
55 RecomputeLinksetConstraintVariables();
56 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
57 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
58 };
59 if (inTaintTime)
60 refreshOperation();
61 else
62 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
63 }
64
65 // The object is going dynamic (physical). Do any setup necessary
66 // for a dynamic linkset.
67 // Only the state of the passed object can be modified. The rest of the linkset
68 // has not yet been fully constructed.
69 // Return 'true' if any properties updated on the passed object.
70 // Called at taint-time!
71 public override bool MakeDynamic(BSPhysObject child)
72 {
73 // What is done for each object in BSPrim is what we want.
74 return false;
75 }
76
77 // The object is going static (non-physical). Do any setup necessary
78 // for a static linkset.
79 // Return 'true' if any properties updated on the passed object.
80 // Called at taint-time!
81 public override bool MakeStatic(BSPhysObject child)
82 {
83 // What is done for each object in BSPrim is what we want.
84 return false;
85 }
86
87 // Called at taint-time!!
88 public override void UpdateProperties(BSPhysObject updated)
89 {
90 // Nothing to do for constraints on property updates
91 }
92
93 // Routine used when rebuilding the body of the root of the linkset
94 // Destroy all the constraints have have been made to root.
95 // This is called when the root body is changing.
96 // Returns 'true' of something eas actually removed and would need restoring
97 // Called at taint-time!!
98 public override bool RemoveBodyDependencies(BSPrim child)
99 {
100 bool ret = false;
101
102 lock (m_linksetActivityLock)
103 {
104 if (IsRoot(child))
105 {
106 // If the one with the dependency is root, must undo all children
107 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
108 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
109
110 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
111 }
112 else
113 {
114 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
115 child.LocalID,
116 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
117 child.LocalID, child.BSBody.ptr.ToString("X"));
118 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
119 // Despite the function name, this removes any link to the specified object.
120 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
121 }
122 }
123 return ret;
124 }
125
126 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
127 // this routine will restore the removed constraints.
128 // Called at taint-time!!
129 public override void RestoreBodyDependencies(BSPrim child)
130 {
131 lock (m_linksetActivityLock)
132 {
133 if (IsRoot(child))
134 {
135 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
136 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
137 foreach (BSPhysObject bpo in m_taintChildren)
138 {
139 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
140 }
141 }
142 else
143 {
144 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
145 LinksetRoot.LocalID,
146 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
147 child.LocalID, child.BSBody.ptr.ToString("X"));
148 PhysicallyLinkAChildToRoot(LinksetRoot, child);
149 }
150 }
151 }
152
153 // ================================================================
154 // Below this point is internal magic
155
156 // I am the root of a linkset and a new child is being added
157 // Called while LinkActivity is locked.
158 protected override void AddChildToLinkset(BSPhysObject child)
159 {
160 if (!HasChild(child))
161 {
162 m_children.Add(child);
163
164 BSPhysObject rootx = LinksetRoot; // capture the root as of now
165 BSPhysObject childx = child;
166
167 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
168
169 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
170 {
171 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
172 rootx.LocalID,
173 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
174 childx.LocalID, childx.BSBody.ptr.ToString("X"));
175 // Since this is taint-time, the body and shape could have changed for the child
176 rootx.ForcePosition = rootx.Position; // DEBUG
177 childx.ForcePosition = childx.Position; // DEBUG
178 PhysicallyLinkAChildToRoot(rootx, childx);
179 m_taintChildren.Add(child);
180 });
181 }
182 return;
183 }
184
185 // Forcefully removing a child from a linkset.
186 // This is not being called by the child so we have to make sure the child doesn't think
187 // it's still connected to the linkset.
188 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
189 // also has to be updated (like pointer to prim's parent).
190 protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
191 {
192 pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
193 RemoveChildFromLinkset(pchild);
194 }
195
196 // I am the root of a linkset and one of my children is being removed.
197 // Safe to call even if the child is not really in my linkset.
198 protected override void RemoveChildFromLinkset(BSPhysObject child)
199 {
200 if (m_children.Remove(child))
201 {
202 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
203 BSPhysObject childx = child;
204
205 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
206 childx.LocalID,
207 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
208 childx.LocalID, childx.BSBody.ptr.ToString("X"));
209
210 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
211 {
212 m_taintChildren.Remove(child);
213 PhysicallyUnlinkAChildFromRoot(rootx, childx);
214 RecomputeLinksetConstraintVariables();
215 });
216
217 }
218 else
219 {
220 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
221 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
222 }
223 return;
224 }
225
226 // Create a constraint between me (root of linkset) and the passed prim (the child).
227 // Called at taint time!
228 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
229 {
230 // Zero motion for children so they don't interpolate
231 childPrim.ZeroMotion();
232
233 // Relative position normalized to the root prim
234 // Essentually a vector pointing from center of rootPrim to center of childPrim
235 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
236
237 // real world coordinate of midpoint between the two objects
238 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
239
240 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
241 rootPrim.LocalID,
242 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
243 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
244 rootPrim.Position, childPrim.Position, midPoint);
245
246 // create a constraint that allows no freedom of movement between the two objects
247 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
248
249 BS6DofConstraint constrain = new BS6DofConstraint(
250 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
251
252 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
253 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
254 * of the objects.
255 * Code left as a warning to future programmers.
256 // ==================================================================================
257 // relative position normalized to the root prim
258 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
259 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
260
261 // relative rotation of the child to the parent
262 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
263 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
264
265 // create a constraint that allows no freedom of movement between the two objects
266 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
267 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
268 BS6DofConstraint constrain = new BS6DofConstraint(
269 PhysicsScene.World, rootPrim.Body, childPrim.Body,
270 OMV.Vector3.Zero,
271 OMV.Quaternion.Inverse(rootPrim.Orientation),
272 OMV.Vector3.Zero,
273 OMV.Quaternion.Inverse(childPrim.Orientation),
274 // A point half way between the parent and child
275 // childRelativePosition/2,
276 // childRelativeRotation,
277 // childRelativePosition/2,
278 // inverseChildRelativeRotation,
279 true,
280 true
281 );
282 // ==================================================================================
283 */
284
285 PhysicsScene.Constraints.AddConstraint(constrain);
286
287 // zero linear and angular limits makes the objects unable to move in relation to each other
288 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
289 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
290
291 // tweek the constraint to increase stability
292 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
293 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
294 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
295 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
296 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
297 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
298 {
299 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
300 }
301 }
302
303 // Remove linkage between myself and a particular child
304 // The root and child bodies are passed in because we need to remove the constraint between
305 // the bodies that were at unlink time.
306 // Called at taint time!
307 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
308 {
309 bool ret = false;
310 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
311 rootPrim.LocalID,
312 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
313 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
314
315 // Find the constraint for this link and get rid of it from the overall collection and from my list
316 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
317 {
318 // Make the child refresh its location
319 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
320 ret = true;
321 }
322
323 return ret;
324 }
325
326 // Remove linkage between myself and any possible children I might have.
327 // Called at taint time!
328 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
329 {
330 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
331 bool ret = false;
332
333 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
334 {
335 ret = true;
336 }
337 return ret;
338 }
339
340 // Call each of the constraints that make up this linkset and recompute the
341 // various transforms and variables. Used when objects are added or removed
342 // from a linkset to make sure the constraints know about the new mass and
343 // geometry.
344 // Must only be called at taint time!!
345 private void RecomputeLinksetConstraintVariables()
346 {
347 float linksetMass = LinksetMass;
348 foreach (BSPhysObject child in m_taintChildren)
349 {
350 BSConstraint constrain;
351 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
352 {
353 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
354 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
355 constrain.RecomputeConstraintVariables(linksetMass);
356 }
357 else
358 {
359 // Non-fatal error that happens when children are being added to the linkset but
360 // their constraints have not been created yet.
361 break;
362 }
363 }
364
365 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
366 if (m_children.Count == m_taintChildren.Count)
367 {
368 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
369 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
370 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
371 centerOfMass, OMV.Quaternion.Identity);
372 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
373 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
374 foreach (BSPhysObject child in m_taintChildren)
375 {
376 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
377 centerOfMass, OMV.Quaternion.Identity);
378 }
379
380 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
381 }
382 return;
383 }
384}
385}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
new file mode 100755
index 0000000..538f905
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -0,0 +1,238 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37// Class to wrap all objects.
38// The rest of BulletSim doesn't need to keep checking for avatars or prims
39// unless the difference is significant.
40public abstract class BSPhysObject : PhysicsActor
41{
42 protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
43 {
44 PhysicsScene = parentScene;
45 LocalID = localID;
46 PhysObjectName = name;
47 TypeName = typeName;
48
49 Linkset = BSLinkset.Factory(PhysicsScene, this);
50 LastAssetBuildFailed = false;
51
52 CollisionCollection = new CollisionEventUpdate();
53 SubscribedEventsMs = 0;
54 CollidingStep = 0;
55 CollidingGroundStep = 0;
56 }
57
58 public BSScene PhysicsScene { get; protected set; }
59 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
60 public string PhysObjectName { get; protected set; }
61 public string TypeName { get; protected set; }
62
63 public BSLinkset Linkset { get; set; }
64
65 // Return the object mass without calculating it or having side effects
66 public abstract float MassRaw { get; }
67
68 // Reference to the physical body (btCollisionObject) of this object
69 public BulletBody BSBody;
70 // Reference to the physical shape (btCollisionShape) of this object
71 public BulletShape BSShape;
72
73 // 'true' if the mesh's underlying asset failed to build.
74 // This will keep us from looping after the first time the build failed.
75 public bool LastAssetBuildFailed { get; set; }
76
77 // The objects base shape information. Null if not a prim type shape.
78 public PrimitiveBaseShape BaseShape { get; protected set; }
79
80 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences
82 // between the current update and the previous values.
83 public EntityProperties CurrentEntityProperties { get; set; }
84 public EntityProperties LastEntityProperties { get; set; }
85
86 public abstract OMV.Vector3 Scale { get; set; }
87 public abstract bool IsSolid { get; }
88 public abstract bool IsStatic { get; }
89
90 // Stop all physical motion.
91 public abstract void ZeroMotion();
92
93 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
94 public virtual void StepVehicle(float timeStep) { }
95
96 // Update the physical location and motion of the object. Called with data from Bullet.
97 public abstract void UpdateProperties(EntityProperties entprop);
98
99 // Tell the object to clean up.
100 public abstract void Destroy();
101
102 public abstract OMV.Vector3 ForcePosition { get; set; }
103
104 public abstract OMV.Quaternion ForceOrientation { get; set; }
105
106 public abstract OMV.Vector3 ForceVelocity { get; set; }
107
108 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
109
110 public abstract float ForceBuoyancy { get; set; }
111
112 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
113
114 #region Collisions
115
116 // Requested number of milliseconds between collision events. Zero means disabled.
117 protected int SubscribedEventsMs { get; set; }
118 // Given subscription, the time that a collision may be passed up
119 protected int NextCollisionOkTime { get; set; }
120 // The simulation step that last had a collision
121 protected long CollidingStep { get; set; }
122 // The simulation step that last had a collision with the ground
123 protected long CollidingGroundStep { get; set; }
124 // The collision flags we think are set in Bullet
125 protected CollisionFlags CurrentCollisionFlags { get; set; }
126
127 // The collisions that have been collected this tick
128 protected CollisionEventUpdate CollisionCollection;
129
130 // The simulation step is telling this object about a collision.
131 // Return 'true' if a collision was processed and should be sent up.
132 // Called at taint time from within the Step() function
133 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
134 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
135 {
136 bool ret = false;
137
138 // The following lines make IsColliding() and IsCollidingGround() work
139 CollidingStep = PhysicsScene.SimulationStep;
140 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
141 {
142 CollidingGroundStep = PhysicsScene.SimulationStep;
143 }
144
145 // prims in the same linkset cannot collide with each other
146 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
147 {
148 return ret;
149 }
150
151 // if someone has subscribed for collision events....
152 if (SubscribedEvents()) {
153 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
154 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
155 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
156
157 ret = true;
158 }
159 return ret;
160 }
161
162 // Send the collected collisions into the simulator.
163 // Called at taint time from within the Step() function thus no locking problems
164 // with CollisionCollection and ObjectsWithNoMoreCollisions.
165 // Return 'true' if there were some actual collisions passed up
166 public virtual bool SendCollisions()
167 {
168 bool ret = true;
169 // If the 'no collision' call, force it to happen right now so quick collision_end
170 bool force = CollisionCollection.Count == 0;
171
172 // throttle the collisions to the number of milliseconds specified in the subscription
173 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
174 {
175 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
176
177 // We are called if we previously had collisions. If there are no collisions
178 // this time, send up one last empty event so OpenSim can sense collision end.
179 if (CollisionCollection.Count == 0)
180 {
181 // If I have no collisions this time, remove me from the list of objects with collisions.
182 ret = false;
183 }
184
185 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
186 base.SendCollisionUpdate(CollisionCollection);
187
188 // The collisionCollection structure is passed around in the simulator.
189 // Make sure we don't have a handle to that one and that a new one is used for next time.
190 CollisionCollection = new CollisionEventUpdate();
191 }
192 return ret;
193 }
194
195 // Subscribe for collision events.
196 // Parameter is the millisecond rate the caller wishes collision events to occur.
197 public override void SubscribeEvents(int ms) {
198 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
199 SubscribedEventsMs = ms;
200 if (ms > 0)
201 {
202 // make sure first collision happens
203 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
204
205 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
206 {
207 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
208 });
209 }
210 else
211 {
212 // Subscribing for zero or less is the same as unsubscribing
213 UnSubscribeEvents();
214 }
215 }
216 public override void UnSubscribeEvents() {
217 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
218 SubscribedEventsMs = 0;
219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
220 {
221 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
222 });
223 }
224 // Return 'true' if the simulator wants collision events
225 public override bool SubscribedEvents() {
226 return (SubscribedEventsMs > 0);
227 }
228
229 #endregion // Collisions
230
231 // High performance detailed logging routine used by the physical objects.
232 protected void DetailLog(string msg, params Object[] args)
233 {
234 if (PhysicsScene.PhysicsLogging.Enabled)
235 PhysicsScene.DetailLog(msg, args);
236 }
237}
238}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 0f027b8..20f5180 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. 36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the 37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine. 38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. 39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
@@ -62,7 +62,7 @@ public class BSPlugin : IPhysicsPlugin
62 if (Util.IsWindows()) 62 if (Util.IsWindows())
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll"); 63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the 64 // If not Windows, loading is performed by the
65 // Mono loader as specified in 65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". 66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67 67
68 _mScene = new BSScene(sceneIdentifier); 68 _mScene = new BSScene(sceneIdentifier);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 9c20004..38ab3de 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.
27using System; 30using System;
28using System.Reflection; 31using System.Reflection;
29using System.Collections.Generic; 32using System.Collections.Generic;
@@ -36,32 +39,18 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36 39
37namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.Physics.BulletSPlugin
38{ 41{
42
39 [Serializable] 43 [Serializable]
40public sealed class BSPrim : PhysicsActor 44public sealed class BSPrim : BSPhysObject
41{ 45{
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]"; 47 private static readonly string LogHeader = "[BULLETS PRIM]";
44 48
45 private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); } 49 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
46 50 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
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.
61 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 51 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
62 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer 52 // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
63 53
64 private bool _stopped;
65 private bool _grabbed; 54 private bool _grabbed;
66 private bool _isSelected; 55 private bool _isSelected;
67 private bool _isVolumeDetect; 56 private bool _isVolumeDetect;
@@ -89,25 +78,6 @@ public sealed class BSPrim : PhysicsActor
89 private bool _kinematic; 78 private bool _kinematic;
90 private float _buoyancy; 79 private float _buoyancy;
91 80
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
111 private BSDynamics _vehicle; 81 private BSDynamics _vehicle;
112 82
113 private OMV.Vector3 _PIDTarget; 83 private OMV.Vector3 _PIDTarget;
@@ -122,108 +92,112 @@ public sealed class BSPrim : PhysicsActor
122 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 92 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
123 { 93 {
124 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 94 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
125 _localID = localID; 95 base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
126 _avName = primName; 96 _physicsActorType = (int)ActorTypes.Prim;
127 _scene = parent_scene;
128 _position = pos; 97 _position = pos;
129 _size = size; 98 _size = size;
130 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 99 Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
131 _orientation = rotation; 100 _orientation = rotation;
132 _buoyancy = 1f; 101 _buoyancy = 1f;
133 _velocity = OMV.Vector3.Zero; 102 _velocity = OMV.Vector3.Zero;
134 _rotationalVelocity = OMV.Vector3.Zero; 103 _rotationalVelocity = OMV.Vector3.Zero;
135 _hullKey = 0; 104 BaseShape = pbs;
136 _meshKey = 0;
137 _pbs = pbs;
138 _isPhysical = pisPhysical; 105 _isPhysical = pisPhysical;
139 _isVolumeDetect = false; 106 _isVolumeDetect = false;
140 _subscribedEventsMs = 0; 107 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
141 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 108 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
142 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 109 _restitution = PhysicsScene.Params.defaultRestitution;
143 _restitution = _scene.Params.defaultRestitution; 110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
144 _linkset = new BSLinkset(_scene, this); // a linkset of one
145 _vehicle = new BSDynamics(this); // add vehicleness
146 _mass = CalculateMass(); 111 _mass = CalculateMass();
147 // do the actual object creation at taint time 112
113 // No body or shape yet
114 BSBody = new BulletBody(LocalID, IntPtr.Zero);
115 BSShape = new BulletShape(IntPtr.Zero);
116
148 DetailLog("{0},BSPrim.constructor,call", LocalID); 117 DetailLog("{0},BSPrim.constructor,call", LocalID);
149 _scene.TaintedObject("BSPrim.create", delegate() 118 // do the actual object creation at taint time
119 PhysicsScene.TaintedObject("BSPrim.create", delegate()
150 { 120 {
151 RecreateGeomAndObject(); 121 CreateGeomAndObject(true);
152 122
153 // Get the pointer to the physical body for this object. 123 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr);
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));
157 }); 124 });
158 } 125 }
159 126
160 // called when this prim is being destroyed and we should free all the resources 127 // called when this prim is being destroyed and we should free all the resources
161 public void Destroy() 128 public override void Destroy()
162 { 129 {
163 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 130 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
164 131
165 // Undo any links between me and any other object 132 // Undo any links between me and any other object
166 BSPrim parentBefore = _linkset.LinksetRoot; 133 BSPhysObject parentBefore = Linkset.LinksetRoot;
167 int childrenBefore = _linkset.NumberOfChildren; 134 int childrenBefore = Linkset.NumberOfChildren;
168 135
169 _linkset = _linkset.RemoveMeFromLinkset(this); 136 Linkset = Linkset.RemoveMeFromLinkset(this);
170 137
171 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", 138 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
172 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 139 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
173 140
174 // Undo any vehicle properties 141 // Undo any vehicle properties
175 this.VehicleType = (int)Vehicle.TYPE_NONE; 142 this.VehicleType = (int)Vehicle.TYPE_NONE;
176 143
177 _scene.TaintedObject("BSPrim.destroy", delegate() 144 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
178 { 145 {
179 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
180 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 147 // If there are physical body and shape, release my use of same.
181 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); 148 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
149 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
182 }); 150 });
183 } 151 }
184 152
185 public override bool Stopped { 153 // No one uses this property.
186 get { return _stopped; } 154 public override bool Stopped {
155 get { return false; }
187 } 156 }
188 public override OMV.Vector3 Size { 157 public override OMV.Vector3 Size {
189 get { return _size; } 158 get { return _size; }
190 set { 159 set {
191 _size = value; 160 _size = value;
192 _scene.TaintedObject("BSPrim.setSize", delegate() 161 ForceBodyShapeRebuild(false);
193 { 162 }
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 }
200 } 163 }
201 public override PrimitiveBaseShape Shape { 164 // Scale is what we set in the physics engine. It is different than 'size' in that
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 {
202 set { 169 set {
203 _pbs = value; 170 BaseShape = value;
204 _scene.TaintedObject("BSPrim.setShape", delegate() 171 ForceBodyShapeRebuild(false);
205 { 172 }
206 _mass = CalculateMass(); // changing the shape changes the mass
207 RecreateGeomAndObject();
208 });
209 }
210 } 173 }
211 public override uint LocalID { 174 public override bool ForceBodyShapeRebuild(bool inTaintTime)
212 set { _localID = value; } 175 {
213 get { return _localID; } 176 LastAssetBuildFailed = false;
177 BSScene.TaintCallback rebuildOperation = delegate()
178 {
179 _mass = CalculateMass(); // changing the shape changes the mass
180 CreateGeomAndObject(true);
181 };
182 if (inTaintTime)
183 rebuildOperation();
184 else
185 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
186 return true;
214 } 187 }
215 public override bool Grabbed { 188 public override bool Grabbed {
216 set { _grabbed = value; 189 set { _grabbed = value;
217 } 190 }
218 } 191 }
219 public override bool Selected { 192 public override bool Selected {
220 set { 193 set {
221 _isSelected = value; 194 _isSelected = value;
222 _scene.TaintedObject("BSPrim.setSelected", delegate() 195 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
223 { 196 {
224 SetObjectDynamic(); 197 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
198 SetObjectDynamic(false);
225 }); 199 });
226 } 200 }
227 } 201 }
228 public override void CrossingFailure() { return; } 202 public override void CrossingFailure() { return; }
229 203
@@ -232,158 +206,227 @@ public sealed class BSPrim : PhysicsActor
232 BSPrim parent = obj as BSPrim; 206 BSPrim parent = obj as BSPrim;
233 if (parent != null) 207 if (parent != null)
234 { 208 {
235 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID); 209 BSPhysObject parentBefore = Linkset.LinksetRoot;
236 BSPrim parentBefore = _linkset.LinksetRoot; 210 int childrenBefore = Linkset.NumberOfChildren;
237 int childrenBefore = _linkset.NumberOfChildren;
238 211
239 _linkset = parent.Linkset.AddMeToLinkset(this); 212 Linkset = parent.Linkset.AddMeToLinkset(this);
240 213
241 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 214 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
242 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 215 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
243 } 216 }
244 return; 217 return;
245 } 218 }
246 219
247 // delink me from my linkset 220 // delink me from my linkset
248 public override void delink() { 221 public override void delink() {
249 // TODO: decide if this parent checking needs to happen at taint time 222 // TODO: decide if this parent checking needs to happen at taint time
250 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 223 // 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());
253 224
254 BSPrim parentBefore = _linkset.LinksetRoot; 225 BSPhysObject parentBefore = Linkset.LinksetRoot;
255 int childrenBefore = _linkset.NumberOfChildren; 226 int childrenBefore = Linkset.NumberOfChildren;
256 227
257 _linkset = _linkset.RemoveMeFromLinkset(this); 228 Linkset = Linkset.RemoveMeFromLinkset(this);
258 229
259 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 230 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
260 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 231 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
261 return; 232 return;
262 } 233 }
263 234
264 // Set motion values to zero. 235 // Set motion values to zero.
265 // Do it to the properties so the values get set in the physics engine. 236 // Do it to the properties so the values get set in the physics engine.
266 // Push the setting of the values to the viewer. 237 // Push the setting of the values to the viewer.
267 // Called at taint time! 238 // Called at taint time!
268 public void ZeroMotion() 239 public override void ZeroMotion()
269 { 240 {
270 _velocity = OMV.Vector3.Zero; 241 _velocity = OMV.Vector3.Zero;
271 _acceleration = OMV.Vector3.Zero; 242 _acceleration = OMV.Vector3.Zero;
272 _rotationalVelocity = OMV.Vector3.Zero; 243 _rotationalVelocity = OMV.Vector3.Zero;
273 244
274 // Zero some other properties directly into the physics engine 245 // Zero some other properties directly into the physics engine
275 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); 246 BulletSimAPI.ClearForces2(BSBody.ptr);
276 BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
277 BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
278 BulletSimAPI.ClearForces2(Body.Ptr);
279 } 247 }
280 248
281 public override void LockAngularMotion(OMV.Vector3 axis) 249 public override void LockAngularMotion(OMV.Vector3 axis)
282 { 250 {
283 // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 251 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
284 return; 252 return;
285 } 253 }
286 254
287 public override OMV.Vector3 Position { 255 public override OMV.Vector3 Position {
288 get { 256 get {
289 if (!_linkset.IsRoot(this)) 257 if (!Linkset.IsRoot(this))
290 // child prims move around based on their parent. Need to get the latest location 258 // child prims move around based on their parent. Need to get the latest location
291 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 259 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
292 260
293 // don't do the GetObjectPosition for root elements because this function is called a zillion times 261 // don't do the GetObjectPosition for root elements because this function is called a zillion times
294 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 262 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
295 return _position; 263 return _position;
296 } 264 }
297 set { 265 set {
266 // If you must push the position into the physics engine, use ForcePosition.
267 if (_position == value)
268 {
269 return;
270 }
298 _position = value; 271 _position = value;
299 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 272 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
300 _scene.TaintedObject("BSPrim.setPosition", delegate() 273 PositionSanityCheck();
274 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
301 { 275 {
302 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 276 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
303 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 277 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
304 }); 278 });
305 } 279 }
280 }
281 public override OMV.Vector3 ForcePosition {
282 get {
283 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
284 return _position;
285 }
286 set {
287 _position = value;
288 PositionSanityCheck();
289 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
290 }
291 }
292
293 // Check that the current position is sane and, if not, modify the position to make it so.
294 // Check for being below terrain and being out of bounds.
295 // Returns 'true' of the position was made sane by some action.
296 private bool PositionSanityCheck()
297 {
298 bool ret = false;
299
300 // If totally below the ground, move the prim up
301 // TODO: figure out the right solution for this... only for dynamic objects?
302 /*
303 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
304 if (Position.Z < terrainHeight)
305 {
306 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
307 _position.Z = terrainHeight + 2.0f;
308 ret = true;
309 }
310 */
311 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
312 {
313 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
314 if (Position.Z < waterHeight)
315 {
316 _position.Z = waterHeight;
317 ret = true;
318 }
319 }
320
321 // TODO: check for out of bounds
322 return ret;
323 }
324
325 // A version of the sanity check that also makes sure a new position value is
326 // pushed to the physics engine. This routine would be used by anyone
327 // who is not already pushing the value.
328 private bool PositionSanityCheck(bool inTaintTime)
329 {
330 bool ret = false;
331 if (PositionSanityCheck())
332 {
333 // The new position value must be pushed into the physics engine but we can't
334 // just assign to "Position" because of potential call loops.
335 BSScene.TaintCallback sanityOperation = delegate()
336 {
337 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
338 ForcePosition = _position;
339 };
340 if (inTaintTime)
341 sanityOperation();
342 else
343 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
344
345 ret = true;
346 }
347 return ret;
306 } 348 }
307 349
308 // Return the effective mass of the object. 350 // Return the effective mass of the object.
309 // If there are multiple items in the linkset, add them together for the root 351 // If there are multiple items in the linkset, add them together for the root
310 public override float Mass 352 public override float Mass
311 { 353 {
312 get 354 get
313 { 355 {
314 return _linkset.LinksetMass; 356 // return Linkset.LinksetMass;
357 return _mass;
315 } 358 }
316 } 359 }
317 360
318 // used when we only want this prim's mass and not the linkset thing 361 // used when we only want this prim's mass and not the linkset thing
319 public float MassRaw { get { return _mass; } } 362 public override float MassRaw { get { return _mass; } }
320 363
321 // Is this used? 364 // Is this used?
322 public override OMV.Vector3 CenterOfMass 365 public override OMV.Vector3 CenterOfMass
323 { 366 {
324 get { return _linkset.CenterOfMass; } 367 get { return Linkset.CenterOfMass; }
325 } 368 }
326 369
327 // Is this used? 370 // Is this used?
328 public override OMV.Vector3 GeometricCenter 371 public override OMV.Vector3 GeometricCenter
329 { 372 {
330 get { return _linkset.GeometricCenter; } 373 get { return Linkset.GeometricCenter; }
331 } 374 }
332 375
333 public override OMV.Vector3 Force { 376 public override OMV.Vector3 Force {
334 get { return _force; } 377 get { return _force; }
335 set { 378 set {
336 _force = value; 379 _force = value;
337 _scene.TaintedObject("BSPrim.setForce", delegate() 380 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
338 { 381 {
339 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 382 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
340 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 383 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
341 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
342 }); 384 });
343 } 385 }
344 } 386 }
345 387
346 public override int VehicleType { 388 public override int VehicleType {
347 get { 389 get {
348 return (int)_vehicle.Type; // if we are a vehicle, return that type 390 return (int)_vehicle.Type; // if we are a vehicle, return that type
349 } 391 }
350 set { 392 set {
351 Vehicle type = (Vehicle)value; 393 Vehicle type = (Vehicle)value;
352 BSPrim vehiclePrim = this; 394
353 _scene.TaintedObject("setVehicleType", delegate() 395 // Tell the scene about the vehicle so it will get processing each frame.
396 PhysicsScene.VehicleInSceneTypeChanged(this, type);
397
398 PhysicsScene.TaintedObject("setVehicleType", delegate()
354 { 399 {
355 // Done at taint time so we're sure the physics engine is not using the variables 400 // Done at taint time so we're sure the physics engine is not using the variables
356 // Vehicle code changes the parameters for this vehicle type. 401 // Vehicle code changes the parameters for this vehicle type.
357 _vehicle.ProcessTypeChange(type); 402 _vehicle.ProcessTypeChange(type);
358 // Tell the scene about the vehicle so it will get processing each frame.
359 _scene.VehicleInSceneTypeChanged(this, type);
360 }); 403 });
361 } 404 }
362 } 405 }
363 public override void VehicleFloatParam(int param, float value) 406 public override void VehicleFloatParam(int param, float value)
364 { 407 {
365 _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 408 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
366 { 409 {
367 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 410 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
368 }); 411 });
369 } 412 }
370 public override void VehicleVectorParam(int param, OMV.Vector3 value) 413 public override void VehicleVectorParam(int param, OMV.Vector3 value)
371 { 414 {
372 _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 415 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
373 { 416 {
374 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 417 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
375 }); 418 });
376 } 419 }
377 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 420 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
378 { 421 {
379 _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 422 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
380 { 423 {
381 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 424 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
382 }); 425 });
383 } 426 }
384 public override void VehicleFlags(int param, bool remove) 427 public override void VehicleFlags(int param, bool remove)
385 { 428 {
386 _scene.TaintedObject("BSPrim.VehicleFlags", delegate() 429 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
387 { 430 {
388 _vehicle.ProcessVehicleFlags(param, remove); 431 _vehicle.ProcessVehicleFlags(param, remove);
389 }); 432 });
@@ -391,143 +434,331 @@ public sealed class BSPrim : PhysicsActor
391 434
392 // Called each simulation step to advance vehicle characteristics. 435 // Called each simulation step to advance vehicle characteristics.
393 // Called from Scene when doing simulation step so we're in taint processing time. 436 // Called from Scene when doing simulation step so we're in taint processing time.
394 public void StepVehicle(float timeStep) 437 public override void StepVehicle(float timeStep)
395 { 438 {
396 if (IsPhysical) 439 if (IsPhysical)
440 {
397 _vehicle.Step(timeStep); 441 _vehicle.Step(timeStep);
442 }
398 } 443 }
399 444
400 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 445 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
401 public override void SetVolumeDetect(int param) { 446 public override void SetVolumeDetect(int param) {
402 bool newValue = (param != 0); 447 bool newValue = (param != 0);
403 _isVolumeDetect = newValue; 448 if (_isVolumeDetect != newValue)
404 _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
405 { 449 {
406 SetObjectDynamic(); 450 _isVolumeDetect = newValue;
407 }); 451 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
408 return; 452 {
453 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
454 SetObjectDynamic(true);
455 });
456 }
457 return;
409 } 458 }
410 459 public override OMV.Vector3 Velocity {
411 public override OMV.Vector3 Velocity { 460 get { return _velocity; }
412 get { return _velocity; }
413 set { 461 set {
414 _velocity = value; 462 _velocity = value;
415 _scene.TaintedObject("BSPrim.setVelocity", delegate() 463 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
416 { 464 {
417 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 465 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
418 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 466 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
419 }); 467 });
420 } 468 }
469 }
470 public override OMV.Vector3 ForceVelocity {
471 get { return _velocity; }
472 set {
473 _velocity = value;
474 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
475 }
421 } 476 }
422 public override OMV.Vector3 Torque { 477 public override OMV.Vector3 Torque {
423 get { return _torque; } 478 get { return _torque; }
424 set { _torque = value; 479 set { _torque = value;
425 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 480 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
426 } 481 }
427 } 482 }
428 public override float CollisionScore { 483 public override float CollisionScore {
429 get { return _collisionScore; } 484 get { return _collisionScore; }
430 set { _collisionScore = value; 485 set { _collisionScore = value;
431 } 486 }
432 } 487 }
433 public override OMV.Vector3 Acceleration { 488 public override OMV.Vector3 Acceleration {
434 get { return _acceleration; } 489 get { return _acceleration; }
435 set { _acceleration = value; } 490 set { _acceleration = value; }
436 } 491 }
437 public override OMV.Quaternion Orientation { 492 public override OMV.Quaternion Orientation {
438 get { 493 get {
439 if (!_linkset.IsRoot(this)) 494 if (!Linkset.IsRoot(this))
440 { 495 {
441 // Children move around because tied to parent. Get a fresh value. 496 // Children move around because tied to parent. Get a fresh value.
442 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); 497 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
443 } 498 }
444 return _orientation; 499 return _orientation;
445 } 500 }
446 set { 501 set {
502 if (_orientation == value)
503 return;
447 _orientation = value; 504 _orientation = value;
448 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 505 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
449 _scene.TaintedObject("BSPrim.setOrientation", delegate() 506 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
450 { 507 {
451 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 508 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
452 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 509 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
453 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 510 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
454 }); 511 });
455 } 512 }
513 }
514 // Go directly to Bullet to get/set the value.
515 public override OMV.Quaternion ForceOrientation
516 {
517 get
518 {
519 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
520 return _orientation;
521 }
522 set
523 {
524 _orientation = value;
525 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
526 }
456 } 527 }
457 public override int PhysicsActorType { 528 public override int PhysicsActorType {
458 get { return _physicsActorType; } 529 get { return _physicsActorType; }
459 set { _physicsActorType = value; 530 set { _physicsActorType = value; }
460 }
461 } 531 }
462 public override bool IsPhysical { 532 public override bool IsPhysical {
463 get { return _isPhysical; } 533 get { return _isPhysical; }
464 set { 534 set {
465 _isPhysical = value; 535 if (_isPhysical != value)
466 _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
467 { 536 {
468 SetObjectDynamic(); 537 _isPhysical = value;
469 }); 538 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
470 } 539 {
540 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
541 SetObjectDynamic(true);
542 });
543 }
544 }
471 } 545 }
472 546
473 // An object is static (does not move) if selected or not physical 547 // An object is static (does not move) if selected or not physical
474 private bool IsStatic 548 public override bool IsStatic
475 { 549 {
476 get { return _isSelected || !IsPhysical; } 550 get { return _isSelected || !IsPhysical; }
477 } 551 }
478 552
479 // An object is solid if it's not phantom and if it's not doing VolumeDetect 553 // An object is solid if it's not phantom and if it's not doing VolumeDetect
480 private bool IsSolid 554 public override bool IsSolid
481 { 555 {
482 get { return !IsPhantom && !_isVolumeDetect; } 556 get { return !IsPhantom && !_isVolumeDetect; }
483 } 557 }
484 558
485 // Make gravity work if the object is physical and not selected 559 // Make gravity work if the object is physical and not selected
486 // No locking here because only called when it is safe 560 // Called at taint-time!!
487 private void SetObjectDynamic() 561 private void SetObjectDynamic(bool forceRebuild)
562 {
563 // Recreate the physical object if necessary
564 CreateGeomAndObject(forceRebuild);
565 }
566
567 // Convert the simulator's physical properties into settings on BulletSim objects.
568 // There are four flags we're interested in:
569 // IsStatic: Object does not move, otherwise the object has mass and moves
570 // isSolid: other objects bounce off of this object
571 // isVolumeDetect: other objects pass through but can generate collisions
572 // collisionEvents: whether this object returns collision events
573 private void UpdatePhysicalParameters()
574 {
575 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
576
577 // Mangling all the physical properties requires the object not be in the physical world.
578 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
579 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
580
581 // Set up the object physicalness (does gravity and collisions move this object)
582 MakeDynamic(IsStatic);
583
584 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
585 _vehicle.Refresh();
586
587 // Arrange for collision events if the simulator wants them
588 EnableCollisions(SubscribedEvents());
589
590 // Make solid or not (do things bounce off or pass through this object).
591 MakeSolid(IsSolid);
592
593 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
594
595 // Rebuild its shape
596 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
597
598 // Collision filter can be set only when the object is in the world
599 if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0)
600 {
601 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask);
602 }
603
604 // Recompute any linkset parameters.
605 // When going from non-physical to physical, this re-enables the constraints that
606 // had been automatically disabled when the mass was set to zero.
607 Linkset.Refresh(this, true);
608
609 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
610 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
611 }
612
613 // "Making dynamic" means changing to and from static.
614 // When static, gravity does not effect the object and it is fixed in space.
615 // When dynamic, the object can fall and be pushed by others.
616 // This is independent of its 'solidness' which controls what passes through
617 // this object and what interacts with it.
618 private void MakeDynamic(bool makeStatic)
488 { 619 {
489 // RA: remove this for the moment. 620 if (makeStatic)
490 // The problem is that dynamic objects are hulls so if we are becoming physical 621 {
491 // the shape has to be checked and possibly built. 622 // Become a Bullet 'static' object type
492 // Maybe a VerifyCorrectPhysicalShape() routine? 623 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
493 // RecreateGeomAndObject(); 624 // Stop all movement
625 BulletSimAPI.ClearAllForces2(BSBody.ptr);
626 // Center of mass is at the center of the object
627 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation);
628 // Mass is zero which disables a bunch of physics stuff in Bullet
629 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
630 // There is no inertia in a static object
631 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
632 // Set collision detection parameters
633 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
634 {
635 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
636 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
637 }
638 // There can be special things needed for implementing linksets
639 Linkset.MakeStatic(this);
640 // The activation state is 'disabled' so Bullet will not try to act on it.
641 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
642 // Start it out sleeping and physical actions could wake it up.
643 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
644
645 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
646 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
647 }
648 else
649 {
650 // Not a Bullet static object
651 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
652
653 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
654 BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
655 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
656
657 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
658 BulletSimAPI.ClearAllForces2(BSBody.ptr);
659
660 // For good measure, make sure the transform is set through to the motion state
661 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
662
663 // A dynamic object has mass
664 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
665 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
666 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
667 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
668
669 // Set collision detection parameters
670 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
671 {
672 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
673 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
674 }
494 675
495 // Bullet wants static objects to have a mass of zero 676 // Various values for simulation limits
496 float mass = IsStatic ? 0f : _mass; 677 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
678 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
679 BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
680 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
497 681
498 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); 682 // There might be special things needed for implementing linksets.
683 Linkset.MakeDynamic(this);
499 684
500 // recompute any linkset parameters 685 // Force activation of the object so Bullet will act on it.
501 _linkset.Refresh(this); 686 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
687 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
688 // BulletSimAPI.Activate2(BSBody.ptr, true);
502 689
503 CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr); 690 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
504 // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf); 691 BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
692 }
693 }
694
695 // "Making solid" means that other object will not pass through this object.
696 // To make transparent, we create a Bullet ghost object.
697 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
698 // the functions after this one set up the state of a possibly newly created collision body.
699 private void MakeSolid(bool makeSolid)
700 {
701 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
702 if (makeSolid)
703 {
704 // Verify the previous code created the correct shape for this type of thing.
705 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
706 {
707 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
708 }
709 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
710 }
711 else
712 {
713 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
714 {
715 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
716 }
717 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
718 BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
719 BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
720 }
721 }
722
723 // Turn on or off the flag controlling whether collision events are returned to the simulator.
724 private void EnableCollisions(bool wantsCollisionEvents)
725 {
726 if (wantsCollisionEvents)
727 {
728 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
729 }
730 else
731 {
732 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
733 }
505 } 734 }
506 735
507 // prims don't fly 736 // prims don't fly
508 public override bool Flying { 737 public override bool Flying {
509 get { return _flying; } 738 get { return _flying; }
510 set { _flying = value; } 739 set {
740 _flying = value;
741 }
511 } 742 }
512 public override bool SetAlwaysRun { 743 public override bool SetAlwaysRun {
513 get { return _setAlwaysRun; } 744 get { return _setAlwaysRun; }
514 set { _setAlwaysRun = value; } 745 set { _setAlwaysRun = value; }
515 } 746 }
516 public override bool ThrottleUpdates { 747 public override bool ThrottleUpdates {
517 get { return _throttleUpdates; } 748 get { return _throttleUpdates; }
518 set { _throttleUpdates = value; } 749 set { _throttleUpdates = value; }
519 } 750 }
520 public override bool IsColliding { 751 public override bool IsColliding {
521 get { return (_collidingStep == _scene.SimulationStep); } 752 get { return (CollidingStep == PhysicsScene.SimulationStep); }
522 set { _isColliding = value; } 753 set { _isColliding = value; }
523 } 754 }
524 public override bool CollidingGround { 755 public override bool CollidingGround {
525 get { return (_collidingGroundStep == _scene.SimulationStep); } 756 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
526 set { _collidingGround = value; } 757 set { _collidingGround = value; }
527 } 758 }
528 public override bool CollidingObj { 759 public override bool CollidingObj {
529 get { return _collidingObj; } 760 get { return _collidingObj; }
530 set { _collidingObj = value; } 761 set { _collidingObj = value; }
531 } 762 }
532 public bool IsPhantom { 763 public bool IsPhantom {
533 get { 764 get {
@@ -537,10 +768,19 @@ public sealed class BSPrim : PhysicsActor
537 return false; 768 return false;
538 } 769 }
539 } 770 }
540 public override bool FloatOnWater { 771 public override bool FloatOnWater {
541 set { _floatOnWater = value; } 772 set {
773 _floatOnWater = value;
774 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
775 {
776 if (_floatOnWater)
777 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
778 else
779 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
780 });
781 }
542 } 782 }
543 public override OMV.Vector3 RotationalVelocity { 783 public override OMV.Vector3 RotationalVelocity {
544 get { 784 get {
545 /* 785 /*
546 OMV.Vector3 pv = OMV.Vector3.Zero; 786 OMV.Vector3 pv = OMV.Vector3.Zero;
@@ -552,58 +792,76 @@ public sealed class BSPrim : PhysicsActor
552 */ 792 */
553 793
554 return _rotationalVelocity; 794 return _rotationalVelocity;
555 } 795 }
556 set { 796 set {
557 _rotationalVelocity = value; 797 _rotationalVelocity = value;
558 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 798 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
559 _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 799 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
560 { 800 {
561 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 801 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
562 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 802 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
563 }); 803 });
564 } 804 }
805 }
806 public override OMV.Vector3 ForceRotationalVelocity {
807 get {
808 return _rotationalVelocity;
809 }
810 set {
811 _rotationalVelocity = value;
812 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
813 }
565 } 814 }
566 public override bool Kinematic { 815 public override bool Kinematic {
567 get { return _kinematic; } 816 get { return _kinematic; }
568 set { _kinematic = value; 817 set { _kinematic = value;
569 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); 818 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
570 } 819 }
571 } 820 }
572 public override float Buoyancy { 821 public override float Buoyancy {
573 get { return _buoyancy; } 822 get { return _buoyancy; }
574 set { 823 set {
575 _buoyancy = value; 824 _buoyancy = value;
576 _scene.TaintedObject("BSPrim.setBuoyancy", delegate() 825 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
577 { 826 {
578 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 827 ForceBuoyancy = _buoyancy;
579 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
580 }); 828 });
581 } 829 }
830 }
831 public override float ForceBuoyancy {
832 get { return _buoyancy; }
833 set {
834 _buoyancy = value;
835 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
836 // Buoyancy is faked by changing the gravity applied to the object
837 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
838 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
839 }
582 } 840 }
583 841
584 // Used for MoveTo 842 // Used for MoveTo
585 public override OMV.Vector3 PIDTarget { 843 public override OMV.Vector3 PIDTarget {
586 set { _PIDTarget = value; } 844 set { _PIDTarget = value; }
587 } 845 }
588 public override bool PIDActive { 846 public override bool PIDActive {
589 set { _usePID = value; } 847 set { _usePID = value; }
590 } 848 }
591 public override float PIDTau { 849 public override float PIDTau {
592 set { _PIDTau = value; } 850 set { _PIDTau = value; }
593 } 851 }
594 852
595 // Used for llSetHoverHeight and maybe vehicle height 853 // Used for llSetHoverHeight and maybe vehicle height
596 // Hover Height will override MoveTo target's Z 854 // Hover Height will override MoveTo target's Z
597 public override bool PIDHoverActive { 855 public override bool PIDHoverActive {
598 set { _useHoverPID = value; } 856 set { _useHoverPID = value; }
599 } 857 }
600 public override float PIDHoverHeight { 858 public override float PIDHoverHeight {
601 set { _PIDHoverHeight = value; } 859 set { _PIDHoverHeight = value; }
602 } 860 }
603 public override PIDHoverType PIDHoverType { 861 public override PIDHoverType PIDHoverType {
604 set { _PIDHoverType = value; } 862 set { _PIDHoverType = value; }
605 } 863 }
606 public override float PIDHoverTau { 864 public override float PIDHoverTau {
607 set { _PIDHoverTao = value; } 865 set { _PIDHoverTao = value; }
608 } 866 }
609 867
@@ -615,6 +873,9 @@ public sealed class BSPrim : PhysicsActor
615 873
616 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); 874 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
617 public override void AddForce(OMV.Vector3 force, bool pushforce) { 875 public override void AddForce(OMV.Vector3 force, bool pushforce) {
876 AddForce(force, pushforce, false);
877 }
878 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
618 // for an object, doesn't matter if force is a pushforce or not 879 // for an object, doesn't matter if force is a pushforce or not
619 if (force.IsFinite()) 880 if (force.IsFinite())
620 { 881 {
@@ -624,56 +885,38 @@ public sealed class BSPrim : PhysicsActor
624 } 885 }
625 else 886 else
626 { 887 {
627 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 888 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
628 return; 889 return;
629 } 890 }
630 _scene.TaintedObject("BSPrim.AddForce", delegate() 891 BSScene.TaintCallback addForceOperation = delegate()
631 { 892 {
632 OMV.Vector3 fSum = OMV.Vector3.Zero; 893 OMV.Vector3 fSum = OMV.Vector3.Zero;
633 lock (m_accumulatedForces) 894 lock (m_accumulatedForces)
634 { 895 {
896 // Sum the accumulated additional forces for one big force to apply once.
635 foreach (OMV.Vector3 v in m_accumulatedForces) 897 foreach (OMV.Vector3 v in m_accumulatedForces)
636 { 898 {
637 fSum += v; 899 fSum += v;
638 } 900 }
639 m_accumulatedForces.Clear(); 901 m_accumulatedForces.Clear();
640 } 902 }
641 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force); 903 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
642 BulletSimAPI.AddObjectForce2(Body.Ptr, fSum); 904 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
643 }); 905 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
906 };
907 if (inTaintTime)
908 addForceOperation();
909 else
910 PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
644 } 911 }
645 912
646 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 913 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
647 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 914 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
648 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 915 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
649 } 916 }
650 public override void SetMomentum(OMV.Vector3 momentum) { 917 public override void SetMomentum(OMV.Vector3 momentum) {
651 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 918 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
652 } 919 }
653 public override void SubscribeEvents(int ms) {
654 _subscribedEventsMs = ms;
655 if (ms > 0)
656 {
657 // make sure first collision happens
658 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
659
660 Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
661 {
662 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
663 });
664 }
665 }
666 public override void UnSubscribeEvents() {
667 _subscribedEventsMs = 0;
668 Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
669 {
670 BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
671 });
672 }
673 public override bool SubscribedEvents() {
674 return (_subscribedEventsMs > 0);
675 }
676
677 #region Mass Calculation 920 #region Mass Calculation
678 921
679 private float CalculateMass() 922 private float CalculateMass()
@@ -682,19 +925,19 @@ public sealed class BSPrim : PhysicsActor
682 float tmp; 925 float tmp;
683 926
684 float returnMass = 0; 927 float returnMass = 0;
685 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 928 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
686 float hollowVolume = hollowAmount * hollowAmount; 929 float hollowVolume = hollowAmount * hollowAmount;
687 930
688 switch (_pbs.ProfileShape) 931 switch (BaseShape.ProfileShape)
689 { 932 {
690 case ProfileShape.Square: 933 case ProfileShape.Square:
691 // default box 934 // default box
692 935
693 if (_pbs.PathCurve == (byte)Extrusion.Straight) 936 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
694 { 937 {
695 if (hollowAmount > 0.0) 938 if (hollowAmount > 0.0)
696 { 939 {
697 switch (_pbs.HollowShape) 940 switch (BaseShape.HollowShape)
698 { 941 {
699 case HollowShape.Square: 942 case HollowShape.Square:
700 case HollowShape.Same: 943 case HollowShape.Same:
@@ -718,19 +961,19 @@ public sealed class BSPrim : PhysicsActor
718 } 961 }
719 } 962 }
720 963
721 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 964 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
722 { 965 {
723 //a tube 966 //a tube
724 967
725 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 968 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
726 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 969 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
727 volume -= volume*tmp*tmp; 970 volume -= volume*tmp*tmp;
728 971
729 if (hollowAmount > 0.0) 972 if (hollowAmount > 0.0)
730 { 973 {
731 hollowVolume *= hollowAmount; 974 hollowVolume *= hollowAmount;
732 975
733 switch (_pbs.HollowShape) 976 switch (BaseShape.HollowShape)
734 { 977 {
735 case HollowShape.Square: 978 case HollowShape.Square:
736 case HollowShape.Same: 979 case HollowShape.Same:
@@ -755,13 +998,13 @@ public sealed class BSPrim : PhysicsActor
755 998
756 case ProfileShape.Circle: 999 case ProfileShape.Circle:
757 1000
758 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1001 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
759 { 1002 {
760 volume *= 0.78539816339f; // elipse base 1003 volume *= 0.78539816339f; // elipse base
761 1004
762 if (hollowAmount > 0.0) 1005 if (hollowAmount > 0.0)
763 { 1006 {
764 switch (_pbs.HollowShape) 1007 switch (BaseShape.HollowShape)
765 { 1008 {
766 case HollowShape.Same: 1009 case HollowShape.Same:
767 case HollowShape.Circle: 1010 case HollowShape.Circle:
@@ -783,19 +1026,19 @@ public sealed class BSPrim : PhysicsActor
783 } 1026 }
784 } 1027 }
785 1028
786 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1029 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
787 { 1030 {
788 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 1031 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
789 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1032 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
790 volume *= (1.0f - tmp * tmp); 1033 volume *= (1.0f - tmp * tmp);
791 1034
792 if (hollowAmount > 0.0) 1035 if (hollowAmount > 0.0)
793 { 1036 {
794 1037
795 // calculate the hollow volume by it's shape compared to the prim shape 1038 // calculate the hollow volume by it's shape compared to the prim shape
796 hollowVolume *= hollowAmount; 1039 hollowVolume *= hollowAmount;
797 1040
798 switch (_pbs.HollowShape) 1041 switch (BaseShape.HollowShape)
799 { 1042 {
800 case HollowShape.Same: 1043 case HollowShape.Same:
801 case HollowShape.Circle: 1044 case HollowShape.Circle:
@@ -819,7 +1062,7 @@ public sealed class BSPrim : PhysicsActor
819 break; 1062 break;
820 1063
821 case ProfileShape.HalfCircle: 1064 case ProfileShape.HalfCircle:
822 if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1065 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
823 { 1066 {
824 volume *= 0.52359877559829887307710723054658f; 1067 volume *= 0.52359877559829887307710723054658f;
825 } 1068 }
@@ -827,7 +1070,7 @@ public sealed class BSPrim : PhysicsActor
827 1070
828 case ProfileShape.EquilateralTriangle: 1071 case ProfileShape.EquilateralTriangle:
829 1072
830 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1073 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
831 { 1074 {
832 volume *= 0.32475953f; 1075 volume *= 0.32475953f;
833 1076
@@ -835,7 +1078,7 @@ public sealed class BSPrim : PhysicsActor
835 { 1078 {
836 1079
837 // calculate the hollow volume by it's shape compared to the prim shape 1080 // calculate the hollow volume by it's shape compared to the prim shape
838 switch (_pbs.HollowShape) 1081 switch (BaseShape.HollowShape)
839 { 1082 {
840 case HollowShape.Same: 1083 case HollowShape.Same:
841 case HollowShape.Triangle: 1084 case HollowShape.Triangle:
@@ -860,11 +1103,11 @@ public sealed class BSPrim : PhysicsActor
860 volume *= (1.0f - hollowVolume); 1103 volume *= (1.0f - hollowVolume);
861 } 1104 }
862 } 1105 }
863 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1106 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
864 { 1107 {
865 volume *= 0.32475953f; 1108 volume *= 0.32475953f;
866 volume *= 0.01f * (float)(200 - _pbs.PathScaleX); 1109 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
867 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1110 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
868 volume *= (1.0f - tmp * tmp); 1111 volume *= (1.0f - tmp * tmp);
869 1112
870 if (hollowAmount > 0.0) 1113 if (hollowAmount > 0.0)
@@ -872,7 +1115,7 @@ public sealed class BSPrim : PhysicsActor
872 1115
873 hollowVolume *= hollowAmount; 1116 hollowVolume *= hollowAmount;
874 1117
875 switch (_pbs.HollowShape) 1118 switch (BaseShape.HollowShape)
876 { 1119 {
877 case HollowShape.Same: 1120 case HollowShape.Same:
878 case HollowShape.Triangle: 1121 case HollowShape.Triangle:
@@ -912,26 +1155,26 @@ public sealed class BSPrim : PhysicsActor
912 float profileBegin; 1155 float profileBegin;
913 float profileEnd; 1156 float profileEnd;
914 1157
915 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) 1158 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
916 { 1159 {
917 taperX1 = _pbs.PathScaleX * 0.01f; 1160 taperX1 = BaseShape.PathScaleX * 0.01f;
918 if (taperX1 > 1.0f) 1161 if (taperX1 > 1.0f)
919 taperX1 = 2.0f - taperX1; 1162 taperX1 = 2.0f - taperX1;
920 taperX = 1.0f - taperX1; 1163 taperX = 1.0f - taperX1;
921 1164
922 taperY1 = _pbs.PathScaleY * 0.01f; 1165 taperY1 = BaseShape.PathScaleY * 0.01f;
923 if (taperY1 > 1.0f) 1166 if (taperY1 > 1.0f)
924 taperY1 = 2.0f - taperY1; 1167 taperY1 = 2.0f - taperY1;
925 taperY = 1.0f - taperY1; 1168 taperY = 1.0f - taperY1;
926 } 1169 }
927 else 1170 else
928 { 1171 {
929 taperX = _pbs.PathTaperX * 0.01f; 1172 taperX = BaseShape.PathTaperX * 0.01f;
930 if (taperX < 0.0f) 1173 if (taperX < 0.0f)
931 taperX = -taperX; 1174 taperX = -taperX;
932 taperX1 = 1.0f - taperX; 1175 taperX1 = 1.0f - taperX;
933 1176
934 taperY = _pbs.PathTaperY * 0.01f; 1177 taperY = BaseShape.PathTaperY * 0.01f;
935 if (taperY < 0.0f) 1178 if (taperY < 0.0f)
936 taperY = -taperY; 1179 taperY = -taperY;
937 taperY1 = 1.0f - taperY; 1180 taperY1 = 1.0f - taperY;
@@ -941,13 +1184,13 @@ public sealed class BSPrim : PhysicsActor
941 1184
942 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); 1185 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
943 1186
944 pathBegin = (float)_pbs.PathBegin * 2.0e-5f; 1187 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
945 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; 1188 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
946 volume *= (pathEnd - pathBegin); 1189 volume *= (pathEnd - pathBegin);
947 1190
948 // this is crude aproximation 1191 // this is crude aproximation
949 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; 1192 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
950 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; 1193 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
951 volume *= (profileEnd - profileBegin); 1194 volume *= (profileEnd - profileBegin);
952 1195
953 returnMass = _density * volume; 1196 returnMass = _density * volume;
@@ -967,296 +1210,66 @@ public sealed class BSPrim : PhysicsActor
967 if (returnMass <= 0) 1210 if (returnMass <= 0)
968 returnMass = 0.0001f; 1211 returnMass = 0.0001f;
969 1212
970 if (returnMass > _scene.MaximumObjectMass) 1213 if (returnMass > PhysicsScene.MaximumObjectMass)
971 returnMass = _scene.MaximumObjectMass; 1214 returnMass = PhysicsScene.MaximumObjectMass;
972 1215
973 return returnMass; 1216 return returnMass;
974 }// end CalculateMass 1217 }// end CalculateMass
975 #endregion Mass Calculation 1218 #endregion Mass Calculation
976 1219
977 // Create the geometry information in Bullet for later use
978 // The objects needs a hull if it's physical otherwise a mesh is enough
979 // No locking here because this is done when we know physics is not simulating
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)
983 {
984 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
985 bool ret = false;
986 if (!_scene.NeedsMeshing(_pbs))
987 {
988 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
989 {
990 // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
991 // {
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;
1100
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)
1105 {
1106 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
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 }
1193 }
1194
1195 // create the hull definition in Bullet
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 1220 // Copy prim's info into the BulletSim shape description structure
1233 public void FillShapeInfo(out ShapeData shape) 1221 public void FillShapeInfo(out ShapeData shape)
1234 { 1222 {
1235 shape.ID = _localID; 1223 shape.ID = LocalID;
1236 shape.Type = _shapeType; 1224 shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
1237 shape.Position = _position; 1225 shape.Position = _position;
1238 shape.Rotation = _orientation; 1226 shape.Rotation = _orientation;
1239 shape.Velocity = _velocity; 1227 shape.Velocity = _velocity;
1240 shape.Scale = _scale; 1228 shape.Size = _size;
1229 shape.Scale = Scale;
1241 shape.Mass = _isPhysical ? _mass : 0f; 1230 shape.Mass = _isPhysical ? _mass : 0f;
1242 shape.Buoyancy = _buoyancy; 1231 shape.Buoyancy = _buoyancy;
1243 shape.HullKey = _hullKey; 1232 shape.HullKey = 0;
1244 shape.MeshKey = _meshKey; 1233 shape.MeshKey = 0;
1245 shape.Friction = _friction; 1234 shape.Friction = _friction;
1246 shape.Restitution = _restitution; 1235 shape.Restitution = _restitution;
1247 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; 1236 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1248 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1237 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1238 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1249 } 1239 }
1250
1251
1252 // Rebuild the geometry and object. 1240 // Rebuild the geometry and object.
1253 // This is called when the shape changes so we need to recreate the mesh/hull. 1241 // 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 1242 // Called at taint-time!!!
1255 private void RecreateGeomAndObject() 1243 private void CreateGeomAndObject(bool forceRebuild)
1256 { 1244 {
1257 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); 1245 ShapeData shapeData;
1258 if (CreateGeom(true)) 1246 FillShapeInfo(out shapeData);
1259 CreateObject(); 1247
1248 // If this prim is part of a linkset, we must remove and restore the physical
1249 // links if the body is rebuilt.
1250 bool needToRestoreLinkset = false;
1251
1252 // Create the correct physical representation for this type of object.
1253 // Updates BSBody and BSShape with the new information.
1254 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1255 // Returns 'true' if either the body or the shape was changed.
1256 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
1257 null, delegate(BulletBody dBody)
1258 {
1259 // Called if the current prim body is about to be destroyed.
1260 // Remove all the physical dependencies on the old body.
1261 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
1262 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1263 });
1264
1265 if (needToRestoreLinkset)
1266 {
1267 // If physical body dependencies were removed, restore them
1268 Linkset.RestoreBodyDependencies(this);
1269 }
1270
1271 // Make sure the properties are set on the new object
1272 UpdatePhysicalParameters();
1260 return; 1273 return;
1261 } 1274 }
1262 1275
@@ -1277,7 +1290,7 @@ public sealed class BSPrim : PhysicsActor
1277 const float ACCELERATION_TOLERANCE = 0.01f; 1290 const float ACCELERATION_TOLERANCE = 0.01f;
1278 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1291 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1279 1292
1280 public void UpdateProperties(EntityProperties entprop) 1293 public override void UpdateProperties(EntityProperties entprop)
1281 { 1294 {
1282 /* 1295 /*
1283 UpdatedProperties changed = 0; 1296 UpdatedProperties changed = 0;
@@ -1325,7 +1338,7 @@ public sealed class BSPrim : PhysicsActor
1325 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1338 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1326 1339
1327 // Updates only for individual prims and for the root object of a linkset. 1340 // Updates only for individual prims and for the root object of a linkset.
1328 if (_linkset.IsRoot(this)) 1341 if (Linkset.IsRoot(this))
1329 { 1342 {
1330 // Assign to the local variables so the normal set action does not happen 1343 // Assign to the local variables so the normal set action does not happen
1331 _position = entprop.Position; 1344 _position = entprop.Position;
@@ -1334,69 +1347,31 @@ public sealed class BSPrim : PhysicsActor
1334 _acceleration = entprop.Acceleration; 1347 _acceleration = entprop.Acceleration;
1335 _rotationalVelocity = entprop.RotationalVelocity; 1348 _rotationalVelocity = entprop.RotationalVelocity;
1336 1349
1337 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", 1350 // remember the current and last set values
1338 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1351 LastEntityProperties = CurrentEntityProperties;
1339 // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1352 CurrentEntityProperties = entprop;
1340 // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1353
1354 PositionSanityCheck(true);
1355
1356 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1357 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1358
1359 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1341 1360
1342 base.RequestPhysicsterseUpdate(); 1361 base.RequestPhysicsterseUpdate();
1343 } 1362 }
1344 /* 1363 /*
1345 else 1364 else
1346 { 1365 {
1347 // For debugging, we also report the movement of children 1366 // For debugging, report the movement of children
1348 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1367 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1349 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1368 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1350 entprop.Acceleration, entprop.RotationalVelocity); 1369 entprop.Acceleration, entprop.RotationalVelocity);
1351 } 1370 }
1352 */ 1371 */
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 1372
1370 // if someone is subscribed to collision events.... 1373 // The linkset implimentation might want to know about this.
1371 if (_subscribedEventsMs != 0) { 1374 Linkset.UpdateProperties(this);
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;
1376
1377 if (collisionCollection == null)
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);
1400 } 1375 }
1401} 1376}
1402} 1377}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..db0c99e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,33 +39,27 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Debug linkset 42// Test sculpties (verified that they don't work)
43// Test with multiple regions in one simulator
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably 43// Compute physics FPS reasonably
47// Based on material, set density and friction 44// Based on material, set density and friction
48// More efficient memory usage when passing hull information from BSPrim to BulletSim 45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
49// Move all logic out of the C++ code and into the C# code for easier future modifications.
50// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
51// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
52// At the moment, physical and phantom causes object to drop through the terrain 48// At the moment, physical and phantom causes object to drop through the terrain
53// Physical phantom objects and related typing (collision options ) 49// Physical phantom objects and related typing (collision options )
54// Use collision masks for collision with terrain and phantom objects
55// Check out llVolumeDetect. Must do something for that. 50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim
56// Should prim.link() and prim.delink() membership checking happen at taint time? 53// Should prim.link() and prim.delink() membership checking happen at taint time?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root. 54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
61// Implement LockAngularMotion 56// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
63// Does NeedsMeshing() really need to exclude all the different shapes?
64// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
65// Add PID movement operations. What does ScenePresence.MoveToTarget do? 59// Add PID movement operations. What does ScenePresence.MoveToTarget do?
66// Check terrain size. 128 or 127? 60// Check terrain size. 128 or 127?
67// Raycast 61// Raycast
68// 62//
69namespace OpenSim.Region.Physics.BulletSPlugin 63namespace OpenSim.Region.Physics.BulletSPlugin
70{ 64{
71public class BSScene : PhysicsScene, IPhysicsParameters 65public class BSScene : PhysicsScene, IPhysicsParameters
@@ -73,62 +67,56 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 68 private static readonly string LogHeader = "[BULLETS SCENE]";
75 69
76 public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } 70 // The name of the region we're working for.
71 public string RegionName { get; private set; }
77 72
78 public string BulletSimVersion = "?"; 73 public string BulletSimVersion = "?";
79 74
80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 75 public Dictionary<uint, BSPhysObject> PhysObjects;
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 76 public BSShapeCollection Shapes;
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>();
84 private List<BSPrim> m_vehicles = new List<BSPrim>();
85 private float[] m_heightMap;
86 private float m_waterLevel;
87 private uint m_worldID;
88 public uint WorldID { get { return m_worldID; } }
89 77
90 // let my minuions use my logger 78 // Keeping track of the objects with collisions so we can report begin and end of a collision
91 public ILog Logger { get { return m_log; } } 79 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
80 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
81 // Keep track of all the avatars so we can send them a collision event
82 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
92 84
93 private bool m_initialized = false; 85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
94 88
95 private int m_detailedStatsStep = 0; 89 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } }
96 91
97 public IMesher mesher; 92 public IMesher mesher;
98 private float m_meshLOD; 93 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 94 public float MeshLOD { get; private set; }
100 { 95 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 96 public float MeshMegaPrimThreshold { get; private set; }
102 } 97 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 98
109 private BulletSim m_worldSim; 99 public uint WorldID { get; private set; }
110 public BulletSim World 100 public BulletSim World { get; private set; }
111 {
112 get { return m_worldSim; }
113 }
114 private BSConstraintCollection m_constraintCollection;
115 public BSConstraintCollection Constraints
116 {
117 get { return m_constraintCollection; }
118 }
119 101
102 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; }
104
105 // Simulation parameters
120 private int m_maxSubSteps; 106 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 107 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
124 110 private int m_taintsToProcessPerStep;
125 public float LastSimulatedTimestep { get; private set; }
126 111
127 // A value of the time now so all the collision and update routines do not have to get their own 112 // A value of the time now so all the collision and update routines do not have to get their own
128 // Set to 'now' just before all the prims and actors are called for collisions and updates 113 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 114 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 115
116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false;
131 118
119 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 120 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 121 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 122 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +125,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 125 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 126 private GCHandle m_updateArrayPinnedHandle;
139 127
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 128 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
141 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes 129 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
130 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
142 131
143 public float PID_D { get; private set; } // derivative 132 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional 133 public float PID_P { get; private set; } // proportional
145 134
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 135 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 136 public const uint GROUNDPLANE_ID = 1;
137 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
138
139 private float m_waterLevel;
140 public BSTerrainManager TerrainManager { get; private set; }
148 141
149 public ConfigurationParameters Params 142 public ConfigurationParameters Params
150 { 143 {
@@ -154,13 +147,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
154 { 147 {
155 get { return new Vector3(0f, 0f, Params.gravity); } 148 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 149 }
157 150 // Just the Z value of the gravity
158 private float m_maximumObjectMass; 151 public float DefaultGravityZ
159 public float MaximumObjectMass
160 { 152 {
161 get { return m_maximumObjectMass; } 153 get { return Params.gravity; }
162 } 154 }
163 155
156 public float MaximumObjectMass { get; private set; }
157
158 // When functions in the unmanaged code must be called, it is only
159 // done at a known time just before the simulation step. The taint
160 // system saves all these function calls and executes them in
161 // order before the simulation.
164 public delegate void TaintCallback(); 162 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 163 private struct TaintCallbackEntry
166 { 164 {
@@ -172,15 +170,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 callback = c; 170 callback = c;
173 } 171 }
174 } 172 }
173 private Object _taintLock = new Object(); // lock for using the next object
175 private List<TaintCallbackEntry> _taintedObjects; 174 private List<TaintCallbackEntry> _taintedObjects;
176 private Object _taintLock = new Object();
177 175
178 // A pointer to an instance if this structure is passed to the C++ code 176 // A pointer to an instance if this structure is passed to the C++ code
177 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 178 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 179 GCHandle m_paramsHandle;
181 180
182 public bool ShouldDebugLog { get; private set; } 181 // Handle to the callback used by the unmanaged code to call into the managed code.
183 182 // Used for debug logging.
183 // Need to store the handle in a persistant variable so it won't be freed.
184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
185 185
186 // Sometimes you just have to log everything. 186 // Sometimes you just have to log everything.
@@ -189,17 +189,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private string m_physicsLoggingDir; 189 private string m_physicsLoggingDir;
190 private string m_physicsLoggingPrefix; 190 private string m_physicsLoggingPrefix;
191 private int m_physicsLoggingFileMinutes; 191 private int m_physicsLoggingFileMinutes;
192 // 'true' of the vehicle code is to log lots of details
193 public bool VehicleLoggingEnabled { get; private set; }
192 194
193 private bool m_vehicleLoggingEnabled; 195 #region Construction and Initialization
194 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
195
196 public BSScene(string identifier) 196 public BSScene(string identifier)
197 { 197 {
198 m_initialized = false; 198 m_initialized = false;
199 // we are passed the name of the region we're working for.
200 RegionName = identifier;
199 } 201 }
200 202
201 public override void Initialise(IMesher meshmerizer, IConfigSource config) 203 public override void Initialise(IMesher meshmerizer, IConfigSource config)
202 { 204 {
205 mesher = meshmerizer;
206 _taintedObjects = new List<TaintCallbackEntry>();
207 PhysObjects = new Dictionary<uint, BSPhysObject>();
208 Shapes = new BSShapeCollection(this);
209
203 // Allocate pinned memory to pass parameters. 210 // Allocate pinned memory to pass parameters.
204 m_params = new ConfigurationParameters[1]; 211 m_params = new ConfigurationParameters[1];
205 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 212 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,7 +222,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 222
216 // Enable very detailed logging. 223 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 224 // By creating an empty logger when not logging, the log message invocation code
218 // can be left in and every call doesn't have to check for null. 225 // can be left in and every call doesn't have to check for null.
219 if (m_physicsLoggingEnabled) 226 if (m_physicsLoggingEnabled)
220 { 227 {
221 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 228 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -225,38 +232,39 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 232 PhysicsLogging = new Logging.LogWriter();
226 } 233 }
227 234
228 // Get the version of the DLL 235 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 236 m_DebugLogCallbackHandle = null;
230 // BulletSimVersion = BulletSimAPI.GetVersion();
231 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
232
233 // if Debug, enable logging from the unmanaged code
234 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 237 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 238 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 239 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 240 if (PhysicsLogging.Enabled)
241 // The handle is saved in a variable to make sure it doesn't get freed after this call
238 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); 242 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 243 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 244 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
241 // the handle is saved in a variable to make sure it doesn't get freed after this call
242 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
243 } 245 }
244 246
245 _taintedObjects = new List<TaintCallbackEntry>(); 247 // Get the version of the DLL
248 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
249 // BulletSimVersion = BulletSimAPI.GetVersion();
250 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 251
247 mesher = meshmerizer; 252 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 253 // a child in a mega-region.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 254 // Bullet actually doesn't care about the extents of the simulated
255 // area. It tracks active objects no matter where they are.
256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
250 257
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 258 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 259 World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 260 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 261 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
262 m_DebugLogCallbackHandle));
263
264 Constraints = new BSConstraintCollection(World);
255 265
256 // Initialization to support the transition to a new API which puts most of the logic 266 TerrainManager = new BSTerrainManager(this);
257 // into the C# code so it is easier to modify and add to. 267 TerrainManager.CreateInitialGroundPlaneAndTerrain();
258 m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID));
259 m_constraintCollection = new BSConstraintCollection(World);
260 268
261 m_initialized = true; 269 m_initialized = true;
262 } 270 }
@@ -281,10 +289,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 289 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 290 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 291 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 292 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 293 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 294 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 295 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
296
297 // Do any replacements in the parameters
298 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 299 }
289 } 300 }
290 } 301 }
@@ -309,13 +320,51 @@ public class BSScene : PhysicsScene, IPhysicsParameters
309 { 320 {
310 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 321 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
311 } 322 }
312 323
313 // Called directly from unmanaged code so don't do much 324 // Called directly from unmanaged code so don't do much
314 private void BulletLoggerPhysLog(string msg) 325 private void BulletLoggerPhysLog(string msg)
315 { 326 {
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 327 DetailLog("[BULLETS UNMANAGED]:" + msg);
317 } 328 }
318 329
330 public override void Dispose()
331 {
332 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
333
334 // make sure no stepping happens while we're deleting stuff
335 m_initialized = false;
336
337 TerrainManager.ReleaseGroundPlaneAndTerrain();
338
339 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
340 {
341 kvp.Value.Destroy();
342 }
343 PhysObjects.Clear();
344
345 // Now that the prims are all cleaned up, there should be no constraints left
346 if (Constraints != null)
347 {
348 Constraints.Dispose();
349 Constraints = null;
350 }
351
352 if (Shapes != null)
353 {
354 Shapes.Dispose();
355 Shapes = null;
356 }
357
358 // Anything left in the unmanaged code should be cleaned out
359 BulletSimAPI.Shutdown2(World.ptr);
360
361 // Not logging any more
362 PhysicsLogging.Close();
363 }
364 #endregion // Construction and Initialization
365
366 #region Prim and Avatar addition and removal
367
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 368 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 369 {
321 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 370 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -329,7 +378,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 378 if (!m_initialized) return null;
330 379
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 380 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 381 lock (PhysObjects) PhysObjects.Add(localID, actor);
382
383 // TODO: Remove kludge someday.
384 // We must generate a collision for avatars whether they collide or not.
385 // This is required by OpenSim to update avatar animations, etc.
386 lock (m_avatars) m_avatars.Add(actor);
387
333 return actor; 388 return actor;
334 } 389 }
335 390
@@ -344,7 +399,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 399 {
345 try 400 try
346 { 401 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 402 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
403 // Remove kludge someday
404 lock (m_avatars) m_avatars.Remove(bsactor);
348 } 405 }
349 catch (Exception e) 406 catch (Exception e)
350 { 407 {
@@ -362,11 +419,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 419 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 420 if (bsprim != null)
364 { 421 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 422 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 423 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 424 try
368 { 425 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 426 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 427 }
371 catch (Exception e) 428 catch (Exception e)
372 { 429 {
@@ -388,18 +445,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 445
389 if (!m_initialized) return null; 446 if (!m_initialized) return null;
390 447
391 // DetailLog("{0},AddPrimShape,call", localID); 448 DetailLog("{0},AddPrimShape,call", localID);
392 449
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 450 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 451 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 452 return prim;
396 } 453 }
397 454
398 // This is a call from the simulator saying that some physical property has been updated. 455 // This is a call from the simulator saying that some physical property has been updated.
399 // The BulletSim driver senses the changing of relevant properties so this taint 456 // The BulletSim driver senses the changing of relevant properties so this taint
400 // information call is not needed. 457 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 458 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 459
460 #endregion // Prim and Avatar addition and removal
461
462 #region Simulation
403 // Simulate one timestep 463 // Simulate one timestep
404 public override float Simulate(float timeStep) 464 public override float Simulate(float timeStep)
405 { 465 {
@@ -408,34 +468,46 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 468 int collidersCount = 0;
409 IntPtr collidersPtr; 469 IntPtr collidersPtr;
410 470
411 LastSimulatedTimestep = timeStep; 471 int beforeTime = 0;
472 int simTime = 0;
412 473
413 // prevent simulation until we've been initialized 474 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 475 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 476
418 // update the prim states while we know the physics engine is not busy 477 // update the prim states while we know the physics engine is not busy
478 int numTaints = _taintedObjects.Count;
419 ProcessTaints(); 479 ProcessTaints();
420 480
421 // Some of the prims operate with special vehicle properties 481 // Some of the prims operate with special vehicle properties
422 ProcessVehicles(timeStep); 482 ProcessVehicles(timeStep);
483 numTaints += _taintedObjects.Count;
423 ProcessTaints(); // the vehicles might have added taints 484 ProcessTaints(); // the vehicles might have added taints
424 485
425 // step the physical world one interval 486 // step the physical world one interval
426 m_simulationStep++; 487 m_simulationStep++;
427 int numSubSteps = 0; 488 int numSubSteps = 0;
489
490 // DEBUG
491 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
492
428 try 493 try
429 { 494 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 495 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
496
497 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 498 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 499
500 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
501 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
502 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
433 } 503 }
434 catch (Exception e) 504 catch (Exception e)
435 { 505 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 506 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
437 // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 507 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 508 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
509 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
510 updatedEntityCount = 0;
439 collidersCount = 0; 511 collidersCount = 0;
440 } 512 }
441 513
@@ -443,7 +515,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
443 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 515 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 516
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 517 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 518 SimulationNowTime = Util.EnvironmentTickCount();
447 519
448 // If there were collisions, process them by sending the event to the prim. 520 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 521 // Collisions must be processed before updates.
@@ -462,19 +534,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
462 534
463 // The above SendCollision's batch up the collisions on the objects. 535 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 536 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 537 if (ObjectsWithCollisions.Count > 0)
466 bsp.SendCollisions(); 538 {
467 m_primsWithCollisions.Clear(); 539 foreach (BSPhysObject bsp in ObjectsWithCollisions)
468 540 if (!bsp.SendCollisions())
469 // This is a kludge to get avatar movement updated. 541 {
470 // Don't send collisions only if there were collisions -- send everytime. 542 // If the object is done colliding, see that it's removed from the colliding list
471 // ODE sends collisions even if there are none and this is used to update 543 ObjectsWithNoMoreCollisions.Add(bsp);
472 // avatar animations and stuff. 544 }
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 545 }
474 // bsc.SendCollisions(); 546
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 547 // This is a kludge to get avatar movement updates.
476 kvp.Value.SendCollisions(); 548 // The simulator expects collisions for avatars even if there are have been no collisions.
477 m_avatarsWithCollisions.Clear(); 549 // The event updates avatar animations and stuff.
550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
551 foreach (BSPhysObject bsp in m_avatars)
552 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
553 bsp.SendCollisions();
554
555 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
556 // Not done above because it is inside an iteration of ObjectWithCollisions.
557 if (ObjectsWithNoMoreCollisions.Count > 0)
558 {
559 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
560 ObjectsWithCollisions.Remove(po);
561 ObjectsWithNoMoreCollisions.Clear();
562 }
478 563
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 564 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 565 if (updatedEntityCount > 0)
@@ -482,145 +567,102 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 567 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 568 {
484 EntityProperties entprop = m_updateArray[ii]; 569 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 570 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 571 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
487 { 572 {
488 prim.UpdateProperties(entprop); 573 pobj.UpdateProperties(entprop);
489 continue;
490 }
491 BSCharacter actor;
492 if (m_avatars.TryGetValue(entprop.ID, out actor))
493 {
494 actor.UpdateProperties(entprop);
495 continue;
496 } 574 }
497 } 575 }
498 } 576 }
499 577
500 // If enabled, call into the physics engine to dump statistics 578 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
501 if (m_detailedStatsStep > 0) 579 // Only enable this in a limited test world with few objects.
502 { 580 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
503 if ((m_simulationStep % m_detailedStatsStep) == 0)
504 {
505 BulletSimAPI.DumpBulletStatistics();
506 }
507 }
508 581
509 // this is a waste since the outside routine also calcuates the physics simulation 582 // The physics engine returns the number of milliseconds it simulated this call.
510 // period. TODO: There should be a way of computing physics frames from simulator computation. 583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); 584 // We multiply by 55 to give a recognizable running rate (55 or less).
512 // return (timeStep * (float)simulateTotalTime); 585 return numSubSteps * m_fixedTimeStep * 1000 * 55;
513 586 // return timeStep * 1000 * 55;
514 // TODO: FIX THIS: fps calculation possibly wrong.
515 // This calculation says 1/timeStep is the ideal frame rate. Any time added to
516 // that by the physics simulation gives a slower frame rate.
517 long totalSimulationTime = Util.EnvironmentTickCountSubtract(simulateStartTime);
518 if (totalSimulationTime >= timeStep)
519 return 0;
520 return 1f / (timeStep + totalSimulationTime);
521 } 587 }
522 588
523 // Something has collided 589 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 590 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 591 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 592 if (localID <= TerrainManager.HighestTerrainID)
527 { 593 {
528 return; // don't send collisions to the terrain 594 return; // don't send collisions to the terrain
529 } 595 }
530 596
531 ActorTypes type = ActorTypes.Prim; 597 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 598 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 599 {
534 else if (m_avatars.ContainsKey(collidingWith)) 600 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent; 601 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
536
537 BSPrim prim;
538 if (m_prims.TryGetValue(localID, out prim)) {
539 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
540 m_primsWithCollisions.Add(prim);
541 return; 602 return;
542 } 603 }
543 BSCharacter actor; 604
544 if (m_avatars.TryGetValue(localID, out actor)) { 605 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
545 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 606 BSPhysObject collidee = null;
546 m_avatarsWithCollisions.Add(actor); 607 PhysObjects.TryGetValue(collidingWith, out collidee);
547 return; 608
609 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
610
611 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
612 {
613 // If a collision was posted, remember to send it to the simulator
614 ObjectsWithCollisions.Add(collider);
548 } 615 }
616
549 return; 617 return;
550 } 618 }
551 619
552 public override void GetResults() { } 620 #endregion // Simulation
553 621
554 public override void SetTerrain(float[] heightMap) { 622 public override void GetResults() { }
555 m_heightMap = heightMap;
556 this.TaintedObject("BSScene.SetTerrain", delegate()
557 {
558 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
559 });
560 }
561 623
562 // Someday we will have complex terrain with caves and tunnels 624 #region Terrain
563 // For the moment, it's flat and convex
564 public float GetTerrainHeightAtXYZ(Vector3 loc)
565 {
566 return GetTerrainHeightAtXY(loc.X, loc.Y);
567 }
568 625
569 public float GetTerrainHeightAtXY(float tX, float tY) 626 public override void SetTerrain(float[] heightMap) {
570 { 627 TerrainManager.SetTerrain(heightMap);
571 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
572 return 30;
573 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
574 } 628 }
575 629
576 public override void SetWaterLevel(float baseheight) 630 public override void SetWaterLevel(float baseheight)
577 { 631 {
578 m_waterLevel = baseheight; 632 m_waterLevel = baseheight;
579 // TODO: pass to physics engine so things will float?
580 } 633 }
581 public float GetWaterLevel() 634 // Someday....
635 public float GetWaterLevelAtXYZ(Vector3 loc)
582 { 636 {
583 return m_waterLevel; 637 return m_waterLevel;
584 } 638 }
585 639
586 public override void DeleteTerrain() 640 public override void DeleteTerrain()
587 { 641 {
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 642 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
589 } 643 }
590 644
591 public override void Dispose() 645 // Although no one seems to check this, I do support combining.
646 public override bool SupportsCombining()
592 { 647 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 648 return TerrainManager.SupportsCombining();
594 649 }
595 // make sure no stepping happens while we're deleting stuff 650 // This call says I am a child to region zero in a mega-region. 'pScene' is that
596 m_initialized = false; 651 // of region zero, 'offset' is my offset from regions zero's origin, and
597 652 // 'extents' is the largest XY that is handled in my region.
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 653 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
599 { 654 {
600 kvp.Value.Destroy(); 655 TerrainManager.Combine(pScene, offset, extents);
601 } 656 }
602 m_avatars.Clear();
603
604 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
605 {
606 kvp.Value.Destroy();
607 }
608 m_prims.Clear();
609
610 // Now that the prims are all cleaned up, there should be no constraints left
611 if (m_constraintCollection != null)
612 {
613 m_constraintCollection.Dispose();
614 m_constraintCollection = null;
615 }
616
617 // Anything left in the unmanaged code should be cleaned out
618 BulletSimAPI.Shutdown(WorldID);
619 657
620 // Not logging any more 658 // Unhook all the combining that I know about.
621 PhysicsLogging.Close(); 659 public override void UnCombine(PhysicsScene pScene)
660 {
661 TerrainManager.UnCombine(pScene);
622 } 662 }
623 663
664 #endregion // Terrain
665
624 public override Dictionary<uint, float> GetTopColliders() 666 public override Dictionary<uint, float> GetTopColliders()
625 { 667 {
626 return new Dictionary<uint, float>(); 668 return new Dictionary<uint, float>();
@@ -628,121 +670,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
628 670
629 public override bool IsThreaded { get { return false; } } 671 public override bool IsThreaded { get { return false; } }
630 672
631 /// <summary>
632 /// Routine to figure out if we need to mesh this prim with our mesher
633 /// </summary>
634 /// <param name="pbs"></param>
635 /// <returns>true if the prim needs meshing</returns>
636 public bool NeedsMeshing(PrimitiveBaseShape pbs)
637 {
638 // most of this is redundant now as the mesher will return null if it cant mesh a prim
639 // but we still need to check for sculptie meshing being enabled so this is the most
640 // convenient place to do it for now...
641
642 // int iPropertiesNotSupportedDefault = 0;
643
644 if (pbs.SculptEntry && !_meshSculptedPrim)
645 {
646 // Render sculpties as boxes
647 return false;
648 }
649
650 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
651 // can use an internal representation for the prim
652 if (!_forceSimplePrimMeshing)
653 {
654 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
655 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
656 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
657 {
658
659 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
660 && pbs.ProfileHollow == 0
661 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
662 && pbs.PathBegin == 0 && pbs.PathEnd == 0
663 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
664 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
665 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
666 {
667 return false;
668 }
669 }
670 }
671
672 /* TODO: verify that the mesher will now do all these shapes
673 if (pbs.ProfileHollow != 0)
674 iPropertiesNotSupportedDefault++;
675
676 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
677 iPropertiesNotSupportedDefault++;
678
679 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
680 iPropertiesNotSupportedDefault++;
681
682 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
683 iPropertiesNotSupportedDefault++;
684
685 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
686 iPropertiesNotSupportedDefault++;
687
688 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
689 iPropertiesNotSupportedDefault++;
690
691 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
692 iPropertiesNotSupportedDefault++;
693
694 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
695 iPropertiesNotSupportedDefault++;
696
697 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
698 iPropertiesNotSupportedDefault++;
699
700 // test for torus
701 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
702 {
703 if (pbs.PathCurve == (byte)Extrusion.Curve1)
704 {
705 iPropertiesNotSupportedDefault++;
706 }
707 }
708 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
709 {
710 if (pbs.PathCurve == (byte)Extrusion.Straight)
711 {
712 iPropertiesNotSupportedDefault++;
713 }
714 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
715 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
716 {
717 iPropertiesNotSupportedDefault++;
718 }
719 }
720 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
721 {
722 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
723 {
724 iPropertiesNotSupportedDefault++;
725 }
726 }
727 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
728 {
729 if (pbs.PathCurve == (byte)Extrusion.Straight)
730 {
731 iPropertiesNotSupportedDefault++;
732 }
733 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
734 {
735 iPropertiesNotSupportedDefault++;
736 }
737 }
738 if (iPropertiesNotSupportedDefault == 0)
739 {
740 return false;
741 }
742 */
743 return true;
744 }
745
746 // Calls to the PhysicsActors can't directly call into the physics engine 673 // Calls to the PhysicsActors can't directly call into the physics engine
747 // because it might be busy. We delay changes to a known time. 674 // because it might be busy. We delay changes to a known time.
748 // We rely on C#'s closure to save and restore the context for the delegate. 675 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -751,7 +678,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
751 if (!m_initialized) return; 678 if (!m_initialized) return;
752 679
753 lock (_taintLock) 680 lock (_taintLock)
681 {
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 682 _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
683 }
684
755 return; 685 return;
756 } 686 }
757 687
@@ -762,6 +692,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
762 { 692 {
763 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
764 { 694 {
695 int taintCount = m_taintsToProcessPerStep;
696 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
697 while (_taintedObjects.Count > 0 && taintCount-- > 0)
698 {
699 bool gotOne = false;
700 lock (_taintLock)
701 {
702 if (_taintedObjects.Count > 0)
703 {
704 oneCallback = _taintedObjects[0];
705 _taintedObjects.RemoveAt(0);
706 gotOne = true;
707 }
708 }
709 if (gotOne)
710 {
711 try
712 {
713 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
714 oneCallback.callback();
715 }
716 catch (Exception e)
717 {
718 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 }
721 }
722 }
723 /*
765 // swizzle a new list into the list location so we can process what's there 724 // swizzle a new list into the list location so we can process what's there
766 List<TaintCallbackEntry> oldList; 725 List<TaintCallbackEntry> oldList;
767 lock (_taintLock) 726 lock (_taintLock)
@@ -774,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
774 { 733 {
775 try 734 try
776 { 735 {
736 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
777 tcbe.callback(); 737 tcbe.callback();
778 } 738 }
779 catch (Exception e) 739 catch (Exception e)
@@ -782,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
782 } 742 }
783 } 743 }
784 oldList.Clear(); 744 oldList.Clear();
745 */
785 } 746 }
786 } 747 }
787 748
@@ -789,13 +750,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
789 750
790 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 751 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
791 { 752 {
792 if (newType == Vehicle.TYPE_NONE) 753 RemoveVehiclePrim(vehic);
793 { 754 if (newType != Vehicle.TYPE_NONE)
794 RemoveVehiclePrim(vehic);
795 }
796 else
797 { 755 {
798 // make it so the scene will call us each tick to do vehicle things 756 // make it so the scene will call us each tick to do vehicle things
799 AddVehiclePrim(vehic); 757 AddVehiclePrim(vehic);
800 } 758 }
801 } 759 }
@@ -827,21 +785,22 @@ public class BSScene : PhysicsScene, IPhysicsParameters
827 } 785 }
828 786
829 // Some prims have extra vehicle actions 787 // Some prims have extra vehicle actions
830 // no locking because only called when physics engine is not busy 788 // Called at taint time!
831 private void ProcessVehicles(float timeStep) 789 private void ProcessVehicles(float timeStep)
832 { 790 {
833 foreach (BSPrim prim in m_vehicles) 791 foreach (BSPhysObject pobj in m_vehicles)
834 { 792 {
835 prim.StepVehicle(timeStep); 793 pobj.StepVehicle(timeStep);
836 } 794 }
837 } 795 }
838 #endregion Vehicles 796 #endregion Vehicles
839 797
840 #region Parameters 798 #region INI and command line parameter processing
841 799
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 800 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 801 delegate float ParamGet(BSScene scene);
844 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); 802 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
803 delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
845 804
846 private struct ParameterDefn 805 private struct ParameterDefn
847 { 806 {
@@ -851,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
851 public ParamUser userParam; // get the value from the configuration file 810 public ParamUser userParam; // get the value from the configuration file
852 public ParamGet getter; // return the current value stored for this parameter 811 public ParamGet getter; // return the current value stored for this parameter
853 public ParamSet setter; // set the current value for this parameter 812 public ParamSet setter; // set the current value for this parameter
813 public SetOnObject onObject; // set the value on an object in the physical domain
854 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) 814 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
855 { 815 {
856 name = n; 816 name = n;
@@ -859,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
859 userParam = u; 819 userParam = u;
860 getter = g; 820 getter = g;
861 setter = s; 821 setter = s;
822 onObject = null;
823 }
824 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
825 {
826 name = n;
827 desc = d;
828 defaultValue = v;
829 userParam = u;
830 getter = g;
831 setter = s;
832 onObject = o;
862 } 833 }
863 } 834 }
864 835
@@ -869,7 +840,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
869 // getters and setters. 840 // getters and setters.
870 // It is easiest to find an existing definition and copy it. 841 // It is easiest to find an existing definition and copy it.
871 // Parameter values are floats. Booleans are converted to a floating value. 842 // Parameter values are floats. Booleans are converted to a floating value.
872 // 843 //
873 // A ParameterDefn() takes the following parameters: 844 // A ParameterDefn() takes the following parameters:
874 // -- the text name of the parameter. This is used for console input and ini file. 845 // -- the text name of the parameter. This is used for console input and ini file.
875 // -- a short text description of the parameter. This shows up in the console listing. 846 // -- a short text description of the parameter. This shows up in the console listing.
@@ -880,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
880 // 851 //
881 // The single letter parameters for the delegates are: 852 // The single letter parameters for the delegates are:
882 // s = BSScene 853 // s = BSScene
854 // o = BSPhysObject
883 // p = string parameter name 855 // p = string parameter name
884 // l = localID of referenced object 856 // l = localID of referenced object
885 // v = float value 857 // v = float value
@@ -888,25 +860,40 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 860 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 861 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 862 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 863 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 864 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 865 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 866 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 867 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 868 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 869 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 870 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
871 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
872 ConfigurationParameters.numericTrue,
873 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
874 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
875 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
899 876
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 877 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 878 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 879 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 880 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 881 (s,p,l,v) => { s.MeshLOD = v; } ),
905 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", 882 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
883 16f,
884 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
885 (s) => { return s.MeshMegaPrimLOD; },
886 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
887 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
888 10f,
889 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
890 (s) => { return s.MeshMegaPrimThreshold; },
891 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
892 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 893 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 894 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 895 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 896 (s,p,l,v) => { s.SculptLOD = v; } ),
910 897
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 898 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 899 10f,
@@ -928,11 +915,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
928 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 915 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
929 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 916 (s) => { return (float)s.m_maxUpdatesPerFrame; },
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 917 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
918 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
919 100f,
920 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
921 (s) => { return (float)s.m_taintsToProcessPerStep; },
922 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 923 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 924 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 925 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 926 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 927 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 928
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 929 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 930 2200f,
@@ -969,104 +961,118 @@ public class BSScene : PhysicsScene, IPhysicsParameters
969 -9.80665f, 961 -9.80665f,
970 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, 962 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].gravity; }, 963 (s) => { return s.m_params[0].gravity; },
972 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), 964 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
965 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
973 966
974 967
975 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", 968 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
976 0f, 969 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 970 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 971 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
973 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
980 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 974 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 975 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 976 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 977 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 978 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
979 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
985 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 980 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 981 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 982 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 983 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 984 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
985 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ),
990 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 986 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 987 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 988 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 989 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 990 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
991 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
995 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 992 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 993 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 994 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 995 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 996 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
997 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
1000 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 998 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 999 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 1000 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 1001 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 1002 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1003 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 1004 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 1005 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 1006 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 1007 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 1008 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1009 (s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 1011 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 1013 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 1014 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1015 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ),
1015 1016
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1017 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 1018 0.5f,
1018 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1019 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1019 (s) => { return s.m_params[0].terrainFriction; }, 1020 (s) => { return s.m_params[0].terrainFriction; },
1020 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), 1021 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
1021 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , 1022 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
1022 0.8f, 1023 0.8f,
1023 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, 1024 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
1024 (s) => { return s.m_params[0].terrainHitFraction; }, 1025 (s) => { return s.m_params[0].terrainHitFraction; },
1025 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), 1026 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
1026 new ParameterDefn("TerrainRestitution", "Bouncyness" , 1027 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
1027 0f, 1028 0f,
1028 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1029 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1029 (s) => { return s.m_params[0].terrainRestitution; }, 1030 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 1031 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1031 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1032 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 1033 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1034 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 1035 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 1036 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1037 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1038 10f,
1039 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1040 (s) => { return s.m_params[0].avatarStandingFriction; },
1041 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
1036 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 1042 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 1043 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 1044 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 1045 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 1046 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 1047 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 1048 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 1049 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 1050 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 1051 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1046 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", 1052 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1047 0.37f, 1053 0.37f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 1054 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 1055 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 1056 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
1051 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 1057 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 1058 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1059 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 1060 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 1061 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1056 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 1062 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 1063 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 1064 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1065 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1066 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 1067
1062 1068
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1069 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1064 0f, // zero to disable 1070 0f,
1065 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, 1071 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, 1072 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1067 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), 1073 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1068 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", 1074 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1069 0f, // zero to disable 1075 0f,
1070 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, 1076 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, 1077 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1072 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), 1078 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
@@ -1081,12 +1087,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1081 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, 1087 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1082 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), 1088 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1083 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", 1089 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1084 ConfigurationParameters.numericFalse, 1090 ConfigurationParameters.numericTrue,
1085 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1091 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1086 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, 1092 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1087 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1093 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1088 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1094 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1089 ConfigurationParameters.numericFalse, 1095 ConfigurationParameters.numericTrue,
1090 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1096 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1091 (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, 1097 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1092 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1098 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1121,28 +1127,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1127 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1128 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1129 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1124 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0", 1130 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1131 0.001f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1132 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1133 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1134 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1129 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1135 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1130 0.2f, 1136 0.8f,
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1137 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1138 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1139 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1140 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1141 40,
1142 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1143 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1144 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1145
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1146 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1147 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1148 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1149 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1150 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1140 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1141 ConfigurationParameters.numericFalse,
1142 (s,cf,p,v) => { s.ShouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1143 (s) => { return s.NumericBool(s.ShouldDebugLog); },
1144 (s,p,l,v) => { s.ShouldDebugLog = s.BoolNumeric(v); } ),
1145
1146 }; 1151 };
1147 1152
1148 // Convert a boolean to our numeric true and false values 1153 // Convert a boolean to our numeric true and false values
@@ -1200,11 +1205,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1205
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1206 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1207
1208 // This creates an array in the correct format for returning the list of
1209 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1210 private void BuildParameterTable()
1204 { 1211 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1212 if (SettableParameters.Length < ParameterDefinitions.Length)
1206 { 1213 {
1207
1208 List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); 1214 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1209 for (int ii = 0; ii < ParameterDefinitions.Length; ii++) 1215 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1210 { 1216 {
@@ -1249,60 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1249 return ret; 1255 return ret;
1250 } 1256 }
1251 1257
1252 // check to see if we are updating a parameter for a particular or all of the prims
1253 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
1254 {
1255 List<uint> operateOn;
1256 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
1257 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1258 }
1259
1260 // check to see if we are updating a parameter for a particular or all of the avatars
1261 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
1262 {
1263 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 }
1267
1268 // update all the localIDs specified 1258 // update all the localIDs specified
1269 // If the local ID is APPLY_TO_NONE, just change the default value 1259 // If the local ID is APPLY_TO_NONE, just change the default value
1270 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1260 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1271 // If the localID is a specific object, apply the parameter change to only that object 1261 // If the localID is a specific object, apply the parameter change to only that object
1272 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) 1262 protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
1273 { 1263 {
1264 List<uint> objectIDs = new List<uint>();
1274 switch (localID) 1265 switch (localID)
1275 { 1266 {
1276 case PhysParameterEntry.APPLY_TO_NONE: 1267 case PhysParameterEntry.APPLY_TO_NONE:
1277 defaultLoc = val; // setting only the default value 1268 defaultLoc = val; // setting only the default value
1269 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1270 objectIDs.Add(TERRAIN_ID);
1271 TaintedUpdateParameter(parm, objectIDs, val);
1278 break; 1272 break;
1279 case PhysParameterEntry.APPLY_TO_ALL: 1273 case PhysParameterEntry.APPLY_TO_ALL:
1280 defaultLoc = val; // setting ALL also sets the default value 1274 defaultLoc = val; // setting ALL also sets the default value
1281 List<uint> objectIDs = lIDs; 1275 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1282 string xparm = parm.ToLower(); 1276 TaintedUpdateParameter(parm, objectIDs, val);
1283 float xval = val;
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs)
1286 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
1288 }
1289 });
1290 break; 1277 break;
1291 default: 1278 default:
1292 // setting only one localID 1279 // setting only one localID
1293 TaintedUpdateParameter(parm, localID, val); 1280 objectIDs.Add(localID);
1281 TaintedUpdateParameter(parm, objectIDs, val);
1294 break; 1282 break;
1295 } 1283 }
1296 } 1284 }
1297 1285
1298 // schedule the actual updating of the paramter to when the phys engine is not busy 1286 // schedule the actual updating of the paramter to when the phys engine is not busy
1299 protected void TaintedUpdateParameter(string parm, uint localID, float val) 1287 protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
1300 { 1288 {
1301 uint xlocalID = localID;
1302 string xparm = parm.ToLower();
1303 float xval = val; 1289 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1290 List<uint> xlIDs = lIDs;
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1291 string xparm = parm;
1292 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1293 ParameterDefn thisParam;
1294 if (TryGetParameter(xparm, out thisParam))
1295 {
1296 if (thisParam.onObject != null)
1297 {
1298 foreach (uint lID in xlIDs)
1299 {
1300 BSPhysObject theObject = null;
1301 PhysObjects.TryGetValue(lID, out theObject);
1302 thisParam.onObject(this, theObject, xval);
1303 }
1304 }
1305 }
1306 }); 1306 });
1307 } 1307 }
1308 1308
@@ -1330,8 +1330,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1330 public void DetailLog(string msg, params Object[] args) 1330 public void DetailLog(string msg, params Object[] args)
1331 { 1331 {
1332 PhysicsLogging.Write(msg, args); 1332 PhysicsLogging.Write(msg, args);
1333 // Add the Flush() if debugging crashes to get all the messages written out.
1334 // PhysicsLogging.Flush();
1333 } 1335 }
1334 // used to fill in the LocalID when there isn't one 1336 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1335 public const string DetailLogZero = "0000000000"; 1337 public const string DetailLogZero = "0000000000";
1336 1338
1337} 1339}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
new file mode 100755
index 0000000..30fa50a
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -0,0 +1,833 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSShapeCollection : IDisposable
38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 protected BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public IntPtr ptr;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 }
52
53 // Description of a hull.
54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
55 private struct HullDesc
56 {
57 public IntPtr ptr;
58 public int referenceCount;
59 public DateTime lastReferenced;
60 }
61
62 // The sharable set of meshes and hulls. Indexed by their shape hash.
63 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
64 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
65
66 public BSShapeCollection(BSScene physScene)
67 {
68 PhysicsScene = physScene;
69 }
70
71 public void Dispose()
72 {
73 // TODO!!!!!!!!!
74 }
75
76 // Callbacks called just before either the body or shape is destroyed.
77 // Mostly used for changing bodies out from under Linksets.
78 // Useful for other cases where parameters need saving.
79 // Passing 'null' says no callback.
80 public delegate void ShapeDestructionCallback(BulletShape shape);
81 public delegate void BodyDestructionCallback(BulletBody body);
82
83 // Called to update/change the body and shape for an object.
84 // First checks the shape and updates that if necessary then makes
85 // sure the body is of the right type.
86 // Return 'true' if either the body or the shape changed.
87 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
88 // the current shape or body is destroyed. This allows the caller to remove any
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed.
91 // Called at taint-time!!
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeData shapeData, PrimitiveBaseShape pbs,
94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
95 {
96 bool ret = false;
97
98 // This lock could probably be pushed down lower but building shouldn't take long
99 lock (m_collectionActivityLock)
100 {
101 // Do we have the correct geometry for this type of object?
102 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape.
104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
105 // If we had to select a new shape geometry for the object,
106 // rebuild the body around it.
107 // Updates prim.BSBody with information/pointers to requested body
108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
109 prim.BSShape, shapeData, bodyCallback);
110 ret = newGeom || newBody;
111 }
112 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
113 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
114
115 return ret;
116 }
117
118 // Track another user of a body
119 // We presume the caller has allocated the body.
120 // Bodies only have one user so the body is just put into the world if not already there.
121 public void ReferenceBody(BulletBody body, bool inTaintTime)
122 {
123 lock (m_collectionActivityLock)
124 {
125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
126 BSScene.TaintCallback createOperation = delegate()
127 {
128 if (!BulletSimAPI.IsInWorld2(body.ptr))
129 {
130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
132 }
133 };
134 if (inTaintTime)
135 createOperation();
136 else
137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
138 }
139 }
140
141 // Release the usage of a body.
142 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
144 {
145 if (body.ptr == IntPtr.Zero)
146 return;
147
148 lock (m_collectionActivityLock)
149 {
150 BSScene.TaintCallback removeOperation = delegate()
151 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
153 body.ID, body.ptr.ToString("X"), inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body);
156
157 // It may have already been removed from the world in which case the next is a NOOP.
158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
159
160 // Zero any reference to the shape so it is not freed when the body is deleted.
161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
163 };
164 // If already in taint-time, do the operations now. Otherwise queue for later.
165 if (inTaintTime)
166 removeOperation();
167 else
168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
169 }
170 }
171
172 // Track the datastructures and use count for a shape.
173 // When creating a hull, this is called first to reference the mesh
174 // and then again to reference the hull.
175 // Meshes and hulls for the same shape have the same hash key.
176 // NOTE that native shapes are not added to the mesh list or removed.
177 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
178 private bool ReferenceShape(BulletShape shape)
179 {
180 bool ret = false;
181 switch (shape.type)
182 {
183 case ShapeData.PhysicsShapeType.SHAPE_MESH:
184 MeshDesc meshDesc;
185 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
186 {
187 // There is an existing instance of this mesh.
188 meshDesc.referenceCount++;
189 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
190 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
191 }
192 else
193 {
194 // This is a new reference to a mesh
195 meshDesc.ptr = shape.ptr;
196 // We keep a reference to the underlying IMesh data so a hull can be built
197 meshDesc.referenceCount = 1;
198 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
199 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
200 ret = true;
201 }
202 meshDesc.lastReferenced = System.DateTime.Now;
203 Meshes[shape.shapeKey] = meshDesc;
204 break;
205 case ShapeData.PhysicsShapeType.SHAPE_HULL:
206 HullDesc hullDesc;
207 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
208 {
209 // There is an existing instance of this hull.
210 hullDesc.referenceCount++;
211 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
212 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
213 }
214 else
215 {
216 // This is a new reference to a hull
217 hullDesc.ptr = shape.ptr;
218 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true;
222
223 }
224 hullDesc.lastReferenced = System.DateTime.Now;
225 Hulls[shape.shapeKey] = hullDesc;
226 break;
227 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
228 break;
229 default:
230 // Native shapes are not tracked and they don't go into any list
231 break;
232 }
233 return ret;
234 }
235
236 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
238 {
239 if (shape.ptr == IntPtr.Zero)
240 return;
241
242 BSScene.TaintCallback dereferenceOperation = delegate()
243 {
244 if (shape.ptr != IntPtr.Zero)
245 {
246 if (shape.isNativeShape)
247 {
248 // Native shapes are not tracked and are released immediately
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
253 }
254 else
255 {
256 switch (shape.type)
257 {
258 case ShapeData.PhysicsShapeType.SHAPE_HULL:
259 DereferenceHull(shape, shapeCallback);
260 break;
261 case ShapeData.PhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback);
263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
265 break;
266 default:
267 break;
268 }
269 }
270 }
271 };
272 if (inTaintTime)
273 {
274 lock (m_collectionActivityLock)
275 {
276 dereferenceOperation();
277 }
278 }
279 else
280 {
281 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
282 }
283 }
284
285 // Count down the reference count for a mesh shape
286 // Called at taint-time.
287 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
288 {
289 MeshDesc meshDesc;
290 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
291 {
292 meshDesc.referenceCount--;
293 // TODO: release the Bullet storage
294 if (shapeCallback != null) shapeCallback(shape);
295 meshDesc.lastReferenced = System.DateTime.Now;
296 Meshes[shape.shapeKey] = meshDesc;
297 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
298 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
299
300 }
301 }
302
303 // Count down the reference count for a hull shape
304 // Called at taint-time.
305 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
306 {
307 HullDesc hullDesc;
308 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
309 {
310 hullDesc.referenceCount--;
311 // TODO: release the Bullet storage (aging old entries?)
312 if (shapeCallback != null) shapeCallback(shape);
313 hullDesc.lastReferenced = System.DateTime.Now;
314 Hulls[shape.shapeKey] = hullDesc;
315 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
316 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
317 }
318 }
319
320 // Create the geometry information in Bullet for later use.
321 // The objects needs a hull if it's physical otherwise a mesh is enough.
322 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
323 // shared geometries will be used. If the parameters of the existing shape are the same
324 // as this request, the shape is not rebuilt.
325 // Info in prim.BSShape is updated to the new shape.
326 // Returns 'true' if the geometry was rebuilt.
327 // Called at taint-time!
328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
330 {
331 bool ret = false;
332 bool haveShape = false;
333 bool nativeShapePossible = true;
334
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 {
337 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
341 ret = true;
342 haveShape = true;
343 }
344 // If the prim attributes are simple, this could be a simple Bullet native shape
345 if (!haveShape
346 && pbs != null
347 && nativeShapePossible
348 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
349 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
350 && pbs.ProfileHollow == 0
351 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
352 && pbs.PathBegin == 0 && pbs.PathEnd == 0
353 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
354 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
355 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
356 {
357 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
358 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
359 {
360 haveShape = true;
361 if (forceRebuild
362 || prim.Scale != shapeData.Size
363 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
364 )
365 {
366 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
367 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
368 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
369 prim.LocalID, forceRebuild, prim.BSShape);
370 }
371 }
372 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
373 {
374 haveShape = true;
375 if (forceRebuild
376 || prim.Scale != shapeData.Size
377 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
378 )
379 {
380 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
381 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
382 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
383 prim.LocalID, forceRebuild, prim.BSShape);
384 }
385 }
386 }
387 // If a simple shape is not happening, create a mesh and possibly a hull.
388 // Note that if it's a native shape, the check for physical/non-physical is not
389 // made. Native shapes are best used in either case.
390 if (!haveShape && pbs != null)
391 {
392 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
393 {
394 // Update prim.BSShape to reference a hull of this shape.
395 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
396 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
397 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
398 }
399 else
400 {
401 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
402 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
403 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
404 }
405 }
406 return ret;
407 }
408
409 // Creates a native shape and assignes it to prim.BSShape.
410 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
411 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
412 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
413 ShapeDestructionCallback shapeCallback)
414 {
415 // release any previous shape
416 DereferenceShape(prim.BSShape, true, shapeCallback);
417
418 shapeData.Type = shapeType;
419 // Bullet native objects are scaled by the Bullet engine so pass the size in
420 prim.Scale = shapeData.Size;
421 shapeData.Scale = shapeData.Size;
422
423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
424
425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale);
428
429 prim.BSShape = newShape;
430 return true;
431 }
432
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
435 {
436 BulletShape newShape;
437 // Need to make sure the passed shape information is for the native type.
438 ShapeData nativeShapeData = shapeData;
439 nativeShapeData.Type = shapeType;
440 nativeShapeData.MeshKey = (ulong)shapeKey;
441 nativeShapeData.HullKey = (ulong)shapeKey;
442
443 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
444 {
445 newShape = new BulletShape(
446 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
447 , shapeType);
448 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
449 }
450 else
451 {
452 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
453 }
454 if (newShape.ptr == IntPtr.Zero)
455 {
456 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
457 LogHeader, nativeShapeData.ID, nativeShapeData.Type);
458 }
459 newShape.shapeKey = (System.UInt64)shapeKey;
460 newShape.isNativeShape = true;
461
462 return newShape;
463 }
464
465 // Builds a mesh shape in the physical world and updates prim.BSShape.
466 // Dereferences previous shape in BSShape and adds a reference for this new shape.
467 // Returns 'true' of a mesh was actually built. Otherwise .
468 // Called at taint-time!
469 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
470 ShapeDestructionCallback shapeCallback)
471 {
472 BulletShape newShape = new BulletShape(IntPtr.Zero);
473
474 float lod;
475 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
476
477 // if this new shape is the same as last time, don't recreate the mesh
478 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
479 return false;
480
481 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
482 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
483
484 // Since we're recreating new, get rid of the reference to the previous shape
485 DereferenceShape(prim.BSShape, true, shapeCallback);
486
487 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
488 // Take evasive action if the mesh was not constructed.
489 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
490
491 ReferenceShape(newShape);
492
493 // meshes are already scaled by the meshmerizer
494 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
495 prim.BSShape = newShape;
496
497 return true; // 'true' means a new shape has been added to this prim
498 }
499
500 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
501 {
502 IMesh meshData = null;
503 IntPtr meshPtr = IntPtr.Zero;
504 MeshDesc meshDesc;
505 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
506 {
507 // If the mesh has already been built just use it.
508 meshPtr = meshDesc.ptr;
509 }
510 else
511 {
512 // Pass false for physicalness as this creates some sort of bounding box which we don't need
513 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
514
515 if (meshData != null)
516 {
517 int[] indices = meshData.getIndexListAsInt();
518 List<OMV.Vector3> vertices = meshData.getVertexList();
519
520 float[] verticesAsFloats = new float[vertices.Count * 3];
521 int vi = 0;
522 foreach (OMV.Vector3 vv in vertices)
523 {
524 verticesAsFloats[vi++] = vv.X;
525 verticesAsFloats[vi++] = vv.Y;
526 verticesAsFloats[vi++] = vv.Z;
527 }
528
529 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
530 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
531
532 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
533 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
534 }
535 }
536 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
537 newShape.shapeKey = newMeshKey;
538
539 return newShape;
540 }
541
542 // See that hull shape exists in the physical world and update prim.BSShape.
543 // We could be creating the hull because scale changed or whatever.
544 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
545 ShapeDestructionCallback shapeCallback)
546 {
547 BulletShape newShape;
548
549 float lod;
550 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
551
552 // if the hull hasn't changed, don't rebuild it
553 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
554 return false;
555
556 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
557 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
558
559 // Remove usage of the previous shape.
560 DereferenceShape(prim.BSShape, true, shapeCallback);
561
562 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
563 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
564
565 ReferenceShape(newShape);
566
567 // hulls are already scaled by the meshmerizer
568 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
569 prim.BSShape = newShape;
570 return true; // 'true' means a new shape has been added to this prim
571 }
572
573 List<ConvexResult> m_hulls;
574 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
575 {
576
577 IntPtr hullPtr = IntPtr.Zero;
578 HullDesc hullDesc;
579 if (Hulls.TryGetValue(newHullKey, out hullDesc))
580 {
581 // If the hull shape already is created, just use it.
582 hullPtr = hullDesc.ptr;
583 }
584 else
585 {
586 // Build a new hull in the physical world
587 // Pass false for physicalness as this creates some sort of bounding box which we don't need
588 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
589 if (meshData != null)
590 {
591
592 int[] indices = meshData.getIndexListAsInt();
593 List<OMV.Vector3> vertices = meshData.getVertexList();
594
595 //format conversion from IMesh format to DecompDesc format
596 List<int> convIndices = new List<int>();
597 List<float3> convVertices = new List<float3>();
598 for (int ii = 0; ii < indices.GetLength(0); ii++)
599 {
600 convIndices.Add(indices[ii]);
601 }
602 foreach (OMV.Vector3 vv in vertices)
603 {
604 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
605 }
606
607 // setup and do convex hull conversion
608 m_hulls = new List<ConvexResult>();
609 DecompDesc dcomp = new DecompDesc();
610 dcomp.mIndices = convIndices;
611 dcomp.mVertices = convVertices;
612 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
613 // create the hull into the _hulls variable
614 convexBuilder.process(dcomp);
615
616 // Convert the vertices and indices for passing to unmanaged.
617 // The hull information is passed as a large floating point array.
618 // The format is:
619 // convHulls[0] = number of hulls
620 // convHulls[1] = number of vertices in first hull
621 // convHulls[2] = hull centroid X coordinate
622 // convHulls[3] = hull centroid Y coordinate
623 // convHulls[4] = hull centroid Z coordinate
624 // convHulls[5] = first hull vertex X
625 // convHulls[6] = first hull vertex Y
626 // convHulls[7] = first hull vertex Z
627 // convHulls[8] = second hull vertex X
628 // ...
629 // convHulls[n] = number of vertices in second hull
630 // convHulls[n+1] = second hull centroid X coordinate
631 // ...
632 //
633 // TODO: is is very inefficient. Someday change the convex hull generator to return
634 // data structures that do not need to be converted in order to pass to Bullet.
635 // And maybe put the values directly into pinned memory rather than marshaling.
636 int hullCount = m_hulls.Count;
637 int totalVertices = 1; // include one for the count of the hulls
638 foreach (ConvexResult cr in m_hulls)
639 {
640 totalVertices += 4; // add four for the vertex count and centroid
641 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
642 }
643 float[] convHulls = new float[totalVertices];
644
645 convHulls[0] = (float)hullCount;
646 int jj = 1;
647 foreach (ConvexResult cr in m_hulls)
648 {
649 // copy vertices for index access
650 float3[] verts = new float3[cr.HullVertices.Count];
651 int kk = 0;
652 foreach (float3 ff in cr.HullVertices)
653 {
654 verts[kk++] = ff;
655 }
656
657 // add to the array one hull's worth of data
658 convHulls[jj++] = cr.HullIndices.Count;
659 convHulls[jj++] = 0f; // centroid x,y,z
660 convHulls[jj++] = 0f;
661 convHulls[jj++] = 0f;
662 foreach (int ind in cr.HullIndices)
663 {
664 convHulls[jj++] = verts[ind].x;
665 convHulls[jj++] = verts[ind].y;
666 convHulls[jj++] = verts[ind].z;
667 }
668 }
669 // create the hull data structure in Bullet
670 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
671 }
672 }
673
674 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
675 newShape.shapeKey = newHullKey;
676
677 return newShape; // 'true' means a new shape has been added to this prim
678 }
679
680 // Callback from convex hull creater with a newly created hull.
681 // Just add it to our collection of hulls for this shape.
682 private void HullReturn(ConvexResult result)
683 {
684 m_hulls.Add(result);
685 return;
686 }
687
688 // Create a hash of all the shape parameters to be used as a key
689 // for this particular shape.
690 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
691 {
692 // level of detail based on size and type of the object
693 float lod = PhysicsScene.MeshLOD;
694 if (pbs.SculptEntry)
695 lod = PhysicsScene.SculptLOD;
696
697 // Mega prims usually get more detail because one can interact with shape approximations at this size.
698 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
699 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
700 lod = PhysicsScene.MeshMegaPrimLOD;
701
702 retLod = lod;
703 return pbs.GetMeshKey(shapeData.Size, lod);
704 }
705 // For those who don't want the LOD
706 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
707 {
708 float lod;
709 return ComputeShapeKey(shapeData, pbs, out lod);
710 }
711
712 // The creation of a mesh or hull can fail if an underlying asset is not available.
713 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
714 // and 2) the asset cannot be converted (like decompressing JPEG2000s).
715 // The first case causes the asset to be fetched. The second case just requires
716 // us to not loop forever.
717 // Called after creating a physical mesh or hull. If the physical shape was created,
718 // just return.
719 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
720 {
721 // If the shape was successfully created, nothing more to do
722 if (newShape.ptr != IntPtr.Zero)
723 return newShape;
724
725 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
726 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
727 {
728 prim.LastAssetBuildFailed = true;
729 BSPhysObject xprim = prim;
730 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
731 LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
732 Util.FireAndForget(delegate
733 {
734 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
735 if (assetProvider != null)
736 {
737 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
738 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
739 {
740 if (!yprim.BaseShape.SculptEntry)
741 return;
742 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
743 return;
744
745 yprim.BaseShape.SculptData = asset.Data;
746 // This will cause the prim to see that the filler shape is not the right
747 // one and try again to build the object.
748 // No race condition with the native sphere setting since the rebuild is at taint time.
749 yprim.ForceBodyShapeRebuild(false);
750
751 });
752 }
753 });
754 }
755 else
756 {
757 if (prim.LastAssetBuildFailed)
758 {
759 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
760 LogHeader, shapeData.ID, pbs.SculptTexture);
761 }
762 }
763
764 // While we figure out the real problem, stick a simple native shape on the object.
765 BulletShape fillinShape =
766 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
767
768 return fillinShape;
769 }
770
771 // Create a body object in Bullet.
772 // Updates prim.BSBody with the information about the new body if one is created.
773 // Returns 'true' if an object was actually created.
774 // Called at taint-time.
775 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
776 ShapeData shapeData, BodyDestructionCallback bodyCallback)
777 {
778 bool ret = false;
779
780 // the mesh, hull or native shape must have already been created in Bullet
781 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
782
783 // If there is an existing body, verify it's of an acceptable type.
784 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
785 if (!mustRebuild)
786 {
787 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
788 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
789 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
790 {
791 // If the collisionObject is not the correct type for solidness, rebuild what's there
792 mustRebuild = true;
793 }
794 }
795
796 if (mustRebuild || forceRebuild)
797 {
798 // Free any old body
799 DereferenceBody(prim.BSBody, true, bodyCallback);
800
801 BulletBody aBody;
802 IntPtr bodyPtr = IntPtr.Zero;
803 if (prim.IsSolid)
804 {
805 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
806 shapeData.ID, shapeData.Position, shapeData.Rotation);
807 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
808 }
809 else
810 {
811 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
812 shapeData.ID, shapeData.Position, shapeData.Rotation);
813 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
814 }
815 aBody = new BulletBody(shapeData.ID, bodyPtr);
816
817 ReferenceBody(aBody, true);
818
819 prim.BSBody = aBody;
820
821 ret = true;
822 }
823
824 return ret;
825 }
826
827 private void DetailLog(string msg, params Object[] args)
828 {
829 if (PhysicsScene.PhysicsLogging.Enabled)
830 PhysicsScene.DetailLog(msg, args);
831 }
832}
833}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
new file mode 100755
index 0000000..880859a
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,492 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public class BSTerrainManager
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
46
47 // These height values are fractional so the odd values will be
48 // noticable when debugging.
49 public const float HEIGHT_INITIALIZATION = 24.987f;
50 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
51 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
52
53 // If the min and max height are equal, we reduce the min by this
54 // amount to make sure that a bounding box is built for the terrain.
55 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
56
57 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
58
59 // Until the whole simulator is changed to pass us the region size, we rely on constants.
60 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
61
62 // The scene that I am part of
63 private BSScene PhysicsScene { get; set; }
64
65 // The ground plane created to keep thing from falling to infinity.
66 private BulletBody m_groundPlane;
67
68 // If doing mega-regions, if we're region zero we will be managing multiple
69 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
71
72 // True of the terrain has been modified.
73 // Used to force recalculation of terrain height after terrain has been modified
74 private bool m_terrainModified;
75
76 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
77 // This is incremented before assigning to new region so it is the last ID allocated.
78 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
79 public uint HighestTerrainID { get {return m_terrainCount; } }
80
81 // If doing mega-regions, this holds our offset from region zero of
82 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
83 private Vector3 m_worldOffset;
84 // If the parent region (region 0), this is the extent of the combined regions
85 // relative to the origin of region zero
86 private Vector3 m_worldMax;
87 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
88
89 public BSTerrainManager(BSScene physicsScene)
90 {
91 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
93 m_terrainModified = false;
94
95 // Assume one region of default size
96 m_worldOffset = Vector3.Zero;
97 m_worldMax = new Vector3(DefaultRegionSize);
98 MegaRegionParentPhysicsScene = null;
99 }
100
101 // Create the initial instance of terrain and the underlying ground plane.
102 // The objects are allocated in the unmanaged space and the pointers are tracked
103 // by the managed code.
104 // The terrains and the groundPlane are not added to the list of PhysObjects.
105 // This is called from the initialization routine so we presume it is
106 // safe to call Bullet in real time. We hope no one is moving prims around yet.
107 public void CreateInitialGroundPlaneAndTerrain()
108 {
109 // The ground plane is here to catch things that are trying to drop to negative infinity
110 BulletShape groundPlaneShape = new BulletShape(
111 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
112 ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
113 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
118 // Ground plane does not move
119 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
120 // Everything collides with the ground plane.
121 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
122 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
123
124 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
125 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
126 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
127 float[] initialMap = new float[totalHeights];
128 for (int ii = 0; ii < totalHeights; ii++)
129 {
130 initialMap[ii] = HEIGHT_INITIALIZATION;
131 }
132 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
133 }
134
135 // Release all the terrain structures we might have allocated
136 public void ReleaseGroundPlaneAndTerrain()
137 {
138 if (m_groundPlane.ptr != IntPtr.Zero)
139 {
140 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
141 {
142 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
143 }
144 m_groundPlane.ptr = IntPtr.Zero;
145 }
146
147 ReleaseTerrain();
148 }
149
150 // Release all the terrain we have allocated
151 public void ReleaseTerrain()
152 {
153 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
154 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
156 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
158 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
159 }
160 }
161 m_heightMaps.Clear();
162 }
163
164 // The simulator wants to set a new heightmap for the terrain.
165 public void SetTerrain(float[] heightMap) {
166 float[] localHeightMap = heightMap;
167 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
168 {
169 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
170 {
171 // If a child of a mega-region, we shouldn't have any terrain allocated for us
172 ReleaseGroundPlaneAndTerrain();
173 // If doing the mega-prim stuff and we are the child of the zero region,
174 // the terrain is added to our parent
175 if (MegaRegionParentPhysicsScene is BSScene)
176 {
177 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
178 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
179 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
180 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
181 }
182 }
183 else
184 {
185 // If not doing the mega-prim thing, just change the terrain
186 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
187
188 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
189 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
190 }
191 });
192 }
193
194 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
195 // based on the passed information. The 'id' should be either the terrain id or
196 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
197 // The latter feature is for creating child terrains for mega-regions.
198 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
199 // then a new body and shape is created and the mapInfo is filled.
200 // This call is used for doing the initial terrain creation.
201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
202 // terrain shape is created and added to the body.
203 // This call is most often used to update the heightMap and parameters of the terrain.
204 // (The above does suggest that some simplification/refactoring is in order.)
205 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
206 {
207 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
208 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
209
210 float minZ = float.MaxValue;
211 float maxZ = float.MinValue;
212 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
213
214 int heightMapSize = heightMap.Length;
215 for (int ii = 0; ii < heightMapSize; ii++)
216 {
217 float height = heightMap[ii];
218 if (height < minZ) minZ = height;
219 if (height > maxZ) maxZ = height;
220 }
221
222 // The shape of the terrain is from its base to its extents.
223 minCoords.Z = minZ;
224 maxCoords.Z = maxZ;
225
226 BulletHeightMapInfo mapInfo;
227 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
228 {
229 // If this is terrain we know about, it's easy to update
230
231 mapInfo.heightMap = heightMap;
232 mapInfo.minCoords = minCoords;
233 mapInfo.maxCoords = maxCoords;
234 mapInfo.minZ = minZ;
235 mapInfo.maxZ = maxZ;
236 mapInfo.sizeX = maxCoords.X - minCoords.X;
237 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
238 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
239 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
240
241 BSScene.TaintCallback rebuildOperation = delegate()
242 {
243 if (MegaRegionParentPhysicsScene != null)
244 {
245 // It's possible that Combine() was called after this code was queued.
246 // If we are a child of combined regions, we don't create any terrain for us.
247 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
248
249 // Get rid of any terrain that may have been allocated for us.
250 ReleaseGroundPlaneAndTerrain();
251
252 // I hate doing this, but just bail
253 return;
254 }
255
256 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
257 {
258 // Updating an existing terrain.
259 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
260 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
261
262 // Remove from the dynamics world because we're going to mangle this object
263 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
264
265 // Get rid of the old terrain
266 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
267 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
268 mapInfo.Ptr = IntPtr.Zero;
269
270 /*
271 // NOTE: This routine is half here because I can't get the terrain shape replacement
272 // to work. In the short term, the above three lines completely delete the old
273 // terrain and the code below recreates one from scratch.
274 // Hopefully the Bullet community will help me out on this one.
275
276 // First, release the old collision shape (there is only one terrain)
277 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
278
279 // Fill the existing height map info with the new location and size information
280 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
281 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
282
283 // Create a terrain shape based on the new info
284 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
285
286 // Stuff the shape into the existing terrain body
287 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
288 */
289 }
290 // else
291 {
292 // Creating a new terrain.
293 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
294 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
295
296 mapInfo.ID = id;
297 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
298 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
299
300 // Create the terrain shape from the mapInfo
301 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
302 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
303
304 // The terrain object initial position is at the center of the object
305 Vector3 centerPos;
306 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
307 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
308 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
309
310 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
311 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
312 id, centerPos, Quaternion.Identity));
313 }
314
315 // Make sure the entry is in the heightmap table
316 m_heightMaps[terrainRegionBase] = mapInfo;
317
318 // Set current terrain attributes
319 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
320 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
321 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
322 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
323
324 // Return the new terrain to the world of physical objects
325 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
326
327 // redo its bounding box now that it is in the world
328 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
329
330 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
331 (uint)CollisionFilterGroups.TerrainFilter,
332 (uint)CollisionFilterGroups.TerrainMask);
333
334 // Make sure the new shape is processed.
335 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
336 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
338
339 m_terrainModified = true;
340 };
341
342 // There is the option to do the changes now (we're already in 'taint time'), or
343 // to do the Bullet operations later.
344 if (inTaintTime)
345 rebuildOperation();
346 else
347 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
348 }
349 else
350 {
351 // We don't know about this terrain so either we are creating a new terrain or
352 // our mega-prim child is giving us a new terrain to add to the phys world
353
354 // if this is a child terrain, calculate a unique terrain id
355 uint newTerrainID = id;
356 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
357 newTerrainID = ++m_terrainCount;
358
359 float[] heightMapX = heightMap;
360 Vector3 minCoordsX = minCoords;
361 Vector3 maxCoordsX = maxCoords;
362
363 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
364 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
365
366 // Code that must happen at taint-time
367 BSScene.TaintCallback createOperation = delegate()
368 {
369 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
370 // Create a new mapInfo that will be filled with the new info
371 mapInfo = new BulletHeightMapInfo(id, heightMapX,
372 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
373 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
374 // Put the unfilled heightmap info into the collection of same
375 m_heightMaps.Add(terrainRegionBase, mapInfo);
376 // Build the terrain
377 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
378
379 m_terrainModified = true;
380 };
381
382 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
383 if (inTaintTime)
384 createOperation();
385 else
386 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
387 }
388 }
389
390 // Someday we will have complex terrain with caves and tunnels
391 public float GetTerrainHeightAtXYZ(Vector3 loc)
392 {
393 // For the moment, it's flat and convex
394 return GetTerrainHeightAtXY(loc.X, loc.Y);
395 }
396
397 // Given an X and Y, find the height of the terrain.
398 // Since we could be handling multiple terrains for a mega-region,
399 // the base of the region is calcuated assuming all regions are
400 // the same size and that is the default.
401 // Once the heightMapInfo is found, we have all the information to
402 // compute the offset into the array.
403 private float lastHeightTX = 999999f;
404 private float lastHeightTY = 999999f;
405 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
406 private float GetTerrainHeightAtXY(float tX, float tY)
407 {
408 // You'd be surprized at the number of times this routine is called
409 // with the same parameters as last time.
410 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
411 return lastHeight;
412
413 lastHeightTX = tX;
414 lastHeightTY = tY;
415 float ret = HEIGHT_GETHEIGHT_RET;
416
417 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
418 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
419 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
420
421 BulletHeightMapInfo mapInfo;
422 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
423 {
424 float regionX = tX - offsetX;
425 float regionY = tY - offsetY;
426 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
427 try
428 {
429 ret = mapInfo.heightMap[mapIndex];
430 }
431 catch
432 {
433 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
434 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
435 LogHeader, terrainBaseXY, regionX, regionY);
436 ret = HEIGHT_GETHEIGHT_RET;
437 }
438 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
439 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
440 }
441 else
442 {
443 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
444 LogHeader, PhysicsScene.RegionName, tX, tY);
445 }
446 m_terrainModified = false;
447 lastHeight = ret;
448 return ret;
449 }
450
451 // Although no one seems to check this, I do support combining.
452 public bool SupportsCombining()
453 {
454 return true;
455 }
456
457 // This routine is called two ways:
458 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
459 // extent of the combined regions. This is to inform the parent of the size
460 // of the combined regions.
461 // and one with 'offset' as the offset of the child region to the base region,
462 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
463 // child of its relative base and new parent.
464 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
465 {
466 m_worldOffset = offset;
467 m_worldMax = extents;
468 MegaRegionParentPhysicsScene = pScene;
469 if (pScene != null)
470 {
471 // We are a child.
472 // We want m_worldMax to be the highest coordinate of our piece of terrain.
473 m_worldMax = offset + DefaultRegionSize;
474 }
475 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
476 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
477 }
478
479 // Unhook all the combining that I know about.
480 public void UnCombine(PhysicsScene pScene)
481 {
482 // Just like ODE, for the moment a NOP
483 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
484 }
485
486
487 private void DetailLog(string msg, params Object[] args)
488 {
489 PhysicsScene.PhysicsLogging.Write(msg, args);
490 }
491}
492}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 504bd3c..5ffd591 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -33,38 +33,153 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin { 33namespace OpenSim.Region.Physics.BulletSPlugin {
34 34
35// Classes to allow some type checking for the API 35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
36public struct BulletSim 39public struct BulletSim
37{ 40{
38 public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } 41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
39 public uint ID; 42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
40 // The scene is only in here so very low level routines have a handle to print debug/error messages 49 // The scene is only in here so very low level routines have a handle to print debug/error messages
41 public BSScene scene; 50 public BSScene physicsScene;
42 public IntPtr Ptr;
43} 51}
44 52
53// An allocated Bullet btRigidBody
45public struct BulletBody 54public struct BulletBody
46{ 55{
47 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } 56 public BulletBody(uint id, IntPtr xx)
48 public IntPtr Ptr; 57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
49 public uint ID; 64 public uint ID;
65 public CollisionFilterGroups collisionFilter;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 || collisionMask != 0)
75 {
76 buff.Append(",f=");
77 buff.Append(collisionFilter.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
84}
85
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = 0;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type;
104 public System.UInt64 shapeKey;
105 public bool isNativeShape;
106 public override string ToString()
107 {
108 StringBuilder buff = new StringBuilder();
109 buff.Append("<p=");
110 buff.Append(ptr.ToString("X"));
111 buff.Append(",s=");
112 buff.Append(type.ToString());
113 buff.Append(",k=");
114 buff.Append(shapeKey.ToString("X"));
115 buff.Append(",n=");
116 buff.Append(isNativeShape.ToString());
117 buff.Append(">");
118 return buff.ToString();
119 }
50} 120}
51 121
122 // Constraint type values as defined by Bullet
123public enum ConstraintType : int
124{
125 POINT2POINT_CONSTRAINT_TYPE = 3,
126 HINGE_CONSTRAINT_TYPE,
127 CONETWIST_CONSTRAINT_TYPE,
128 D6_CONSTRAINT_TYPE,
129 SLIDER_CONSTRAINT_TYPE,
130 CONTACT_CONSTRAINT_TYPE,
131 D6_SPRING_CONSTRAINT_TYPE,
132 MAX_CONSTRAINT_TYPE
133}
134
135// An allocated Bullet btConstraint
52public struct BulletConstraint 136public struct BulletConstraint
53{ 137{
54 public BulletConstraint(IntPtr xx) { Ptr = xx; } 138 public BulletConstraint(IntPtr xx)
139 {
140 ptr = xx;
141 }
142 public IntPtr ptr;
143}
144
145// An allocated HeightMapThing which holds various heightmap info.
146// Made a class rather than a struct so there would be only one
147// instance of this and C# will pass around pointers rather
148// than making copies.
149public class BulletHeightMapInfo
150{
151 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
152 ID = id;
153 Ptr = xx;
154 heightMap = hm;
155 terrainRegionBase = new Vector2(0f, 0f);
156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f;
159 sizeX = sizeY = 256f;
160 }
161 public uint ID;
55 public IntPtr Ptr; 162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector2 terrainRegionBase;
165 public Vector3 minCoords;
166 public Vector3 maxCoords;
167 public float sizeX, sizeY;
168 public float minZ, maxZ;
169 public BulletShape terrainShape;
170 public BulletBody terrainBody;
56} 171}
57 172
58// =============================================================================== 173// ===============================================================================
59[StructLayout(LayoutKind.Sequential)] 174[StructLayout(LayoutKind.Sequential)]
60public struct ConvexHull 175public struct ConvexHull
61{ 176{
62 Vector3 Offset; 177 Vector3 Offset;
63 int VertexCount; 178 int VertexCount;
64 Vector3[] Vertices; 179 Vector3[] Vertices;
65} 180}
66[StructLayout(LayoutKind.Sequential)] 181[StructLayout(LayoutKind.Sequential)]
67public struct ShapeData 182public struct ShapeData
68{ 183{
69 public enum PhysicsShapeType 184 public enum PhysicsShapeType
70 { 185 {
@@ -75,7 +190,10 @@ public struct ShapeData
75 SHAPE_CYLINDER = 4, 190 SHAPE_CYLINDER = 4,
76 SHAPE_SPHERE = 5, 191 SHAPE_SPHERE = 5,
77 SHAPE_MESH = 6, 192 SHAPE_MESH = 6,
78 SHAPE_HULL = 7 193 SHAPE_HULL = 7,
194 // following defined by BulletSim
195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21,
79 }; 197 };
80 public uint ID; 198 public uint ID;
81 public PhysicsShapeType Type; 199 public PhysicsShapeType Type;
@@ -91,13 +209,25 @@ public struct ShapeData
91 public float Restitution; 209 public float Restitution;
92 public float Collidable; // true of things bump into this 210 public float Collidable; // true of things bump into this
93 public float Static; // true if a static object. Otherwise gravity, etc. 211 public float Static; // true if a static object. Otherwise gravity, etc.
212 public float Solid; // true if object cannot be passed through
213 public Vector3 Size;
94 214
95 // note that bools are passed as floats since bool size changes by language and architecture 215 // note that bools are passed as floats since bool size changes by language and architecture
96 public const float numericTrue = 1f; 216 public const float numericTrue = 1f;
97 public const float numericFalse = 0f; 217 public const float numericFalse = 0f;
218
219 // The native shapes have predefined shape hash keys
220 public enum FixedShapeKey : ulong
221 {
222 KEY_BOX = 1,
223 KEY_SPHERE = 2,
224 KEY_CONE = 3,
225 KEY_CYLINDER = 4,
226 KEY_CAPSULE = 5,
227 }
98} 228}
99[StructLayout(LayoutKind.Sequential)] 229[StructLayout(LayoutKind.Sequential)]
100public struct SweepHit 230public struct SweepHit
101{ 231{
102 public uint ID; 232 public uint ID;
103 public float Fraction; 233 public float Fraction;
@@ -153,6 +283,7 @@ public struct ConfigurationParameters
153 public float terrainHitFraction; 283 public float terrainHitFraction;
154 public float terrainRestitution; 284 public float terrainRestitution;
155 public float avatarFriction; 285 public float avatarFriction;
286 public float avatarStandingFriction;
156 public float avatarDensity; 287 public float avatarDensity;
157 public float avatarRestitution; 288 public float avatarRestitution;
158 public float avatarCapsuleRadius; 289 public float avatarCapsuleRadius;
@@ -174,12 +305,38 @@ public struct ConfigurationParameters
174 public float linkConstraintTransMotorMaxForce; 305 public float linkConstraintTransMotorMaxForce;
175 public float linkConstraintERP; 306 public float linkConstraintERP;
176 public float linkConstraintCFM; 307 public float linkConstraintCFM;
308 public float linkConstraintSolverIterations;
309
310 public float physicsLoggingFrames;
177 311
178 public const float numericTrue = 1f; 312 public const float numericTrue = 1f;
179 public const float numericFalse = 0f; 313 public const float numericFalse = 0f;
180} 314}
181 315
182// Values used by Bullet and BulletSim to control collisions 316
317// The states a bullet collision object can have
318public enum ActivationState : uint
319{
320 ACTIVE_TAG = 1,
321 ISLAND_SLEEPING,
322 WANTS_DEACTIVATION,
323 DISABLE_DEACTIVATION,
324 DISABLE_SIMULATION,
325}
326
327public enum CollisionObjectTypes : int
328{
329 CO_COLLISION_OBJECT = 1 << 0,
330 CO_RIGID_BODY = 1 << 1,
331 CO_GHOST_OBJECT = 1 << 2,
332 CO_SOFT_BODY = 1 << 3,
333 CO_HF_FLUID = 1 << 4,
334 CO_USER_TYPE = 1 << 5,
335}
336
337// Values used by Bullet and BulletSim to control object properties.
338// Bullet's "CollisionFlags" has more to do with operations on the
339// object (if collisions happen, if gravity effects it, ...).
183public enum CollisionFlags : uint 340public enum CollisionFlags : uint
184{ 341{
185 CF_STATIC_OBJECT = 1 << 0, 342 CF_STATIC_OBJECT = 1 << 0,
@@ -191,11 +348,55 @@ public enum CollisionFlags : uint
191 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 348 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
192 // Following used by BulletSim to control collisions 349 // Following used by BulletSim to control collisions
193 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 350 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
194 BS_VOLUME_DETECT_OBJECT = 1 << 11, 351 BS_FLOATS_ON_WATER = 1 << 11,
195 BS_PHANTOM_OBJECT = 1 << 12, 352 BS_NONE = 0,
196 BS_PHYSICAL_OBJECT = 1 << 13, 353 BS_ALL = 0xFFFFFFFF,
354
355 // These are the collision flags switched depending on physical state.
356 // The other flags are used for other things and should not be fooled with.
357 BS_ACTIVE = CF_STATIC_OBJECT
358 | CF_KINEMATIC_OBJECT
359 | CF_NO_CONTACT_RESPONSE
197}; 360};
198 361
362// Values for collisions groups and masks
363public enum CollisionFilterGroups : uint
364{
365 // Don't use the bit definitions!! Define the use in a
366 // filter/mask definition below. This way collision interactions
367 // are more easily debugged.
368 BNoneFilter = 0,
369 BDefaultFilter = 1 << 0,
370 BStaticFilter = 1 << 1,
371 BKinematicFilter = 1 << 2,
372 BDebrisFilter = 1 << 3,
373 BSensorTrigger = 1 << 4,
374 BCharacterFilter = 1 << 5,
375 BAllFilter = 0xFFFFFFFF,
376 // Filter groups defined by BulletSim
377 BGroundPlaneFilter = 1 << 10,
378 BTerrainFilter = 1 << 11,
379 BRaycastFilter = 1 << 12,
380 BSolidFilter = 1 << 13,
381
382 // The collsion filters and masked are defined in one place -- don't want them scattered
383 AvatarFilter = BCharacterFilter,
384 AvatarMask = BAllFilter,
385 ObjectFilter = BSolidFilter,
386 ObjectMask = BAllFilter,
387 StaticObjectFilter = BStaticFilter,
388 StaticObjectMask = BAllFilter,
389 VolumeDetectFilter = BSensorTrigger,
390 VolumeDetectMask = ~BSensorTrigger,
391 TerrainFilter = BTerrainFilter,
392 TerrainMask = BAllFilter & ~BStaticFilter,
393 GroundPlaneFilter = BGroundPlaneFilter,
394 GroundPlaneMask = BAllFilter
395
396};
397
398
399
199// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 400// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
200// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. 401// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
201public enum ConstraintParams : int 402public enum ConstraintParams : int
@@ -221,14 +422,23 @@ public enum ConstraintParamAxis : int
221// =============================================================================== 422// ===============================================================================
222static class BulletSimAPI { 423static class BulletSimAPI {
223 424
425// Link back to the managed code for outputting log messages
426[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
427public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
428
224[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 429[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
225[return: MarshalAs(UnmanagedType.LPStr)] 430[return: MarshalAs(UnmanagedType.LPStr)]
226public static extern string GetVersion(); 431public static extern string GetVersion();
227 432
433/* Remove the linkage to the old api methods
228[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
229public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 435public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
230 int maxCollisions, IntPtr collisionArray, 436 int maxCollisions, IntPtr collisionArray,
231 int maxUpdates, IntPtr updateArray); 437 int maxUpdates, IntPtr updateArray,
438 DebugLogCallback logRoutine);
439
440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
441public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
232 442
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 444public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
@@ -242,19 +452,19 @@ public static extern bool UpdateParameter(uint worldID, uint localID,
242 452
243// =============================================================================== 453// ===============================================================================
244[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
245public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 455public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
246 out int updatedEntityCount, 456 out int updatedEntityCount,
247 out IntPtr updatedEntitiesPtr, 457 out IntPtr updatedEntitiesPtr,
248 out int collidersCount, 458 out int collidersCount,
249 out IntPtr collidersPtr); 459 out IntPtr collidersPtr);
250 460
251[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
252public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, 462public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
253 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls 463 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
254 ); 464 );
255 465
256[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
257public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, 467public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
258 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, 468 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
259 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices 469 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
260 ); 470 );
@@ -268,23 +478,6 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
268[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
269public static extern bool CreateObject(uint worldID, ShapeData shapeData); 479public static extern bool CreateObject(uint worldID, ShapeData shapeData);
270 480
271/* Remove old functionality
272[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
273public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
274
275[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
276public static extern void AddConstraint(uint worldID, uint id1, uint id2,
277 Vector3 frame1, Quaternion frame1rot,
278 Vector3 frame2, Quaternion frame2rot,
279 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
280
281[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
282public static extern bool RemoveConstraintByID(uint worldID, uint id1);
283
284[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
285public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
286 */
287
288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
289public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 482public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
290 483
@@ -300,6 +493,7 @@ public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 veloc
300[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
301public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); 494public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
302 495
496// Set the current force acting on the object
303[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 497[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
304public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); 498public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
305 499
@@ -340,10 +534,8 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
340// =============================================================================== 534// ===============================================================================
341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
342public static extern void DumpBulletStatistics(); 536public static extern void DumpBulletStatistics();
343 537*/
344// Log a debug message 538// Log a debug message
345[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
346public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
348public static extern void SetDebugLogCallback(DebugLogCallback callback); 540public static extern void SetDebugLogCallback(DebugLogCallback callback);
349 541
@@ -358,6 +550,7 @@ public static extern void SetDebugLogCallback(DebugLogCallback callback);
358// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt 550// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
359// and the old code is removed. 551// and the old code is removed.
360 552
553// Functions use while converting from API1 to API2. Can be removed when totally converted.
361[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
362public static extern IntPtr GetSimHandle2(uint worldID); 555public static extern IntPtr GetSimHandle2(uint worldID);
363 556
@@ -368,23 +561,25 @@ public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
368public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); 561public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
369 562
370// =============================================================================== 563// ===============================================================================
564// Initialization and simulation
371[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
372public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 566public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
373 int maxCollisions, IntPtr collisionArray, 567 int maxCollisions, IntPtr collisionArray,
374 int maxUpdates, IntPtr updateArray); 568 int maxUpdates, IntPtr updateArray,
569 DebugLogCallback logRoutine);
375 570
376[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 571[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
377public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 572public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
378 573
379[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 574[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
380public static extern void SetHeightmap2(IntPtr world, float[] heightmap); 575public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
381 576
382[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 577[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
383public static extern void Shutdown2(IntPtr sim); 578public static extern void Shutdown2(IntPtr sim);
384 579
385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 580[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
386public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, 581public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
387 out int updatedEntityCount, 582 out int updatedEntityCount,
388 out IntPtr updatedEntitiesPtr, 583 out IntPtr updatedEntitiesPtr,
389 out int collidersCount, 584 out int collidersCount,
390 out IntPtr collidersPtr); 585 out IntPtr collidersPtr);
@@ -392,24 +587,90 @@ public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSt
392[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 587[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
393public static extern bool PushUpdate2(IntPtr obj); 588public static extern bool PushUpdate2(IntPtr obj);
394 589
395/* 590// =====================================================================================
591// Mesh, hull, shape and body creation helper routines
396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
397public static extern IntPtr CreateMesh2(IntPtr world, int indicesCount, int* indices, int verticesCount, float* vertices ); 593public static extern IntPtr CreateMeshShape2(IntPtr world,
594 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
595 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
398 596
399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 597[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
400public static extern bool BuildHull2(IntPtr world, IntPtr mesh); 598public static extern IntPtr CreateHullShape2(IntPtr world,
599 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
401 600
402[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
403public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh); 602public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
404 603
405[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
406public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh); 605public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
407 606
408[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
409public static extern IntPtr CreateObject2(IntPtr world, ShapeData shapeData); 608public static extern bool IsNativeShape2(IntPtr shape);
410*/ 609
610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
611public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
612
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
614public static extern IntPtr CreateCompoundShape2(IntPtr sim);
615
616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
617public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
618
619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
620public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
621
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
624
625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
626public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
627
628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
629public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
411 630
412[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
632public static extern int GetBodyType2(IntPtr obj);
633
634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
635public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
636
637[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
638public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
639
640[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
641public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
642
643[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
644public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
645
646[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
647public static extern void ReleaseBodyInfo2(IntPtr obj);
648
649[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
650public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
651
652// =====================================================================================
653// Terrain creation and helper routines
654[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
655public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
656 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
657
658[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
659public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
660 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
661
662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
663public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
664
665[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
666public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
667
668[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
669public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
670
671// =====================================================================================
672// Constraint creation and helper routines
673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
413public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 674public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
414 Vector3 frame1loc, Quaternion frame1rot, 675 Vector3 frame1loc, Quaternion frame1rot,
415 Vector3 frame2loc, Quaternion frame2rot, 676 Vector3 frame2loc, Quaternion frame2rot,
@@ -433,7 +694,7 @@ public static extern void SetConstraintEnable2(IntPtr constrain, float numericTr
433public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); 694public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
434 695
435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
436public static extern bool SetFrames2(IntPtr constrain, 697public static extern bool SetFrames2(IntPtr constrain,
437 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); 698 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
438 699
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 700[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -460,11 +721,108 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams
460[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 721[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
461public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); 722public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
462 723
724// =====================================================================================
725// btCollisionWorld entries
726[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
727public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
728
729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
730public static extern void UpdateAabbs2(IntPtr world);
731
732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
733public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
734
735[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
736public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
737
738// =====================================================================================
739// btDynamicsWorld entries
740[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
741public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
742
743[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
744public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
745
746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
747public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
748
749[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
750public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
751// =====================================================================================
752// btCollisionObject entries
753[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
754public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
755
756[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
757public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
758
759[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
760public static extern bool HasAnisotripicFriction2(IntPtr constrain);
761
762[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
763public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
764
765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
766public static extern float GetContactProcessingThreshold2(IntPtr obj);
767
768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
769public static extern bool IsStaticObject2(IntPtr obj);
770
771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
772public static extern bool IsKinematicObject2(IntPtr obj);
773
463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
464public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); 775public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
465 776
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 778public static extern bool HasContactResponse2(IntPtr obj);
779
780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
781public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
782
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern IntPtr GetCollisionShape2(IntPtr obj);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern int GetActivationState2(IntPtr obj);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern void SetActivationState2(IntPtr obj, int state);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern float GetDeactivationTime2(IntPtr obj);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern void Activate2(IntPtr obj, bool forceActivation);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern bool IsActive2(IntPtr obj);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern void SetRestitution2(IntPtr obj, float val);
809
810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
811public static extern float GetRestitution2(IntPtr obj);
812
813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
814public static extern void SetFriction2(IntPtr obj, float val);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern float GetFriction2(IntPtr obj);
818
819 /* Haven't defined the type 'Transform'
820[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
821public static extern Transform GetWorldTransform2(IntPtr obj);
822
823[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
824public static extern void setWorldTransform2(IntPtr obj, Transform trans);
825 */
468 826
469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 827[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
470public static extern Vector3 GetPosition2(IntPtr obj); 828public static extern Vector3 GetPosition2(IntPtr obj);
@@ -473,85 +831,290 @@ public static extern Vector3 GetPosition2(IntPtr obj);
473public static extern Quaternion GetOrientation2(IntPtr obj); 831public static extern Quaternion GetOrientation2(IntPtr obj);
474 832
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 833[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); 834public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
477 835
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 836[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity); 837public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
480 838
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 839[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); 840public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
483 841
842 /*
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 843[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); 844public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
486 845
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 846[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern bool AddObjectForce2(IntPtr obj, Vector3 force); 847public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
848 */
489 849
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); 851public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
492 852
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val); 854public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
495 855
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping); 857public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
498 858
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 859[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern bool SetDeactivationTime2(IntPtr obj, float val); 860public static extern float GetHitFraction2(IntPtr obj);
501 861
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 862[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); 863public static extern void SetHitFraction2(IntPtr obj, float val);
504 864
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 865[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); 866public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
507 867
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern bool SetFriction2(IntPtr obj, float val); 869public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
510 870
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 871[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern bool SetRestitution2(IntPtr obj, float val); 872public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
513 873
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 874[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val); 875public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
516 876
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 877[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); 878public static extern float GetCcdMotionThreshold2(IntPtr obj);
519 879
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 880[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); 881public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
882
883[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
884public static extern float GetCcdSweepSphereRadius2(IntPtr obj);
885
886[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
887public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val);
888
889[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
890public static extern IntPtr GetUserPointer2(IntPtr obj);
891
892[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
893public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
894
895// =====================================================================================
896// btRigidBody entries
897[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
898public static extern void ApplyGravity2(IntPtr obj);
899
900[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
901public static extern void SetGravity2(IntPtr obj, Vector3 val);
902
903[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
904public static extern Vector3 GetGravity2(IntPtr obj);
905
906[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
907public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
908
909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
910public static extern float GetLinearDamping2(IntPtr obj);
911
912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
913public static extern float GetAngularDamping2(IntPtr obj);
914
915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
916public static extern float GetLinearSleepingThreshold2(IntPtr obj);
917
918[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
919public static extern float GetAngularSleepingThreshold2(IntPtr obj);
920
921[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
922public static extern void ApplyDamping2(IntPtr obj, float timeStep);
923
924[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
925public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
926
927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
928public static extern Vector3 GetLinearFactor2(IntPtr obj);
929
930[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
931public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
932
933 /*
934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
935public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
936 */
937
938[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
939public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
940
941// Add a force to the object as if its mass is one.
942[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
943public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
944
945// Set the force being applied to the object as if its mass is one.
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
948
949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
950public static extern Vector3 GetTotalForce2(IntPtr obj);
951
952[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
953public static extern Vector3 GetTotalTorque2(IntPtr obj);
954
955[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
956public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
957
958[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
959public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
960
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
963
964[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
965public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
966
967// Apply force at the given point. Will add torque to the object.
968[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
969public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
970
971// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
972[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
973public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
974
975// Apply impulse to the object's torque. Force is scaled by object's mass.
976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
977public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
978
979// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
980[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
981public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
982
983[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
984public static extern void ClearForces2(IntPtr obj);
985
986[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
987public static extern void ClearAllForces2(IntPtr obj);
988
989[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
990public static extern void UpdateInertiaTensor2(IntPtr obj);
991
992[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
993public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
994
995 /*
996[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
997public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
998 */
999
1000[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1001public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1002
1003[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1004public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1005
1006[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1007public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1008
1009[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1010public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1011
1012[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1013public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1014
1015[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1016public static extern void Translate2(IntPtr obj, Vector3 trans);
1017
1018[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1019public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1020
1021[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1022public static extern bool WantsSleeping2(IntPtr obj);
1023
1024[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1025public static extern void SetAngularFactor2(IntPtr obj, float factor);
1026
1027[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1028public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1029
1030[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1031public static extern Vector3 GetAngularFactor2(IntPtr obj);
1032
1033[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1034public static extern bool IsInWorld2(IntPtr obj);
1035
1036[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1037public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1038
1039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1040public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1041
1042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1043public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1044
1045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1046public static extern int GetNumConstraintRefs2(IntPtr obj);
1047
1048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1049public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1050
1051// =====================================================================================
1052// btCollisionShape entries
1053
1054[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1055public static extern float GetAngularMotionDisc2(IntPtr shape);
1056
1057[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1058public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1059
1060[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1061public static extern bool IsPolyhedral2(IntPtr shape);
1062
1063[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1064public static extern bool IsConvex2d2(IntPtr shape);
1065
1066[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1067public static extern bool IsConvex2(IntPtr shape);
1068
1069[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1070public static extern bool IsNonMoving2(IntPtr shape);
1071
1072[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1073public static extern bool IsConcave2(IntPtr shape);
1074
1075[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1076public static extern bool IsCompound2(IntPtr shape);
1077
1078[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1079public static extern bool IsSoftBody2(IntPtr shape);
1080
1081[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1082public static extern bool IsInfinite2(IntPtr shape);
522 1083
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1084[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags); 1085public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
525 1086
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1087[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); 1088public static extern Vector3 GetLocalScaling2(IntPtr shape);
528 1089
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1090[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); 1091public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
531 1092
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1093[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); 1094public static extern int GetShapeType2(IntPtr shape);
534 1095
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1096[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern bool UpdateInertiaTensor2(IntPtr obj); 1097public static extern void SetMargin2(IntPtr shape, float val);
537 1098
538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1099[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
539public static extern bool SetGravity2(IntPtr obj, Vector3 val); 1100public static extern float GetMargin2(IntPtr shape);
540 1101
1102// =====================================================================================
1103// Debugging
541[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1104[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
542public static extern IntPtr ClearForces2(IntPtr obj); 1105public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
543 1106
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr ClearAllForces2(IntPtr obj); 1108public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
546 1109
547[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
548public static extern bool SetMargin2(IntPtr obj, float val); 1111public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
549 1112
550[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
551public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); 1114public static extern void DumpAllInfo2(IntPtr sim);
552 1115
553[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1116[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
554public static extern bool DestroyObject2(IntPtr world, uint id); 1117public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
555 1118
556[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1119[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
557public static extern void DumpPhysicsStatistics2(IntPtr sim); 1120public static extern void DumpPhysicsStatistics2(IntPtr sim);
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index f3b0630..c736557 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin
100 private bool m_hackSentFly = false; 100 private bool m_hackSentFly = false;
101 private int m_requestedUpdateFrequency = 0; 101 private int m_requestedUpdateFrequency = 0;
102 private Vector3 m_taintPosition; 102 private Vector3 m_taintPosition;
103 103 internal bool m_avatarplanted = false;
104 /// <summary> 104 /// <summary>
105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force 105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
106 /// while calculatios are going on 106 /// while calculatios are going on
@@ -413,7 +413,7 @@ namespace OpenSim.Region.Physics.OdePlugin
413 set 413 set
414 { 414 {
415 m_iscollidingObj = value; 415 m_iscollidingObj = value;
416 if (value) 416 if (value && !m_avatarplanted)
417 m_pidControllerActive = false; 417 m_pidControllerActive = false;
418 else 418 else
419 m_pidControllerActive = true; 419 m_pidControllerActive = true;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index 2e78de5..0551c0b 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -67,6 +67,14 @@ namespace OpenSim.Region.Physics.OdePlugin
67 private int m_expectedCollisionContacts = 0; 67 private int m_expectedCollisionContacts = 0;
68 68
69 /// <summary> 69 /// <summary>
70 /// Gets collide bits so that we can still perform land collisions if a mesh fails to load.
71 /// </summary>
72 private int BadMeshAssetCollideBits
73 {
74 get { return m_isphysical ? (int)CollisionCategories.Land : 0; }
75 }
76
77 /// <summary>
70 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. 78 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
71 /// </summary> 79 /// </summary>
72 public override bool IsPhysical 80 public override bool IsPhysical
@@ -156,7 +164,7 @@ namespace OpenSim.Region.Physics.OdePlugin
156 164
157 private PrimitiveBaseShape _pbs; 165 private PrimitiveBaseShape _pbs;
158 private OdeScene _parent_scene; 166 private OdeScene _parent_scene;
159 167
160 /// <summary> 168 /// <summary>
161 /// The physics space which contains prim geometries 169 /// The physics space which contains prim geometries
162 /// </summary> 170 /// </summary>
@@ -3365,4 +3373,4 @@ Console.WriteLine(" JointCreateFixed");
3365 } 3373 }
3366 } 3374 }
3367 } 3375 }
3368} \ No newline at end of file 3376}
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 7a50c4c..d53bd90 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -501,6 +501,8 @@ namespace OpenSim.Region.Physics.OdePlugin
501 public int physics_logging_interval = 0; 501 public int physics_logging_interval = 0;
502 public bool physics_logging_append_existing_logfile = false; 502 public bool physics_logging_append_existing_logfile = false;
503 503
504 private bool avplanted = false;
505 private bool av_av_collisions_off = false;
504 506
505 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); 507 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
506 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); 508 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
@@ -644,6 +646,9 @@ namespace OpenSim.Region.Physics.OdePlugin
644 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); 646 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
645 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); 647 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
646 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); 648 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
649 avplanted = physicsconfig.GetBoolean("av_planted", false);
650 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
651
647 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); 652 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
648 653
649 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); 654 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
@@ -663,6 +668,8 @@ namespace OpenSim.Region.Physics.OdePlugin
663 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); 668 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
664 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); 669 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
665 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); 670 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
671
672
666 673
667 if (Environment.OSVersion.Platform == PlatformID.Unix) 674 if (Environment.OSVersion.Platform == PlatformID.Unix)
668 { 675 {
@@ -1309,6 +1316,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1309 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) 1316 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1310 skipThisContact = true; // No collision on volume detect prims 1317 skipThisContact = true; // No collision on volume detect prims
1311 1318
1319 if (av_av_collisions_off)
1320 if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1321 skipThisContact = true;
1322
1312 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) 1323 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1313 skipThisContact = true; // No collision on volume detect prims 1324 skipThisContact = true; // No collision on volume detect prims
1314 1325
@@ -1972,7 +1983,8 @@ namespace OpenSim.Region.Physics.OdePlugin
1972 1983
1973 newAv.Flying = isFlying; 1984 newAv.Flying = isFlying;
1974 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; 1985 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1975 1986 newAv.m_avatarplanted = avplanted;
1987
1976 return newAv; 1988 return newAv;
1977 } 1989 }
1978 1990
@@ -1987,6 +1999,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1987 1999
1988 internal void AddCharacter(OdeCharacter chr) 2000 internal void AddCharacter(OdeCharacter chr)
1989 { 2001 {
2002 chr.m_avatarplanted = avplanted;
1990 if (!_characters.Contains(chr)) 2003 if (!_characters.Contains(chr))
1991 { 2004 {
1992 _characters.Add(chr); 2005 _characters.Add(chr);
@@ -4307,4 +4320,4 @@ namespace OpenSim.Region.Physics.OdePlugin
4307 m_stats[ODEPrimUpdateFrameMsStatName] = 0; 4320 m_stats[ODEPrimUpdateFrameMsStatName] = 0;
4308 } 4321 }
4309 } 4322 }
4310} \ No newline at end of file 4323}