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.cs538
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs36
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs616
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs112
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs422
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs213
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1115
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs708
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs737
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs493
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs717
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs37
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs41
15 files changed, 3900 insertions, 1947 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..2a52e01 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -28,62 +28,46 @@ 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; 44 private OMV.Vector3 _scale;
48 private PrimitiveBaseShape _pbs; 45 private PrimitiveBaseShape _pbs;
49 private uint _localID = 0;
50 private bool _grabbed; 46 private bool _grabbed;
51 private bool _selected; 47 private bool _selected;
52 private Vector3 _position; 48 private OMV.Vector3 _position;
53 private float _mass; 49 private float _mass;
54 public float _density; 50 private float _avatarDensity;
55 public float _avatarVolume; 51 private float _avatarVolume;
56 private Vector3 _force; 52 private OMV.Vector3 _force;
57 private Vector3 _velocity; 53 private OMV.Vector3 _velocity;
58 private Vector3 _torque; 54 private OMV.Vector3 _torque;
59 private float _collisionScore; 55 private float _collisionScore;
60 private Vector3 _acceleration; 56 private OMV.Vector3 _acceleration;
61 private Quaternion _orientation; 57 private OMV.Quaternion _orientation;
62 private int _physicsActorType; 58 private int _physicsActorType;
63 private bool _isPhysical; 59 private bool _isPhysical;
64 private bool _flying; 60 private bool _flying;
65 private bool _setAlwaysRun; 61 private bool _setAlwaysRun;
66 private bool _throttleUpdates; 62 private bool _throttleUpdates;
67 private bool _isColliding; 63 private bool _isColliding;
68 private long _collidingStep;
69 private bool _collidingGround;
70 private long _collidingGroundStep;
71 private bool _collidingObj; 64 private bool _collidingObj;
72 private bool _floatOnWater; 65 private bool _floatOnWater;
73 private Vector3 _rotationalVelocity; 66 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic; 67 private bool _kinematic;
75 private float _buoyancy; 68 private float _buoyancy;
76 69
77 private BulletBody m_body; 70 private OMV.Vector3 _PIDTarget;
78 public BulletBody Body {
79 get { return m_body; }
80 set { m_body = value; }
81 }
82
83 private int _subscribedEventsMs = 0;
84 private int _nextCollisionOkTime = 0;
85
86 private Vector3 _PIDTarget;
87 private bool _usePID; 71 private bool _usePID;
88 private float _PIDTau; 72 private float _PIDTau;
89 private bool _useHoverPID; 73 private bool _useHoverPID;
@@ -91,25 +75,26 @@ public class BSCharacter : PhysicsActor
91 private PIDHoverType _PIDHoverType; 75 private PIDHoverType _PIDHoverType;
92 private float _PIDHoverTao; 76 private float _PIDHoverTao;
93 77
94 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) 78 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
95 { 79 {
96 _localID = localID; 80 base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
97 _avName = avName; 81 _physicsActorType = (int)ActorTypes.Agent;
98 _scene = parent_scene;
99 _position = pos; 82 _position = pos;
100 _size = size; 83 _size = size;
101 _flying = isFlying; 84 _flying = isFlying;
102 _orientation = Quaternion.Identity; 85 _orientation = OMV.Quaternion.Identity;
103 _velocity = Vector3.Zero; 86 _velocity = OMV.Vector3.Zero;
104 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 87 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
88
105 // The dimensions of the avatar capsule are kept in the scale. 89 // The dimensions of the avatar capsule are kept in the scale.
106 // Physics creates a unit capsule which is scaled by the physics engine. 90 // Physics creates a unit capsule which is scaled by the physics engine.
107 _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); 91 ComputeAvatarScale(_size);
108 _density = _scene.Params.avatarDensity; 92 _avatarDensity = PhysicsScene.Params.avatarDensity;
109 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 93 // set _avatarVolume and _mass based on capsule size, _density and _scale
94 ComputeAvatarVolumeAndMass();
110 95
111 ShapeData shapeData = new ShapeData(); 96 ShapeData shapeData = new ShapeData();
112 shapeData.ID = _localID; 97 shapeData.ID = LocalID;
113 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; 98 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
114 shapeData.Position = _position; 99 shapeData.Position = _position;
115 shapeData.Rotation = _orientation; 100 shapeData.Rotation = _orientation;
@@ -118,29 +103,35 @@ public class BSCharacter : PhysicsActor
118 shapeData.Mass = _mass; 103 shapeData.Mass = _mass;
119 shapeData.Buoyancy = _buoyancy; 104 shapeData.Buoyancy = _buoyancy;
120 shapeData.Static = ShapeData.numericFalse; 105 shapeData.Static = ShapeData.numericFalse;
121 shapeData.Friction = _scene.Params.avatarFriction; 106 shapeData.Friction = PhysicsScene.Params.avatarFriction;
122 shapeData.Restitution = _scene.Params.avatarRestitution; 107 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
123 108
124 // do actual create at taint time 109 // do actual create at taint time
125 _scene.TaintedObject("BSCharacter.create", delegate() 110 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
126 { 111 {
127 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113 BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
114
115 // Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
116 // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
117 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
118
119 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
128 120
129 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); 121 // This works here because CreateObject has already put the character into the physical world.
130 // avatars get all collisions no matter what 122 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
131 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 123 (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
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 BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
144 }); 135 });
145 } 136 }
146 137
@@ -149,274 +140,357 @@ public class BSCharacter : PhysicsActor
149 base.RequestPhysicsterseUpdate(); 140 base.RequestPhysicsterseUpdate();
150 } 141 }
151 // No one calls this method so I don't know what it could possibly mean 142 // No one calls this method so I don't know what it could possibly mean
152 public override bool Stopped { 143 public override bool Stopped {
153 get { return false; } 144 get { return false; }
154 } 145 }
155 public override Vector3 Size { 146 public override OMV.Vector3 Size {
156 get 147 get
157 { 148 {
158 // Avatar capsule size is kept in the scale parameter. 149 // Avatar capsule size is kept in the scale parameter.
159 return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 150 return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
160 } 151 }
161 152
162 set { 153 set {
163 // When an avatar's size is set, only the height is changed 154 // When an avatar's size is set, only the height is changed
164 // and that really only depends on the radius. 155 // and that really only depends on the radius.
165 _size = value; 156 _size = value;
166 _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 157 ComputeAvatarScale(_size);
167 158
168 // TODO: something has to be done with the avatar's vertical position 159 // TODO: something has to be done with the avatar's vertical position
169 160
170 ComputeAvatarVolumeAndMass(); 161 ComputeAvatarVolumeAndMass();
171 162
172 _scene.TaintedObject("BSCharacter.setSize", delegate() 163 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
173 { 164 {
174 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); 165 BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
175 }); 166 });
176 167
177 } 168 }
178 }
179 public override PrimitiveBaseShape Shape {
180 set { _pbs = value;
181 }
182 } 169 }
183 public override uint LocalID { 170 public override PrimitiveBaseShape Shape {
184 set { _localID = value; 171 set { _pbs = value;
185 } 172 }
186 get { return _localID; }
187 } 173 }
188 public override bool Grabbed { 174 public override bool Grabbed {
189 set { _grabbed = value; 175 set { _grabbed = value;
190 } 176 }
191 } 177 }
192 public override bool Selected { 178 public override bool Selected {
193 set { _selected = value; 179 set { _selected = value;
194 } 180 }
195 } 181 }
196 public override void CrossingFailure() { return; } 182 public override void CrossingFailure() { return; }
197 public override void link(PhysicsActor obj) { return; } 183 public override void link(PhysicsActor obj) { return; }
198 public override void delink() { return; } 184 public override void delink() { return; }
199 public override void LockAngularMotion(Vector3 axis) { return; }
200 185
201 public override Vector3 Position { 186 // Set motion values to zero.
187 // Do it to the properties so the values get set in the physics engine.
188 // Push the setting of the values to the viewer.
189 // Called at taint time!
190 public override void ZeroMotion()
191 {
192 _velocity = OMV.Vector3.Zero;
193 _acceleration = OMV.Vector3.Zero;
194 _rotationalVelocity = OMV.Vector3.Zero;
195
196 // Zero some other properties directly into the physics engine
197 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
198 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
199 BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
200 BulletSimAPI.ClearForces2(BSBody.ptr);
201 }
202
203 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
204
205 public override OMV.Vector3 Position {
202 get { 206 get {
203 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 207 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
204 return _position; 208 return _position;
205 } 209 }
206 set { 210 set {
207 _position = value; 211 _position = value;
208 PositionSanityCheck(); 212 PositionSanityCheck();
209 213
210 _scene.TaintedObject("BSCharacter.setPosition", delegate() 214 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
211 { 215 {
212 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 216 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
213 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 217 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
214 }); 218 });
215 } 219 }
220 }
221 public override OMV.Vector3 ForcePosition {
222 get {
223 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
224 return _position;
225 }
226 set {
227 _position = value;
228 PositionSanityCheck();
229 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
230 }
216 } 231 }
217 232
233
218 // Check that the current position is sane and, if not, modify the position to make it so. 234 // 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. 235 // Check for being below terrain and being out of bounds.
220 // Returns 'true' of the position was made sane by some action. 236 // Returns 'true' of the position was made sane by some action.
221 private bool PositionSanityCheck() 237 private bool PositionSanityCheck()
222 { 238 {
223 bool ret = false; 239 bool ret = false;
224 240
225 // If below the ground, move the avatar up 241 // If below the ground, move the avatar up
226 float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); 242 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
227 if (_position.Z < terrainHeight) 243 if (Position.Z < terrainHeight)
228 { 244 {
229 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); 245 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
230 _position.Z = terrainHeight + 2.0f; 246 _position.Z = terrainHeight + 2.0f;
231 ret = true; 247 ret = true;
232 } 248 }
249 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
250 {
251 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
252 if (Position.Z < waterHeight)
253 {
254 _position.Z = waterHeight;
255 ret = true;
256 }
257 }
233 258
234 // TODO: check for out of bounds 259 // TODO: check for out of bounds
260 return ret;
261 }
235 262
263 // A version of the sanity check that also makes sure a new position value is
264 // pushed back to the physics engine. This routine would be used by anyone
265 // who is not already pushing the value.
266 private bool PositionSanityCheck2(bool atTaintTime)
267 {
268 bool ret = false;
269 if (PositionSanityCheck())
270 {
271 // The new position value must be pushed into the physics engine but we can't
272 // just assign to "Position" because of potential call loops.
273 BSScene.TaintCallback sanityOperation = delegate()
274 {
275 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
277 };
278 if (atTaintTime)
279 sanityOperation();
280 else
281 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
282 ret = true;
283 }
236 return ret; 284 return ret;
237 } 285 }
238 286
239 public override float Mass { 287 public override float Mass {
240 get { 288 get {
241 return _mass; 289 return _mass;
242 } 290 }
243 } 291 }
244 public override Vector3 Force { 292
245 get { return _force; } 293 // used when we only want this prim's mass and not the linkset thing
294 public override float MassRaw { get {return _mass; } }
295
296 public override OMV.Vector3 Force {
297 get { return _force; }
246 set { 298 set {
247 _force = value; 299 _force = value;
248 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 300 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
249 Scene.TaintedObject("BSCharacter.SetForce", delegate() 301 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
250 { 302 {
251 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 303 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
252 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); 304 BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
253 }); 305 });
254 } 306 }
255 } 307 }
256 308
257 public override int VehicleType { 309 public override int VehicleType {
258 get { return 0; } 310 get { return 0; }
259 set { return; } 311 set { return; }
260 } 312 }
261 public override void VehicleFloatParam(int param, float value) { } 313 public override void VehicleFloatParam(int param, float value) { }
262 public override void VehicleVectorParam(int param, Vector3 value) {} 314 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
263 public override void VehicleRotationParam(int param, Quaternion rotation) { } 315 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
264 public override void VehicleFlags(int param, bool remove) { } 316 public override void VehicleFlags(int param, bool remove) { }
265 317
266 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 318 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
267 public override void SetVolumeDetect(int param) { return; } 319 public override void SetVolumeDetect(int param) { return; }
268 320
269 public override Vector3 GeometricCenter { get { return Vector3.Zero; } } 321 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
270 public override Vector3 CenterOfMass { get { return Vector3.Zero; } } 322 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
271 public override Vector3 Velocity { 323 public override OMV.Vector3 Velocity {
272 get { return _velocity; } 324 get { return _velocity; }
273 set { 325 set {
274 _velocity = value; 326 _velocity = value;
275 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 327 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
276 _scene.TaintedObject("BSCharacter.setVelocity", delegate() 328 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
277 { 329 {
278 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 330 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
279 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); 331 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
280 }); 332 });
281 } 333 }
282 } 334 }
283 public override Vector3 Torque { 335 public override OMV.Vector3 Torque {
284 get { return _torque; } 336 get { return _torque; }
285 set { _torque = value; 337 set { _torque = value;
286 } 338 }
287 } 339 }
288 public override float CollisionScore { 340 public override float CollisionScore {
289 get { return _collisionScore; } 341 get { return _collisionScore; }
290 set { _collisionScore = value; 342 set { _collisionScore = value;
291 } 343 }
292 } 344 }
293 public override Vector3 Acceleration { 345 public override OMV.Vector3 Acceleration {
294 get { return _acceleration; } 346 get { return _acceleration; }
295 set { _acceleration = value; } 347 set { _acceleration = value; }
296 } 348 }
297 public override Quaternion Orientation { 349 public override OMV.Quaternion Orientation {
298 get { return _orientation; } 350 get { return _orientation; }
299 set { 351 set {
300 _orientation = value; 352 _orientation = value;
301 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 353 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
302 _scene.TaintedObject("BSCharacter.setOrientation", delegate() 354 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
303 { 355 {
304 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 356 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
305 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 357 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
306 }); 358 });
307 } 359 }
360 }
361 // Go directly to Bullet to get/set the value.
362 public override OMV.Quaternion ForceOrientation
363 {
364 get
365 {
366 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
367 return _orientation;
368 }
369 set
370 {
371 _orientation = value;
372 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
373 }
308 } 374 }
309 public override int PhysicsActorType { 375 public override int PhysicsActorType {
310 get { return _physicsActorType; } 376 get { return _physicsActorType; }
311 set { _physicsActorType = value; 377 set { _physicsActorType = value;
312 } 378 }
313 } 379 }
314 public override bool IsPhysical { 380 public override bool IsPhysical {
315 get { return _isPhysical; } 381 get { return _isPhysical; }
316 set { _isPhysical = value; 382 set { _isPhysical = value;
317 } 383 }
318 } 384 }
319 public override bool Flying { 385 public override bool Flying {
320 get { return _flying; } 386 get { return _flying; }
321 set { 387 set {
322 if (_flying != value) 388 _flying = value;
323 { 389 // simulate flying by changing the effect of gravity
324 _flying = value; 390 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
325 // simulate flying by changing the effect of gravity 391 }
326 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
327 }
328 }
329 } 392 }
393 // Flying is implimented by changing the avatar's buoyancy.
394 // Would this be done better with a vehicle type?
330 private float ComputeBuoyancyFromFlying(bool ifFlying) { 395 private float ComputeBuoyancyFromFlying(bool ifFlying) {
331 return ifFlying ? 1f : 0f; 396 return ifFlying ? 1f : 0f;
332 } 397 }
333 public override bool 398 public override bool
334 SetAlwaysRun { 399 SetAlwaysRun {
335 get { return _setAlwaysRun; } 400 get { return _setAlwaysRun; }
336 set { _setAlwaysRun = value; } 401 set { _setAlwaysRun = value; }
337 } 402 }
338 public override bool ThrottleUpdates { 403 public override bool ThrottleUpdates {
339 get { return _throttleUpdates; } 404 get { return _throttleUpdates; }
340 set { _throttleUpdates = value; } 405 set { _throttleUpdates = value; }
341 } 406 }
342 public override bool IsColliding { 407 public override bool IsColliding {
343 get { return (_collidingStep == _scene.SimulationStep); } 408 get { return (CollidingStep == PhysicsScene.SimulationStep); }
344 set { _isColliding = value; } 409 set { _isColliding = value; }
345 } 410 }
346 public override bool CollidingGround { 411 public override bool CollidingGround {
347 get { return (_collidingGroundStep == _scene.SimulationStep); } 412 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
348 set { _collidingGround = value; } 413 set { CollidingGround = value; }
349 } 414 }
350 public override bool CollidingObj { 415 public override bool CollidingObj {
351 get { return _collidingObj; } 416 get { return _collidingObj; }
352 set { _collidingObj = value; } 417 set { _collidingObj = value; }
353 } 418 }
354 public override bool FloatOnWater { 419 public override bool FloatOnWater {
355 set { _floatOnWater = value; } 420 set {
421 _floatOnWater = value;
422 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
423 {
424 if (_floatOnWater)
425 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
426 else
427 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
428 });
429 }
356 } 430 }
357 public override Vector3 RotationalVelocity { 431 public override OMV.Vector3 RotationalVelocity {
358 get { return _rotationalVelocity; } 432 get { return _rotationalVelocity; }
359 set { _rotationalVelocity = value; } 433 set { _rotationalVelocity = value; }
360 } 434 }
361 public override bool Kinematic { 435 public override bool Kinematic {
362 get { return _kinematic; } 436 get { return _kinematic; }
363 set { _kinematic = value; } 437 set { _kinematic = value; }
364 } 438 }
365 // neg=fall quickly, 0=1g, 1=0g, pos=float up 439 // neg=fall quickly, 0=1g, 1=0g, pos=float up
366 public override float Buoyancy { 440 public override float Buoyancy {
367 get { return _buoyancy; } 441 get { return _buoyancy; }
368 set { _buoyancy = value; 442 set { _buoyancy = value;
369 _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() 443 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
370 { 444 {
371 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 445 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
372 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); 446 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
373 }); 447 });
374 } 448 }
375 } 449 }
376 450
377 // Used for MoveTo 451 // Used for MoveTo
378 public override Vector3 PIDTarget { 452 public override OMV.Vector3 PIDTarget {
379 set { _PIDTarget = value; } 453 set { _PIDTarget = value; }
380 } 454 }
381 public override bool PIDActive { 455 public override bool PIDActive {
382 set { _usePID = value; } 456 set { _usePID = value; }
383 } 457 }
384 public override float PIDTau { 458 public override float PIDTau {
385 set { _PIDTau = value; } 459 set { _PIDTau = value; }
386 } 460 }
387 461
388 // Used for llSetHoverHeight and maybe vehicle height 462 // Used for llSetHoverHeight and maybe vehicle height
389 // Hover Height will override MoveTo target's Z 463 // Hover Height will override MoveTo target's Z
390 public override bool PIDHoverActive { 464 public override bool PIDHoverActive {
391 set { _useHoverPID = value; } 465 set { _useHoverPID = value; }
392 } 466 }
393 public override float PIDHoverHeight { 467 public override float PIDHoverHeight {
394 set { _PIDHoverHeight = value; } 468 set { _PIDHoverHeight = value; }
395 } 469 }
396 public override PIDHoverType PIDHoverType { 470 public override PIDHoverType PIDHoverType {
397 set { _PIDHoverType = value; } 471 set { _PIDHoverType = value; }
398 } 472 }
399 public override float PIDHoverTau { 473 public override float PIDHoverTau {
400 set { _PIDHoverTao = value; } 474 set { _PIDHoverTao = value; }
401 } 475 }
402 476
403 // For RotLookAt 477 // For RotLookAt
404 public override Quaternion APIDTarget { set { return; } } 478 public override OMV.Quaternion APIDTarget { set { return; } }
405 public override bool APIDActive { set { return; } } 479 public override bool APIDActive { set { return; } }
406 public override float APIDStrength { set { return; } } 480 public override float APIDStrength { set { return; } }
407 public override float APIDDamping { set { return; } } 481 public override float APIDDamping { set { return; } }
408 482
409 public override void AddForce(Vector3 force, bool pushforce) { 483 public override void AddForce(OMV.Vector3 force, bool pushforce) {
410 if (force.IsFinite()) 484 if (force.IsFinite())
411 { 485 {
412 _force.X += force.X; 486 _force.X += force.X;
413 _force.Y += force.Y; 487 _force.Y += force.Y;
414 _force.Z += force.Z; 488 _force.Z += force.Z;
415 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 489 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
416 _scene.TaintedObject("BSCharacter.AddForce", delegate() 490 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
417 { 491 {
418 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 492 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
419 BulletSimAPI.AddObjectForce2(Body.Ptr, _force); 493 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
420 }); 494 });
421 } 495 }
422 else 496 else
@@ -426,37 +500,19 @@ public class BSCharacter : PhysicsActor
426 //m_lastUpdateSent = false; 500 //m_lastUpdateSent = false;
427 } 501 }
428 502
429 public override void AddAngularForce(Vector3 force, bool pushforce) { 503 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
430 } 504 }
431 public override void SetMomentum(Vector3 momentum) { 505 public override void SetMomentum(OMV.Vector3 momentum) {
432 } 506 }
433 507
434 // Turn on collision events at a rate no faster than one every the given milliseconds 508 private void ComputeAvatarScale(OMV.Vector3 size)
435 public override void SubscribeEvents(int ms) { 509 {
436 _subscribedEventsMs = ms; 510 _scale.X = PhysicsScene.Params.avatarCapsuleRadius;
437 if (ms > 0) 511 _scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
438 {
439 // make sure first collision happens
440 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
441 512
442 Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() 513 // The 1.15 came from ODE but it seems to cause the avatar to float off the ground
443 { 514 // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
444 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 515 _scale.Z = (_size.Z) - (_scale.X + _scale.Y);
445 });
446 }
447 }
448 // Stop collision events
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 } 516 }
461 517
462 // set _avatarVolume and _mass based on capsule size, _density and _scale 518 // set _avatarVolume and _mass based on capsule size, _density and _scale
@@ -473,82 +529,26 @@ public class BSCharacter : PhysicsActor
473 * Math.Min(_scale.X, _scale.Y) 529 * Math.Min(_scale.X, _scale.Y)
474 * _scale.Y // plus the volume of the capsule end caps 530 * _scale.Y // plus the volume of the capsule end caps
475 ); 531 );
476 _mass = _density * _avatarVolume; 532 _mass = _avatarDensity * _avatarVolume;
477 } 533 }
478 534
479 // The physics engine says that properties have updated. Update same and inform 535 // The physics engine says that properties have updated. Update same and inform
480 // the world that things have changed. 536 // the world that things have changed.
481 public void UpdateProperties(EntityProperties entprop) 537 public override void UpdateProperties(EntityProperties entprop)
482 { 538 {
483 _position = entprop.Position; 539 _position = entprop.Position;
484 _orientation = entprop.Rotation; 540 _orientation = entprop.Rotation;
485 _velocity = entprop.Velocity; 541 _velocity = entprop.Velocity;
486 _acceleration = entprop.Acceleration; 542 _acceleration = entprop.Acceleration;
487 _rotationalVelocity = entprop.RotationalVelocity; 543 _rotationalVelocity = entprop.RotationalVelocity;
544 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
545 PositionSanityCheck2(true);
546
488 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 547 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
489 // base.RequestPhysicsterseUpdate(); 548 // base.RequestPhysicsterseUpdate();
490 549
491 /*
492 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 550 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
493 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 551 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
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
506 // The following makes IsColliding() and IsCollidingGround() work
507 _collidingStep = _scene.SimulationStep;
508 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
509 {
510 _collidingGroundStep = _scene.SimulationStep;
511 }
512 // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
513
514 // throttle collisions to the rate specified in the subscription
515 if (_subscribedEventsMs != 0) {
516 int nowTime = _scene.SimulationNowTime;
517 if (nowTime >= _nextCollisionOkTime) {
518 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
519
520 if (collisionCollection == null)
521 collisionCollection = new CollisionEventUpdate();
522 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
523 }
524 }
525 }
526
527 public void SendCollisions()
528 {
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 } 552 }
553} 553}
554} 554}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 25084d8..63a4127 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -48,22 +48,24 @@ public abstract class BSConstraint : IDisposable
48 { 48 {
49 if (m_enabled) 49 if (m_enabled)
50 { 50 {
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; 51 m_enabled = false;
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
53 m_world.physicsScene.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;
56 } 55 }
57 } 56 }
58 57
59 public BulletBody Body1 { get { return m_body1; } } 58 public BulletBody Body1 { get { return m_body1; } }
60 public BulletBody Body2 { get { return m_body2; } } 59 public BulletBody Body2 { get { return m_body2; } }
60 public BulletConstraint Constraint { get { return m_constraint; } }
61 public abstract ConstraintType Type { get; }
62
61 63
62 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 64 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
63 { 65 {
64 bool ret = false; 66 bool ret = false;
65 if (m_enabled) 67 if (m_enabled)
66 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); 68 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
67 return ret; 69 return ret;
68 } 70 }
69 71
@@ -71,7 +73,18 @@ public abstract class BSConstraint : IDisposable
71 { 73 {
72 bool ret = false; 74 bool ret = false;
73 if (m_enabled) 75 if (m_enabled)
74 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); 76 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
77 return ret;
78 }
79
80 public virtual bool SetSolverIterations(float cnt)
81 {
82 bool ret = false;
83 if (m_enabled)
84 {
85 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
86 ret = true;
87 }
75 return ret; 88 return ret;
76 } 89 }
77 90
@@ -81,7 +94,7 @@ public abstract class BSConstraint : IDisposable
81 if (m_enabled) 94 if (m_enabled)
82 { 95 {
83 // Recompute the internal transforms 96 // Recompute the internal transforms
84 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); 97 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
85 ret = true; 98 ret = true;
86 } 99 }
87 return ret; 100 return ret;
@@ -97,13 +110,14 @@ public abstract class BSConstraint : IDisposable
97 ret = CalculateTransforms(); 110 ret = CalculateTransforms();
98 if (ret) 111 if (ret)
99 { 112 {
100 // m_world.scene.PhysicsLogging.Write("{0},BSConstraint.RecomputeConstraintVariables,taint,enabling,A={1},B={2}", 113 // Setting an object's mass to zero (making it static like when it's selected)
101 // BSScene.DetailLogZero, Body1.ID, Body2.ID); 114 // automatically disables the constraints.
102 BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); 115 // If the link is enabled, be sure to set the constraint itself to enabled.
116 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
103 } 117 }
104 else 118 else
105 { 119 {
106 m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 120 m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
107 } 121 }
108 } 122 }
109 return ret; 123 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5a9f135..4ba2f62 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -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)
123 {
124 PhysicsScene = myScene;
125 Prim = myPrim;
126 Type = Vehicle.TYPE_NONE;
127 }
128
129 // Return 'true' if this vehicle is doing vehicle things
130 public bool IsActive
128 { 131 {
129 m_prim = myPrim; 132 get { return Type != Vehicle.TYPE_NONE; }
130 m_type = Vehicle.TYPE_NONE;
131 } 133 }
132 134
133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep) 135 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
134 { 136 {
135 DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 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 }
322 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
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 } 273 }
332 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) 274 else
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,66 @@ 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 torque action introduced by Bullet.
466 Vector3 inertia = Vector3.Zero;
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
469 }
607 470
608 frcount++; // used to limit debug comment output 471 // One step of the vehicle properties for the next 'pTimestep' seconds.
609 if (frcount > 100) 472 internal void Step(float pTimestep)
610 frcount = 0; 473 {
474 if (!IsActive) return;
611 475
612 MoveLinear(pTimestep); 476 MoveLinear(pTimestep);
613 MoveAngular(pTimestep); 477 MoveAngular(pTimestep);
614 LimitRotation(pTimestep); 478 LimitRotation(pTimestep);
615 479
616 DetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 480 // 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); 481 m_lastPositionVector = Prim.ForcePosition;
482
483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
484 Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity);
618 }// end Step 485 }// end Step
619 486
487 // Apply the effect of the linear motor.
488 // Also does hover and float.
620 private void MoveLinear(float pTimestep) 489 private void MoveLinear(float pTimestep)
621 { 490 {
622 // requested m_linearMotorDirection is significant 491 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
623 // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) 492 // m_lastLinearVelocityVector is the speed we are moving in that direction
624 if (m_linearMotorDirection.LengthSquared() > 0.0001f) 493 if (m_linearMotorDirection.LengthSquared() > 0.001f)
625 { 494 {
626 Vector3 origDir = m_linearMotorDirection; 495 Vector3 origDir = m_linearMotorDirection;
627 Vector3 origVel = m_lastLinearVelocityVector; 496 Vector3 origVel = m_lastLinearVelocityVector;
628 497
629 // add drive to body 498 // add drive to body
630 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); 499 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep);
631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale); 500 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep);
632 // lastLinearVelocityVector is the current body velocity vector? 501 // lastLinearVelocityVector is the current body velocity vector
633 // RA: Not sure what the *10 is for. A correction for pTimestep? 502 // RA: Not sure what the *10 is for. A correction for pTimestep?
634 // m_lastLinearVelocityVector += (addAmount*10); 503 // m_lastLinearVelocityVector += (addAmount*10);
635 m_lastLinearVelocityVector += addAmount; 504 m_lastLinearVelocityVector += addAmount;
636 505
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 506 // 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)) 507 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
641 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 508 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
@@ -644,124 +511,87 @@ namespace OpenSim.Region.Physics.BulletSPlugin
644 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) 511 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
645 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; 512 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
646 513
514 /*
647 // decay applied velocity 515 // decay applied velocity
648 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); 516 Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep);
517 // (RA: do not know where the 0.5f comes from)
649 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 518 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 */ 519 */
520 float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep));
521 m_linearMotorDirection *= keepfraction;
659 522
660 DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}", 523 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); 524 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
662 } 525 }
663 else 526 else
664 { 527 {
665 // if what remains of applied is small, zero it. 528 // 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; 529 m_linearMotorDirection = Vector3.Zero;
669 m_lastLinearVelocityVector = Vector3.Zero; 530 m_lastLinearVelocityVector = Vector3.Zero;
531 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
670 } 532 }
671 533
672 // convert requested object velocity to world-referenced vector 534 // convert requested object velocity to object relative vector
673 Quaternion rotq = m_prim.Orientation; 535 Quaternion rotq = Prim.ForceOrientation;
674 m_dir = m_lastLinearVelocityVector * rotq; 536 m_newVelocity = m_lastLinearVelocityVector * rotq;
675 537
676 // Add the various forces into m_dir which will be our new direction vector (velocity) 538 // Add the various forces into m_dir which will be our new direction vector (velocity)
677 539
678 // add Gravity and Buoyancy 540 // 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. 541 // There is some gravity, make a gravity force vector that is applied after object velocity.
684 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
685 grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy); 543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy));
544
545 /*
546 * RA: Not sure why one would do this
686 // Preserve the current Z velocity 547 // Preserve the current Z velocity
687 Vector3 vel_now = m_prim.Velocity; 548 Vector3 vel_now = m_prim.Velocity;
688 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 549 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
550 */
689 551
690 Vector3 pos = m_prim.Position; 552 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); 553// 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 554
730 // If below the terrain, move us above the ground a little. 555 // If below the terrain, move us above the ground a little.
731 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) 556 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
557 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
558 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
559 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
560 // if (rotatedSize.Z < terrainHeight)
561 if (pos.Z < terrainHeight)
732 { 562 {
733 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; 563 pos.Z = terrainHeight + 2;
734 m_prim.Position = pos; 564 Prim.ForcePosition = pos;
735 DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); 565 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
736 } 566 }
737 567
738 // Check if hovering 568 // Check if hovering
739 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 569 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
740 { 570 {
741 // We should hover, get the target height 571 // We should hover, get the target height
742 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) 572 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
743 { 573 {
744 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight; 574 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
745 } 575 }
746 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 576 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
747 { 577 {
748 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 578 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight;
749 } 579 }
750 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 580 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
751 { 581 {
752 m_VhoverTargetHeight = m_VhoverHeight; 582 m_VhoverTargetHeight = m_VhoverHeight;
753 } 583 }
754 584
755 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) 585 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
756 { 586 {
757 // If body is aready heigher, use its height as target height 587 // If body is aready heigher, use its height as target height
758 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; 588 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
759 } 589 }
760 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 590 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
761 { 591 {
762 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 592 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
763 { 593 {
764 m_prim.Position = pos; 594 Prim.ForcePosition = pos;
765 } 595 }
766 } 596 }
767 else 597 else
@@ -770,85 +600,99 @@ namespace OpenSim.Region.Physics.BulletSPlugin
770 // Replace Vertical speed with correction figure if significant 600 // Replace Vertical speed with correction figure if significant
771 if (Math.Abs(herr0) > 0.01f) 601 if (Math.Abs(herr0) > 0.01f)
772 { 602 {
773 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 603 m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
774 //KF: m_VhoverEfficiency is not yet implemented 604 //KF: m_VhoverEfficiency is not yet implemented
775 } 605 }
776 else 606 else
777 { 607 {
778 m_dir.Z = 0f; 608 m_newVelocity.Z = 0f;
779 } 609 }
780 } 610 }
781 611
782 DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight); 612 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
613 }
783 614
784// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped 615 Vector3 posChange = pos - m_lastPositionVector;
785// m_VhoverTimescale = 0f; // time to acheive height 616 if (m_BlockingEndPoint != Vector3.Zero)
786// pTimestep is time since last frame,in secs 617 {
618 bool changed = false;
619 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
620 {
621 pos.X -= posChange.X + 1;
622 changed = true;
623 }
624 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
625 {
626 pos.Y -= posChange.Y + 1;
627 changed = true;
628 }
629 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
630 {
631 pos.Z -= posChange.Z + 1;
632 changed = true;
633 }
634 if (pos.X <= 0)
635 {
636 pos.X += posChange.X + 1;
637 changed = true;
638 }
639 if (pos.Y <= 0)
640 {
641 pos.Y += posChange.Y + 1;
642 changed = true;
643 }
644 if (changed)
645 {
646 Prim.ForcePosition = pos;
647 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
648 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
649 }
787 } 650 }
788 651
652 // Limit absolute vertical change
653 float Zchange = Math.Abs(posChange.Z);
789 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 654 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
790 { 655 {
791 //Start Experimental Values
792 if (Zchange > .3) 656 if (Zchange > .3)
793 {
794 grav.Z = (float)(grav.Z * 3); 657 grav.Z = (float)(grav.Z * 3);
795 }
796 if (Zchange > .15) 658 if (Zchange > .15)
797 {
798 grav.Z = (float)(grav.Z * 2); 659 grav.Z = (float)(grav.Z * 2);
799 }
800 if (Zchange > .75) 660 if (Zchange > .75)
801 {
802 grav.Z = (float)(grav.Z * 1.5); 661 grav.Z = (float)(grav.Z * 1.5);
803 }
804 if (Zchange > .05) 662 if (Zchange > .05)
805 {
806 grav.Z = (float)(grav.Z * 1.25); 663 grav.Z = (float)(grav.Z * 1.25);
807 }
808 if (Zchange > .025) 664 if (Zchange > .025)
809 {
810 grav.Z = (float)(grav.Z * 1.125); 665 grav.Z = (float)(grav.Z * 1.125);
811 } 666 float postemp = (pos.Z - terrainHeight);
812 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
813 float postemp = (pos.Z - terraintemp);
814 if (postemp > 2.5f) 667 if (postemp > 2.5f)
815 {
816 grav.Z = (float)(grav.Z * 1.037125); 668 grav.Z = (float)(grav.Z * 1.037125);
817 } 669 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 } 670 }
671
672 // If not changing some axis, reduce out velocity
821 if ((m_flags & (VehicleFlag.NO_X)) != 0) 673 if ((m_flags & (VehicleFlag.NO_X)) != 0)
822 { 674 m_newVelocity.X = 0;
823 m_dir.X = 0;
824 }
825 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 675 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
826 { 676 m_newVelocity.Y = 0;
827 m_dir.Y = 0;
828 }
829 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 677 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
830 { 678 m_newVelocity.Z = 0;
831 m_dir.Z = 0;
832 }
833
834 m_lastPositionVector = m_prim.Position;
835 679
836 // Apply velocity 680 // Apply velocity
837 m_prim.Velocity = m_dir; 681 Prim.Velocity = m_newVelocity;
838 // apply gravity force 682 // apply gravity force
839 // Why is this set here? The physics engine already does gravity. 683 // Why is this set here? The physics engine already does gravity.
840 // m_prim.AddForce(grav, false); 684 // m_prim.AddForce(grav, false);
841 // m_prim.Force = grav;
842 685
843 // Apply friction 686 // Apply friction
844 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); 687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
845 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; 688 m_lastLinearVelocityVector *= keepFraction;
846 689
847 DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}", 690 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
848 m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount); 691 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
849 692
850 } // end MoveLinear() 693 } // end MoveLinear()
851 694
695 // Apply the effect of the angular motor.
852 private void MoveAngular(float pTimestep) 696 private void MoveAngular(float pTimestep)
853 { 697 {
854 // m_angularMotorDirection // angular velocity requested by LSL motor 698 // m_angularMotorDirection // angular velocity requested by LSL motor
@@ -860,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
860 // m_lastAngularVelocity // what was last applied to body 704 // m_lastAngularVelocity // what was last applied to body
861 705
862 // Get what the body is doing, this includes 'external' influences 706 // Get what the body is doing, this includes 'external' influences
863 Vector3 angularVelocity = m_prim.RotationalVelocity; 707 Vector3 angularVelocity = Prim.RotationalVelocity;
864 708
865 if (m_angularMotorApply > 0) 709 if (m_angularMotorApply > 0)
866 { 710 {
@@ -868,48 +712,58 @@ namespace OpenSim.Region.Physics.BulletSPlugin
868 // a newly set velocity, this routine steps the value from the previous 712 // a newly set velocity, this routine steps the value from the previous
869 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). 713 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
870 // There are m_angularMotorApply steps. 714 // There are m_angularMotorApply steps.
871 Vector3 origAngularVelocity = m_angularMotorVelocity; 715 Vector3 origVel = m_angularMotorVelocity;
716 Vector3 origDir = m_angularMotorDirection;
717
872 // ramp up to new value 718 // ramp up to new value
873 // current velocity += error / (time to get there / step interval) 719 // new velocity += error / ( time to get there / step interval)
874 // requested speed - last motor speed 720 // requested speed - last motor speed
875 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 721 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); 722 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); 723 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
878 724
879 DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}", 725 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); 726 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
881 727
882 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected 728 m_angularMotorApply--;
883 // velocity may still be acheived.
884 } 729 }
885 else 730 else
886 { 731 {
887 // No motor recently applied, keep the body velocity 732 // No motor recently applied, keep the body velocity
888 // and decay the velocity 733 // and decay the velocity
889 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 734 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
735 if (m_angularMotorVelocity.LengthSquared() < 0.00001)
736 m_angularMotorVelocity = Vector3.Zero;
890 } // end motor section 737 } // end motor section
891 738
892 // Vertical attractor section 739 // Vertical attractor section
893 Vector3 vertattr = Vector3.Zero; 740 Vector3 vertattr = Vector3.Zero;
894 if (m_verticalAttractionTimescale < 300) 741 Vector3 deflection = Vector3.Zero;
742 Vector3 banking = Vector3.Zero;
743
744 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
895 { 745 {
896 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); 746 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
747 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
748
897 // get present body rotation 749 // get present body rotation
898 Quaternion rotq = m_prim.Orientation; 750 Quaternion rotq = Prim.ForceOrientation;
899 // make a vector pointing up 751 // vector pointing up
900 Vector3 verterr = Vector3.Zero; 752 Vector3 verterr = Vector3.Zero;
901 verterr.Z = 1.0f; 753 verterr.Z = 1.0f;
754
902 // rotate it to Body Angle 755 // rotate it to Body Angle
903 verterr = verterr * rotq; 756 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. 757 // 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 758 // 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. 759 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
760
761 // Error is 0 (no error) to +/- 2 (max error)
907 if (verterr.Z < 0.0f) 762 if (verterr.Z < 0.0f)
908 { 763 {
909 verterr.X = 2.0f - verterr.X; 764 verterr.X = 2.0f - verterr.X;
910 verterr.Y = 2.0f - verterr.Y; 765 verterr.Y = 2.0f - verterr.Y;
911 } 766 }
912 // Error is 0 (no error) to +/- 2 (max error)
913 // scale it by VAservo 767 // scale it by VAservo
914 verterr = verterr * VAservo; 768 verterr = verterr * VAservo;
915 769
@@ -924,12 +778,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
924 vertattr.X += bounce * angularVelocity.X; 778 vertattr.X += bounce * angularVelocity.X;
925 vertattr.Y += bounce * angularVelocity.Y; 779 vertattr.Y += bounce * angularVelocity.Y;
926 780
927 DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 781 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
928 m_prim.LocalID, verterr, bounce, vertattr); 782 Prim.LocalID, verterr, bounce, vertattr);
929 783
930 } // else vertical attractor is off 784 } // else vertical attractor is off
931 785
932 // m_lastVertAttractor = vertattr; 786 m_lastVertAttractor = vertattr;
933 787
934 // Bank section tba 788 // Bank section tba
935 789
@@ -937,18 +791,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
937 791
938 // Sum velocities 792 // Sum velocities
939 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 793 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
940 794
941 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 795 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
942 { 796 {
943 m_lastAngularVelocity.X = 0; 797 m_lastAngularVelocity.X = 0;
944 m_lastAngularVelocity.Y = 0; 798 m_lastAngularVelocity.Y = 0;
945 DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 799 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
946 } 800 }
947 801
948 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 802 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
949 { 803 {
950 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 804 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
951 DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 805 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
952 } 806 }
953 807
954 // apply friction 808 // apply friction
@@ -956,14 +810,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
956 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
957 811
958 // Apply to the body 812 // Apply to the body
959 m_prim.RotationalVelocity = m_lastAngularVelocity; 813 Prim.RotationalVelocity = m_lastAngularVelocity;
960 814
961 DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); 815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
962 } //end MoveAngular 816 } //end MoveAngular
963 817
964 internal void LimitRotation(float timestep) 818 internal void LimitRotation(float timestep)
965 { 819 {
966 Quaternion rotq = m_prim.Orientation; 820 Quaternion rotq = Prim.ForceOrientation;
967 Quaternion m_rot = rotq; 821 Quaternion m_rot = rotq;
968 bool changed = false; 822 bool changed = false;
969 if (m_RollreferenceFrame != Quaternion.Identity) 823 if (m_RollreferenceFrame != Quaternion.Identity)
@@ -996,23 +850,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
996 m_rot.Y = 0; 850 m_rot.Y = 0;
997 changed = true; 851 changed = true;
998 } 852 }
999 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 853 if (changed)
1000 { 854 {
1001 m_rot.X = 0; 855 Prim.ForceOrientation = m_rot;
1002 m_rot.Y = 0; 856 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1003 changed = true;
1004 } 857 }
1005 if (changed)
1006 m_prim.Orientation = m_rot;
1007 858
1008 DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
1009 } 859 }
1010 860
1011 // Invoke the detailed logger and output something if it's enabled. 861 // Invoke the detailed logger and output something if it's enabled.
1012 private void DetailLog(string msg, params Object[] args) 862 private void VDetailLog(string msg, params Object[] args)
1013 { 863 {
1014 if (m_prim.Scene.VehicleLoggingEnabled) 864 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1015 m_prim.Scene.PhysicsLogging.Write(msg, args); 865 Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
1016 } 866 }
1017 } 867 }
1018} 868}
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..3e82642 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -34,16 +34,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public 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 public BSPhysObject LinksetRoot { get; protected set; }
40 public BSPrim LinksetRoot { get { return m_linksetRoot; } }
41 40
42 private BSScene m_physicsScene; 41 public BSScene PhysicsScene { get; private set; }
43 public BSScene PhysicsScene { get { return m_physicsScene; } }
44 42
45 // The children under the root in this linkset 43 static int m_nextLinksetID = 1;
46 private List<BSPrim> m_children; 44 public int LinksetID { get; private set; }
45
46 // The children under the root in this linkset.
47 // There are two lists of children: the current children at runtime
48 // and the children at taint-time. For instance, if you delink a
49 // child from the linkset, the child is removed from m_children
50 // but the constraint won't be removed until taint time.
51 // Two lists lets this track the 'current' children and
52 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these
54 // two lists must be the same.
55 private List<BSPhysObject> m_children;
56 private List<BSPhysObject> m_taintChildren;
47 57
48 // We lock the diddling of linkset classes to prevent any badness. 58 // We lock the diddling of linkset classes to prevent any badness.
49 // This locks the modification of the instances of this class. Changes 59 // This locks the modification of the instances of this class. Changes
@@ -52,9 +62,9 @@ public class BSLinkset
52 62
53 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
54 private float m_mass; 64 private float m_mass;
55 public float LinksetMass 65 public float LinksetMass
56 { 66 {
57 get 67 get
58 { 68 {
59 m_mass = ComputeLinksetMass(); 69 m_mass = ComputeLinksetMass();
60 return m_mass; 70 return m_mass;
@@ -71,23 +81,31 @@ public class BSLinkset
71 get { return ComputeLinksetGeometricCenter(); } 81 get { return ComputeLinksetGeometricCenter(); }
72 } 82 }
73 83
74 public BSLinkset(BSScene scene, BSPrim parent) 84 public BSLinkset(BSScene scene, BSPhysObject parent)
75 { 85 {
76 // A simple linkset of one (no children) 86 // A simple linkset of one (no children)
77 m_physicsScene = scene; 87 LinksetID = m_nextLinksetID++;
78 m_linksetRoot = parent; 88 // We create LOTS of linksets.
79 m_children = new List<BSPrim>(); 89 if (m_nextLinksetID <= 0)
90 m_nextLinksetID = 1;
91 PhysicsScene = scene;
92 LinksetRoot = parent;
93 m_children = new List<BSPhysObject>();
94 m_taintChildren = new List<BSPhysObject>();
80 m_mass = parent.MassRaw; 95 m_mass = parent.MassRaw;
81 } 96 }
82 97
83 // Link to a linkset where the child knows the parent. 98 // Link to a linkset where the child knows the parent.
84 // Parent changing should not happen so do some sanity checking. 99 // Parent changing should not happen so do some sanity checking.
85 // We return the parent's linkset so the child can track its membership. 100 // We return the parent's linkset so the child can track its membership.
86 public BSLinkset AddMeToLinkset(BSPrim child) 101 // Called at runtime.
102 public BSLinkset AddMeToLinkset(BSPhysObject child)
87 { 103 {
88 lock (m_linksetActivityLock) 104 lock (m_linksetActivityLock)
89 { 105 {
90 AddChildToLinkset(child); 106 // Don't add the root to its own linkset
107 if (!IsRoot(child))
108 AddChildToLinkset(child);
91 } 109 }
92 return this; 110 return this;
93 } 111 }
@@ -95,26 +113,18 @@ public class BSLinkset
95 // Remove a child from a linkset. 113 // Remove a child from a linkset.
96 // Returns a new linkset for the child which is a linkset of one (just the 114 // Returns a new linkset for the child which is a linkset of one (just the
97 // orphened child). 115 // orphened child).
98 public BSLinkset RemoveMeFromLinkset(BSPrim child) 116 // Called at runtime.
117 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
99 { 118 {
100 lock (m_linksetActivityLock) 119 lock (m_linksetActivityLock)
101 { 120 {
102 if (IsRoot(child)) 121 if (IsRoot(child))
103 { 122 {
104 // if root of linkset, take the linkset apart 123 // Cannot remove the root from a linkset.
105 while (m_children.Count > 0) 124 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 } 125 }
126
127 RemoveChildFromLinkset(child);
118 } 128 }
119 129
120 // The child is down to a linkset of just itself 130 // The child is down to a linkset of just itself
@@ -122,9 +132,9 @@ public class BSLinkset
122 } 132 }
123 133
124 // Return 'true' if the passed object is the root object of this linkset 134 // Return 'true' if the passed object is the root object of this linkset
125 public bool IsRoot(BSPrim requestor) 135 public bool IsRoot(BSPhysObject requestor)
126 { 136 {
127 return (requestor.LocalID == m_linksetRoot.LocalID); 137 return (requestor.LocalID == LinksetRoot.LocalID);
128 } 138 }
129 139
130 public int NumberOfChildren { get { return m_children.Count; } } 140 public int NumberOfChildren { get { return m_children.Count; } }
@@ -133,12 +143,12 @@ public class BSLinkset
133 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 143 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
134 144
135 // Return 'true' if this child is in this linkset 145 // Return 'true' if this child is in this linkset
136 public bool HasChild(BSPrim child) 146 public bool HasChild(BSPhysObject child)
137 { 147 {
138 bool ret = false; 148 bool ret = false;
139 lock (m_linksetActivityLock) 149 lock (m_linksetActivityLock)
140 { 150 {
141 foreach (BSPrim bp in m_children) 151 foreach (BSPhysObject bp in m_children)
142 { 152 {
143 if (child.LocalID == bp.LocalID) 153 if (child.LocalID == bp.LocalID)
144 { 154 {
@@ -150,117 +160,192 @@ public class BSLinkset
150 return ret; 160 return ret;
151 } 161 }
152 162
153 private float ComputeLinksetMass() 163 // The object is going dynamic (physical). Do any setup necessary
164 // for a dynamic linkset.
165 // Only the state of the passed object can be modified. The rest of the linkset
166 // has not yet been fully constructed.
167 // Return 'true' if any properties updated on the passed object.
168 // Called at taint-time!
169 public bool MakeDynamic(BSPhysObject child)
170 {
171 // What is done for each object in BSPrim is what we want.
172 return false;
173 }
174
175 // The object is going static (non-physical). Do any setup necessary
176 // for a static linkset.
177 // Return 'true' if any properties updated on the passed object.
178 // Called at taint-time!
179 public bool MakeStatic(BSPhysObject child)
180 {
181 // What is done for each object in BSPrim is what we want.
182 return false;
183 }
184
185 // When physical properties are changed the linkset needs to recalculate
186 // its internal properties.
187 // Called at runtime.
188 public void Refresh(BSPhysObject requestor)
154 { 189 {
155 float mass = m_linksetRoot.MassRaw; 190 // If there are no children, there can't be any constraints to recompute
156 foreach (BSPrim bp in m_children) 191 if (!HasAnyChildren)
192 return;
193
194 // Only the root does the recomputation
195 if (IsRoot(requestor))
157 { 196 {
158 mass += bp.MassRaw; 197 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
198 {
199 RecomputeLinksetConstraintVariables();
200 });
159 } 201 }
160 return mass;
161 } 202 }
162 203
163 private OMV.Vector3 ComputeLinksetCenterOfMass() 204 // Routine used when rebuilding the body of the root of the linkset
205 // Destroy all the constraints have have been made to root.
206 // This is called when the root body is changing.
207 // Returns 'true' of something eas actually removed and would need restoring
208 // Called at taint-time!!
209 public bool RemoveBodyDependencies(BSPrim child)
164 { 210 {
165 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; 211 bool ret = false;
166 float totalMass = m_linksetRoot.MassRaw;
167 212
168 lock (m_linksetActivityLock) 213 lock (m_linksetActivityLock)
169 { 214 {
170 foreach (BSPrim bp in m_children) 215 if (IsRoot(child))
171 { 216 {
172 com += bp.Position * bp.MassRaw; 217 // If the one with the dependency is root, must undo all children
173 totalMass += bp.MassRaw; 218 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
219 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
220 foreach (BSPhysObject bpo in m_taintChildren)
221 {
222 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
223 ret = true;
224 }
225 }
226 else
227 {
228 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
229 child.LocalID,
230 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
231 child.LocalID, child.BSBody.ptr.ToString("X"));
232 // Remove the dependency on the body of this one
233 if (m_taintChildren.Contains(child))
234 {
235 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
236 ret = true;
237 }
174 } 238 }
175 if (totalMass != 0f)
176 com /= totalMass;
177 } 239 }
178 240 return ret;
179 return com;
180 } 241 }
181 242
182 private OMV.Vector3 ComputeLinksetGeometricCenter() 243 // Routine used when rebuilding the body of the root of the linkset
244 // This is called after RemoveAllLinksToRoot() to restore all the constraints.
245 // This is called when the root body has been changed.
246 // Called at taint-time!!
247 public void RestoreBodyDependencies(BSPrim child)
183 { 248 {
184 OMV.Vector3 com = m_linksetRoot.Position;
185
186 lock (m_linksetActivityLock) 249 lock (m_linksetActivityLock)
187 { 250 {
188 foreach (BSPrim bp in m_children) 251 if (IsRoot(child))
189 { 252 {
190 com += bp.Position * bp.MassRaw; 253 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
254 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
255 foreach (BSPhysObject bpo in m_taintChildren)
256 {
257 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
258 }
259 }
260 else
261 {
262 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
263 LinksetRoot.LocalID,
264 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
265 child.LocalID, child.BSBody.ptr.ToString("X"));
266 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
191 } 267 }
192 com /= (m_children.Count + 1);
193 } 268 }
194
195 return com;
196 } 269 }
197 270
198 // When physical properties are changed the linkset needs to recalculate 271 // ================================================================
199 // its internal properties. 272 // Below this point is internal magic
200 public void Refresh(BSPrim requestor) 273
274 private float ComputeLinksetMass()
201 { 275 {
202 // If there are no children, there aren't any constraints to recompute 276 float mass;
203 if (!HasAnyChildren) 277 lock (m_linksetActivityLock)
204 return; 278 {
279 mass = LinksetRoot.MassRaw;
280 foreach (BSPhysObject bp in m_taintChildren)
281 {
282 mass += bp.MassRaw;
283 }
284 }
285 return mass;
286 }
205 287
206 // Only the root does the recomputation 288 private OMV.Vector3 ComputeLinksetCenterOfMass()
207 if (IsRoot(requestor)) 289 {
290 OMV.Vector3 com;
291 lock (m_linksetActivityLock)
208 { 292 {
209 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 293 com = LinksetRoot.Position * LinksetRoot.MassRaw;
294 float totalMass = LinksetRoot.MassRaw;
295
296 foreach (BSPhysObject bp in m_taintChildren)
210 { 297 {
211 RecomputeLinksetConstraintVariables(); 298 com += bp.Position * bp.MassRaw;
212 }); 299 totalMass += bp.MassRaw;
300 }
301 if (totalMass != 0f)
302 com /= totalMass;
213 } 303 }
304
305 return com;
214 } 306 }
215 307
216 // Call each of the constraints that make up this linkset and recompute the 308 private OMV.Vector3 ComputeLinksetGeometricCenter()
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 { 309 {
223 float linksetMass = LinksetMass; 310 OMV.Vector3 com;
224 lock (m_linksetActivityLock) 311 lock (m_linksetActivityLock)
225 { 312 {
226 foreach (BSPrim child in m_children) 313 com = LinksetRoot.Position;
314
315 foreach (BSPhysObject bp in m_taintChildren)
227 { 316 {
228 BSConstraint constrain; 317 com += bp.Position * bp.MassRaw;
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 } 318 }
319 com /= (m_taintChildren.Count + 1);
245 } 320 }
246 return false; 321
322 return com;
247 } 323 }
248 324
249 // I am the root of a linkset and a new child is being added 325 // I am the root of a linkset and a new child is being added
250 // Called while LinkActivity is locked. 326 // Called while LinkActivity is locked.
251 private void AddChildToLinkset(BSPrim child) 327 private void AddChildToLinkset(BSPhysObject child)
252 { 328 {
253 if (!HasChild(child)) 329 if (!HasChild(child))
254 { 330 {
255 m_children.Add(child); 331 m_children.Add(child);
256 332
257 BSPrim rootx = LinksetRoot; // capture the root as of now 333 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
258 BSPrim childx = child; 334 BSPhysObject childx = child;
259 m_physicsScene.TaintedObject("AddChildToLinkset", delegate() 335
336 DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
337 rootx.LocalID,
338 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
339 childx.LocalID, childx.BSBody.ptr.ToString("X"));
340
341 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
260 { 342 {
261 // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); 343 DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
262 // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 344 // build the physical binding between me and the child
263 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child 345 m_taintChildren.Add(childx);
346
347 // Since this is taint-time, the body and shape could have changed for the child
348 PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody);
264 }); 349 });
265 } 350 }
266 return; 351 return;
@@ -270,30 +355,36 @@ public class BSLinkset
270 // This is not being called by the child so we have to make sure the child doesn't think 355 // 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. 356 // it's still connected to the linkset.
272 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 357 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
273 // has to be updated also (like pointer to prim's parent). 358 // also has to be updated (like pointer to prim's parent).
274 private void RemoveChildFromOtherLinkset(BSPrim pchild) 359 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
275 { 360 {
276 pchild.Linkset = new BSLinkset(m_physicsScene, pchild); 361 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
277 RemoveChildFromLinkset(pchild); 362 RemoveChildFromLinkset(pchild);
278 } 363 }
279 364
280 // I am the root of a linkset and one of my children is being removed. 365 // 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. 366 // Safe to call even if the child is not really in my linkset.
282 private void RemoveChildFromLinkset(BSPrim child) 367 private void RemoveChildFromLinkset(BSPhysObject child)
283 { 368 {
284 if (m_children.Remove(child)) 369 if (m_children.Remove(child))
285 { 370 {
286 BSPrim rootx = LinksetRoot; // capture the root as of now 371 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
287 BSPrim childx = child; 372 BSPhysObject childx = child;
288 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 373
374 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
375 childx.LocalID,
376 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
377 childx.LocalID, childx.BSBody.ptr.ToString("X"));
378
379 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
289 { 380 {
290 // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); 381 if (m_taintChildren.Contains(childx))
291 // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 382 m_taintChildren.Remove(childx);
292 383
293 PhysicallyUnlinkAChildFromRoot(rootx, childx); 384 PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody);
385 RecomputeLinksetConstraintVariables();
294 }); 386 });
295 387
296 RecomputeLinksetConstraintVariables();
297 } 388 }
298 else 389 else
299 { 390 {
@@ -305,7 +396,8 @@ public class BSLinkset
305 396
306 // Create a constraint between me (root of linkset) and the passed prim (the child). 397 // Create a constraint between me (root of linkset) and the passed prim (the child).
307 // Called at taint time! 398 // Called at taint time!
308 private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) 399 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
400 BSPhysObject childPrim, BulletBody childBody)
309 { 401 {
310 // Zero motion for children so they don't interpolate 402 // Zero motion for children so they don't interpolate
311 childPrim.ZeroMotion(); 403 childPrim.ZeroMotion();
@@ -317,21 +409,38 @@ public class BSLinkset
317 // real world coordinate of midpoint between the two objects 409 // real world coordinate of midpoint between the two objects
318 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 410 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
319 411
412 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
413 rootPrim.LocalID,
414 rootPrim.LocalID, rootBody.ptr.ToString("X"),
415 childPrim.LocalID, childBody.ptr.ToString("X"),
416 rootPrim.Position, childPrim.Position, midPoint);
417
320 // create a constraint that allows no freedom of movement between the two objects 418 // create a constraint that allows no freedom of movement between the two objects
321 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 419 // 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); 420
323 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", 421 // There is great subtlty in these paramters. Notice the check for a ptr of zero.
324 rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); 422 // We pass the BulletBody structure into the taint in order to capture the pointer
423 // of the body at the time of constraint creation. This doesn't work for the very first
424 // construction because there is no body yet. The body
425 // is constructed later at taint time. Thus we use the body address at time of the
426 // taint creation but, if it is zero, use what's in the prim at the moment.
427 // There is a possible race condition since shape can change without a taint call
428 // (like changing to a mesh that is already constructed). The fix for that would be
429 // to only change BSShape at taint time thus syncronizing these operations at
430 // the cost of efficiency and lag.
325 BS6DofConstraint constrain = new BS6DofConstraint( 431 BS6DofConstraint constrain = new BS6DofConstraint(
326 m_physicsScene.World, rootPrim.Body, childPrim.Body, 432 PhysicsScene.World,
433 rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
434 childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
327 midPoint, 435 midPoint,
328 true, 436 true,
329 true 437 true
330 ); 438 );
331 /* NOTE: attempt to build constraint with full frame computation, etc. 439
332 * Using the midpoint is easier since it lets the Bullet code use the transforms 440 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
441 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
333 * of the objects. 442 * of the objects.
334 * Code left here as an example. 443 * Code left as a warning to future programmers.
335 // ================================================================================== 444 // ==================================================================================
336 // relative position normalized to the root prim 445 // relative position normalized to the root prim
337 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); 446 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
@@ -343,7 +452,6 @@ public class BSLinkset
343 452
344 // create a constraint that allows no freedom of movement between the two objects 453 // create a constraint that allows no freedom of movement between the two objects
345 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 454 // 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); 455 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
348 BS6DofConstraint constrain = new BS6DofConstraint( 456 BS6DofConstraint constrain = new BS6DofConstraint(
349 PhysicsScene.World, rootPrim.Body, childPrim.Body, 457 PhysicsScene.World, rootPrim.Body, childPrim.Body,
@@ -362,7 +470,7 @@ public class BSLinkset
362 // ================================================================================== 470 // ==================================================================================
363 */ 471 */
364 472
365 m_physicsScene.Constraints.AddConstraint(constrain); 473 PhysicsScene.Constraints.AddConstraint(constrain);
366 474
367 // zero linear and angular limits makes the objects unable to move in relation to each other 475 // 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); 476 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -374,46 +482,88 @@ public class BSLinkset
374 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 482 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
375 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 483 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
376 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 484 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
485 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
486 {
487 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
488 }
377 489
378 RecomputeLinksetConstraintVariables(); 490 RecomputeLinksetConstraintVariables();
379 } 491 }
380 492
381 // Remove linkage between myself and a particular child 493 // Remove linkage between myself and a particular child
494 // The root and child bodies are passed in because we need to remove the constraint between
495 // the bodies that were at unlink time.
382 // Called at taint time! 496 // Called at taint time!
383 private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) 497 private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
498 BSPhysObject childPrim, BulletBody childBody)
384 { 499 {
385 // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", 500 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
386 // LogHeader, rootPrim.LocalID, childPrim.LocalID); 501 rootPrim.LocalID,
387 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 502 rootPrim.LocalID, rootBody.ptr.ToString("X"),
503 childPrim.LocalID, childBody.ptr.ToString("X"));
388 504
389 // Find the constraint for this link and get rid of it from the overall collection and from my list 505 // 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); 506 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
391 507
392 // Make the child refresh its location 508 // Make the child refresh its location
393 BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); 509 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
394 } 510 }
395 511
396 // Remove linkage between myself and any possible children I might have 512 /*
513 // Remove linkage between myself and any possible children I might have.
397 // Called at taint time! 514 // Called at taint time!
398 private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) 515 private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
399 { 516 {
400 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
401 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 517 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
402 518
403 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); 519 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
404 } 520 }
521 */
405 522
406 // Invoke the detailed logger and output something if it's enabled. 523 // Call each of the constraints that make up this linkset and recompute the
407 private void DebugLog(string msg, params Object[] args) 524 // various transforms and variables. Used when objects are added or removed
525 // from a linkset to make sure the constraints know about the new mass and
526 // geometry.
527 // Must only be called at taint time!!
528 private void RecomputeLinksetConstraintVariables()
408 { 529 {
409 if (m_physicsScene.ShouldDebugLog) 530 float linksetMass = LinksetMass;
410 m_physicsScene.Logger.DebugFormat(msg, args); 531 foreach (BSPhysObject child in m_taintChildren)
532 {
533 BSConstraint constrain;
534 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
535 {
536 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
537 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
538 constrain.RecomputeConstraintVariables(linksetMass);
539 }
540 else
541 {
542 // Non-fatal error that happens when children are being added to the linkset but
543 // their constraints have not been created yet.
544 break;
545 }
546 }
547
548 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
549 if (m_children.Count == m_taintChildren.Count)
550 {
551 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
552 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
553 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
554 foreach (BSPhysObject child in m_taintChildren)
555 {
556 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
557 }
558 }
559 return;
411 } 560 }
412 561
562
413 // Invoke the detailed logger and output something if it's enabled. 563 // Invoke the detailed logger and output something if it's enabled.
414 private void DetailLog(string msg, params Object[] args) 564 private void DetailLog(string msg, params Object[] args)
415 { 565 {
416 m_physicsScene.PhysicsLogging.Write(msg, args); 566 PhysicsScene.PhysicsLogging.Write(msg, args);
417 } 567 }
418 568
419} 569}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
new file mode 100755
index 0000000..1ac8c59
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -0,0 +1,213 @@
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 = new BSLinkset(PhysicsScene, this);
50
51 CollisionCollection = new CollisionEventUpdate();
52 SubscribedEventsMs = 0;
53 CollidingStep = 0;
54 CollidingGroundStep = 0;
55 }
56
57 public BSScene PhysicsScene { get; protected set; }
58 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
59 public string PhysObjectName { get; protected set; }
60 public string TypeName { get; protected set; }
61
62 public BSLinkset Linkset { get; set; }
63
64 // Return the object mass without calculating it or having side effects
65 public abstract float MassRaw { get; }
66
67 // Reference to the physical body (btCollisionObject) of this object
68 public BulletBody BSBody;
69 // Reference to the physical shape (btCollisionShape) of this object
70 public BulletShape BSShape;
71
72 // Stop all physical motion.
73 public abstract void ZeroMotion();
74
75 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
76 public virtual void StepVehicle(float timeStep) { }
77
78 // Update the physical location and motion of the object. Called with data from Bullet.
79 public abstract void UpdateProperties(EntityProperties entprop);
80
81 // Tell the object to clean up.
82 public abstract void Destroy();
83
84 public abstract OMV.Vector3 ForcePosition { get; set; }
85
86 public abstract OMV.Quaternion ForceOrientation { get; set; }
87
88 #region Collisions
89
90 // Requested number of milliseconds between collision events. Zero means disabled.
91 protected int SubscribedEventsMs { get; set; }
92 // Given subscription, the time that a collision may be passed up
93 protected int NextCollisionOkTime { get; set; }
94 // The simulation step that last had a collision
95 protected long CollidingStep { get; set; }
96 // The simulation step that last had a collision with the ground
97 protected long CollidingGroundStep { get; set; }
98 // The collision flags we think are set in Bullet
99 protected CollisionFlags CurrentCollisionFlags { get; set; }
100
101 // The collisions that have been collected this tick
102 protected CollisionEventUpdate CollisionCollection;
103
104 // The simulation step is telling this object about a collision.
105 // Return 'true' if a collision was processed and should be sent up.
106 // Called at taint time from within the Step() function
107 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
108 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
109 {
110 bool ret = false;
111
112 // The following lines make IsColliding() and IsCollidingGround() work
113 CollidingStep = PhysicsScene.SimulationStep;
114 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
115 {
116 CollidingGroundStep = PhysicsScene.SimulationStep;
117 }
118
119 // prims in the same linkset cannot collide with each other
120 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
121 {
122 return ret;
123 }
124
125 // if someone has subscribed for collision events....
126 if (SubscribedEvents()) {
127 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
128 // DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
129 // LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
130
131 ret = true;
132 }
133 return ret;
134 }
135
136 // Routine to send the collected collisions into the simulator.
137 // Also handles removal of this from the collection of objects with collisions if
138 // there are no collisions from this object. Mechanism is create one last
139 // collision event to make collision_end work.
140 // Called at taint time from within the Step() function thus no locking problems
141 // with CollisionCollection and ObjectsWithNoMoreCollisions.
142 // Return 'true' if there were some actual collisions passed up
143 public virtual bool SendCollisions()
144 {
145 bool ret = true;
146
147 // throttle the collisions to the number of milliseconds specified in the subscription
148 int nowTime = PhysicsScene.SimulationNowTime;
149 if (nowTime >= NextCollisionOkTime)
150 {
151 NextCollisionOkTime = nowTime + SubscribedEventsMs;
152
153 // We are called if we previously had collisions. If there are no collisions
154 // this time, send up one last empty event so OpenSim can sense collision end.
155 if (CollisionCollection.Count == 0)
156 {
157 // If I have no collisions this time, remove me from the list of objects with collisions.
158 ret = false;
159 }
160
161 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
162 base.SendCollisionUpdate(CollisionCollection);
163
164 // The collisionCollection structure is passed around in the simulator.
165 // Make sure we don't have a handle to that one and that a new one is used for next time.
166 CollisionCollection = new CollisionEventUpdate();
167 }
168 return ret;
169 }
170
171 // Subscribe for collision events.
172 // Parameter is the millisecond rate the caller wishes collision events to occur.
173 public override void SubscribeEvents(int ms) {
174 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
175 SubscribedEventsMs = ms;
176 if (ms > 0)
177 {
178 // make sure first collision happens
179 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
180
181 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
182 {
183 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
184 });
185 }
186 else
187 {
188 // Subscribing for zero or less is the same as unsubscribing
189 UnSubscribeEvents();
190 }
191 }
192 public override void UnSubscribeEvents() {
193 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
194 SubscribedEventsMs = 0;
195 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
196 {
197 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
198 });
199 }
200 // Return 'true' if the simulator wants collision events
201 public override bool SubscribedEvents() {
202 return (SubscribedEventsMs > 0);
203 }
204
205 #endregion // Collisions
206
207 // High performance detailed logging routine used by the physical objects.
208 protected void DetailLog(string msg, params Object[] args)
209 {
210 PhysicsScene.PhysicsLogging.Write(msg, args);
211 }
212}
213}
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..f7b68ba 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,20 @@ 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); }
46
47 private IMesh _mesh;
48 private PrimitiveBaseShape _pbs; 49 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 50
59 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. 51 // _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. 52 // 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 53 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 54 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
63 55
64 private bool _stopped;
65 private bool _grabbed; 56 private bool _grabbed;
66 private bool _isSelected; 57 private bool _isSelected;
67 private bool _isVolumeDetect; 58 private bool _isVolumeDetect;
@@ -89,25 +80,6 @@ public sealed class BSPrim : PhysicsActor
89 private bool _kinematic; 80 private bool _kinematic;
90 private float _buoyancy; 81 private float _buoyancy;
91 82
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; 83 private BSDynamics _vehicle;
112 84
113 private OMV.Vector3 _PIDTarget; 85 private OMV.Vector3 _PIDTarget;
@@ -122,9 +94,8 @@ public sealed class BSPrim : PhysicsActor
122 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 94 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
123 { 95 {
124 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 96 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
125 _localID = localID; 97 base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
126 _avName = primName; 98 _physicsActorType = (int)ActorTypes.Prim;
127 _scene = parent_scene;
128 _position = pos; 99 _position = pos;
129 _size = size; 100 _size = size;
130 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 101 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
@@ -132,98 +103,103 @@ public sealed class BSPrim : PhysicsActor
132 _buoyancy = 1f; 103 _buoyancy = 1f;
133 _velocity = OMV.Vector3.Zero; 104 _velocity = OMV.Vector3.Zero;
134 _rotationalVelocity = OMV.Vector3.Zero; 105 _rotationalVelocity = OMV.Vector3.Zero;
135 _hullKey = 0;
136 _meshKey = 0;
137 _pbs = pbs; 106 _pbs = pbs;
138 _isPhysical = pisPhysical; 107 _isPhysical = pisPhysical;
139 _isVolumeDetect = false; 108 _isVolumeDetect = false;
140 _subscribedEventsMs = 0; 109 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
141 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 110 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
142 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 111 _restitution = PhysicsScene.Params.defaultRestitution;
143 _restitution = _scene.Params.defaultRestitution; 112 _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(); 113 _mass = CalculateMass();
147 // do the actual object creation at taint time 114
115 // No body or shape yet
116 BSBody = new BulletBody(LocalID, IntPtr.Zero);
117 BSShape = new BulletShape(IntPtr.Zero);
118
148 DetailLog("{0},BSPrim.constructor,call", LocalID); 119 DetailLog("{0},BSPrim.constructor,call", LocalID);
149 _scene.TaintedObject("BSPrim.create", delegate() 120 // do the actual object creation at taint time
121 PhysicsScene.TaintedObject("BSPrim.create", delegate()
150 { 122 {
151 RecreateGeomAndObject(); 123 CreateGeomAndObject(true);
152 124
153 // Get the pointer to the physical body for this object. 125 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 }); 126 });
158 } 127 }
159 128
160 // called when this prim is being destroyed and we should free all the resources 129 // called when this prim is being destroyed and we should free all the resources
161 public void Destroy() 130 public override void Destroy()
162 { 131 {
163 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 132 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
164 133
165 // Undo any links between me and any other object 134 // Undo any links between me and any other object
166 BSPrim parentBefore = _linkset.LinksetRoot; 135 BSPhysObject parentBefore = Linkset.LinksetRoot;
167 int childrenBefore = _linkset.NumberOfChildren; 136 int childrenBefore = Linkset.NumberOfChildren;
168 137
169 _linkset = _linkset.RemoveMeFromLinkset(this); 138 Linkset = Linkset.RemoveMeFromLinkset(this);
170 139
171 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", 140 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
172 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 141 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
173 142
174 // Undo any vehicle properties 143 // Undo any vehicle properties
175 this.VehicleType = (int)Vehicle.TYPE_NONE; 144 this.VehicleType = (int)Vehicle.TYPE_NONE;
176 145
177 _scene.TaintedObject("BSPrim.destroy", delegate() 146 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
178 { 147 {
179 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 148 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
180 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 149 // If there are physical body and shape, release my use of same.
181 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); 150 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
151 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
182 }); 152 });
183 } 153 }
184 154
185 public override bool Stopped { 155 // No one uses this property.
186 get { return _stopped; } 156 public override bool Stopped {
157 get { return false; }
187 } 158 }
188 public override OMV.Vector3 Size { 159 public override OMV.Vector3 Size {
189 get { return _size; } 160 get { return _size; }
190 set { 161 set {
191 _size = value; 162 _size = value;
192 _scene.TaintedObject("BSPrim.setSize", delegate() 163 PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
193 { 164 {
194 _mass = CalculateMass(); // changing size changes the mass 165 _mass = CalculateMass(); // changing size changes the mass
195 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); 166 // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
196 // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical); 167 // scale and margins are set.
197 RecreateGeomAndObject(); 168 CreateGeomAndObject(true);
169 // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
198 }); 170 });
199 } 171 }
200 } 172 }
201 public override PrimitiveBaseShape Shape { 173 // Scale is what we set in the physics engine. It is different than 'size' in that
174 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
175 public OMV.Vector3 Scale
176 {
177 get { return _scale; }
178 set { _scale = value; }
179 }
180 public override PrimitiveBaseShape Shape {
202 set { 181 set {
203 _pbs = value; 182 _pbs = value;
204 _scene.TaintedObject("BSPrim.setShape", delegate() 183 PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
205 { 184 {
206 _mass = CalculateMass(); // changing the shape changes the mass 185 _mass = CalculateMass(); // changing the shape changes the mass
207 RecreateGeomAndObject(); 186 CreateGeomAndObject(true);
208 }); 187 });
209 } 188 }
210 }
211 public override uint LocalID {
212 set { _localID = value; }
213 get { return _localID; }
214 } 189 }
215 public override bool Grabbed { 190 public override bool Grabbed {
216 set { _grabbed = value; 191 set { _grabbed = value;
217 } 192 }
218 } 193 }
219 public override bool Selected { 194 public override bool Selected {
220 set { 195 set {
221 _isSelected = value; 196 _isSelected = value;
222 _scene.TaintedObject("BSPrim.setSelected", delegate() 197 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
223 { 198 {
224 SetObjectDynamic(); 199 // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
200 SetObjectDynamic(false);
225 }); 201 });
226 } 202 }
227 } 203 }
228 public override void CrossingFailure() { return; } 204 public override void CrossingFailure() { return; }
229 205
@@ -232,158 +208,222 @@ public sealed class BSPrim : PhysicsActor
232 BSPrim parent = obj as BSPrim; 208 BSPrim parent = obj as BSPrim;
233 if (parent != null) 209 if (parent != null)
234 { 210 {
235 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID); 211 BSPhysObject parentBefore = Linkset.LinksetRoot;
236 BSPrim parentBefore = _linkset.LinksetRoot; 212 int childrenBefore = Linkset.NumberOfChildren;
237 int childrenBefore = _linkset.NumberOfChildren;
238 213
239 _linkset = parent.Linkset.AddMeToLinkset(this); 214 Linkset = parent.Linkset.AddMeToLinkset(this);
240 215
241 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 216 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
242 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 217 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
243 } 218 }
244 return; 219 return;
245 } 220 }
246 221
247 // delink me from my linkset 222 // delink me from my linkset
248 public override void delink() { 223 public override void delink() {
249 // TODO: decide if this parent checking needs to happen at taint time 224 // 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 225 // 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 226
254 BSPrim parentBefore = _linkset.LinksetRoot; 227 BSPhysObject parentBefore = Linkset.LinksetRoot;
255 int childrenBefore = _linkset.NumberOfChildren; 228 int childrenBefore = Linkset.NumberOfChildren;
256
257 _linkset = _linkset.RemoveMeFromLinkset(this);
258 229
259 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 230 Linkset = Linkset.RemoveMeFromLinkset(this);
260 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 231
261 return; 232 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
233 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
234 return;
262 } 235 }
263 236
264 // Set motion values to zero. 237 // Set motion values to zero.
265 // Do it to the properties so the values get set in the physics engine. 238 // Do it to the properties so the values get set in the physics engine.
266 // Push the setting of the values to the viewer. 239 // Push the setting of the values to the viewer.
267 // Called at taint time! 240 // Called at taint time!
268 public void ZeroMotion() 241 public override void ZeroMotion()
269 { 242 {
270 _velocity = OMV.Vector3.Zero; 243 _velocity = OMV.Vector3.Zero;
271 _acceleration = OMV.Vector3.Zero; 244 _acceleration = OMV.Vector3.Zero;
272 _rotationalVelocity = OMV.Vector3.Zero; 245 _rotationalVelocity = OMV.Vector3.Zero;
273 246
274 // Zero some other properties directly into the physics engine 247 // Zero some other properties directly into the physics engine
275 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); 248 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 } 249 }
280 250
281 public override void LockAngularMotion(OMV.Vector3 axis) 251 public override void LockAngularMotion(OMV.Vector3 axis)
282 { 252 {
283 // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 253 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
284 return; 254 return;
285 } 255 }
286 256
287 public override OMV.Vector3 Position { 257 public override OMV.Vector3 Position {
288 get { 258 get {
289 if (!_linkset.IsRoot(this)) 259 if (!Linkset.IsRoot(this))
290 // child prims move around based on their parent. Need to get the latest location 260 // child prims move around based on their parent. Need to get the latest location
291 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 261 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
292 262
293 // don't do the GetObjectPosition for root elements because this function is called a zillion times 263 // don't do the GetObjectPosition for root elements because this function is called a zillion times
294 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 264 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
295 return _position; 265 return _position;
296 } 266 }
297 set { 267 set {
298 _position = value; 268 _position = value;
299 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 269 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
300 _scene.TaintedObject("BSPrim.setPosition", delegate() 270 PositionSanityCheck();
271 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
301 { 272 {
302 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 273 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
303 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 274 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
304 }); 275 });
305 } 276 }
277 }
278 public override OMV.Vector3 ForcePosition {
279 get {
280 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
281 return _position;
282 }
283 set {
284 _position = value;
285 PositionSanityCheck();
286 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
287 }
288 }
289
290 // Check that the current position is sane and, if not, modify the position to make it so.
291 // Check for being below terrain and being out of bounds.
292 // Returns 'true' of the position was made sane by some action.
293 private bool PositionSanityCheck()
294 {
295 bool ret = false;
296
297 // If totally below the ground, move the prim up
298 // TODO: figure out the right solution for this... only for dynamic objects?
299 /*
300 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
301 if (Position.Z < terrainHeight)
302 {
303 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
304 _position.Z = terrainHeight + 2.0f;
305 ret = true;
306 }
307 */
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight)
312 {
313 _position.Z = waterHeight;
314 ret = true;
315 }
316 }
317
318 // TODO: check for out of bounds
319 return ret;
320 }
321
322 // A version of the sanity check that also makes sure a new position value is
323 // pushed back to the physics engine. This routine would be used by anyone
324 // who is not already pushing the value.
325 private bool PositionSanityCheck2(bool atTaintTime)
326 {
327 bool ret = false;
328 if (PositionSanityCheck())
329 {
330 // The new position value must be pushed into the physics engine but we can't
331 // just assign to "Position" because of potential call loops.
332 BSScene.TaintCallback sanityOperation = delegate()
333 {
334 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
336 };
337 if (atTaintTime)
338 sanityOperation();
339 else
340 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
341
342 ret = true;
343 }
344 return ret;
306 } 345 }
307 346
308 // Return the effective mass of the object. 347 // Return the effective mass of the object.
309 // If there are multiple items in the linkset, add them together for the root 348 // If there are multiple items in the linkset, add them together for the root
310 public override float Mass 349 public override float Mass
311 { 350 {
312 get 351 get
313 { 352 {
314 return _linkset.LinksetMass; 353 // return Linkset.LinksetMass;
354 return _mass;
315 } 355 }
316 } 356 }
317 357
318 // used when we only want this prim's mass and not the linkset thing 358 // used when we only want this prim's mass and not the linkset thing
319 public float MassRaw { get { return _mass; } } 359 public override float MassRaw { get { return _mass; } }
320 360
321 // Is this used? 361 // Is this used?
322 public override OMV.Vector3 CenterOfMass 362 public override OMV.Vector3 CenterOfMass
323 { 363 {
324 get { return _linkset.CenterOfMass; } 364 get { return Linkset.CenterOfMass; }
325 } 365 }
326 366
327 // Is this used? 367 // Is this used?
328 public override OMV.Vector3 GeometricCenter 368 public override OMV.Vector3 GeometricCenter
329 { 369 {
330 get { return _linkset.GeometricCenter; } 370 get { return Linkset.GeometricCenter; }
331 } 371 }
332 372
333 public override OMV.Vector3 Force { 373 public override OMV.Vector3 Force {
334 get { return _force; } 374 get { return _force; }
335 set { 375 set {
336 _force = value; 376 _force = value;
337 _scene.TaintedObject("BSPrim.setForce", delegate() 377 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
338 { 378 {
339 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 379 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
340 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 380 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
341 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
342 }); 381 });
343 } 382 }
344 } 383 }
345 384
346 public override int VehicleType { 385 public override int VehicleType {
347 get { 386 get {
348 return (int)_vehicle.Type; // if we are a vehicle, return that type 387 return (int)_vehicle.Type; // if we are a vehicle, return that type
349 } 388 }
350 set { 389 set {
351 Vehicle type = (Vehicle)value; 390 Vehicle type = (Vehicle)value;
352 BSPrim vehiclePrim = this; 391
353 _scene.TaintedObject("setVehicleType", delegate() 392 // Tell the scene about the vehicle so it will get processing each frame.
393 PhysicsScene.VehicleInSceneTypeChanged(this, type);
394
395 PhysicsScene.TaintedObject("setVehicleType", delegate()
354 { 396 {
355 // Done at taint time so we're sure the physics engine is not using the variables 397 // 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. 398 // Vehicle code changes the parameters for this vehicle type.
357 _vehicle.ProcessTypeChange(type); 399 this._vehicle.ProcessTypeChange(type);
358 // Tell the scene about the vehicle so it will get processing each frame.
359 _scene.VehicleInSceneTypeChanged(this, type);
360 }); 400 });
361 } 401 }
362 } 402 }
363 public override void VehicleFloatParam(int param, float value) 403 public override void VehicleFloatParam(int param, float value)
364 { 404 {
365 _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 405 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
366 { 406 {
367 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 407 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
368 }); 408 });
369 } 409 }
370 public override void VehicleVectorParam(int param, OMV.Vector3 value) 410 public override void VehicleVectorParam(int param, OMV.Vector3 value)
371 { 411 {
372 _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 412 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
373 { 413 {
374 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 414 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
375 }); 415 });
376 } 416 }
377 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 417 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
378 { 418 {
379 _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 419 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
380 { 420 {
381 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 421 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
382 }); 422 });
383 } 423 }
384 public override void VehicleFlags(int param, bool remove) 424 public override void VehicleFlags(int param, bool remove)
385 { 425 {
386 _scene.TaintedObject("BSPrim.VehicleFlags", delegate() 426 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
387 { 427 {
388 _vehicle.ProcessVehicleFlags(param, remove); 428 _vehicle.ProcessVehicleFlags(param, remove);
389 }); 429 });
@@ -391,83 +431,106 @@ public sealed class BSPrim : PhysicsActor
391 431
392 // Called each simulation step to advance vehicle characteristics. 432 // Called each simulation step to advance vehicle characteristics.
393 // Called from Scene when doing simulation step so we're in taint processing time. 433 // Called from Scene when doing simulation step so we're in taint processing time.
394 public void StepVehicle(float timeStep) 434 public override void StepVehicle(float timeStep)
395 { 435 {
396 if (IsPhysical) 436 if (IsPhysical)
437 {
397 _vehicle.Step(timeStep); 438 _vehicle.Step(timeStep);
439 }
398 } 440 }
399 441
400 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 442 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
401 public override void SetVolumeDetect(int param) { 443 public override void SetVolumeDetect(int param) {
402 bool newValue = (param != 0); 444 bool newValue = (param != 0);
403 _isVolumeDetect = newValue; 445 if (_isVolumeDetect != newValue)
404 _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
405 { 446 {
406 SetObjectDynamic(); 447 _isVolumeDetect = newValue;
407 }); 448 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
408 return; 449 {
450 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
451 SetObjectDynamic(true);
452 });
453 }
454 return;
409 } 455 }
410 456
411 public override OMV.Vector3 Velocity { 457 public override OMV.Vector3 Velocity {
412 get { return _velocity; } 458 get { return _velocity; }
413 set { 459 set {
414 _velocity = value; 460 _velocity = value;
415 _scene.TaintedObject("BSPrim.setVelocity", delegate() 461 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
416 { 462 {
417 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 463 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
418 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 464 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
419 }); 465 });
420 } 466 }
421 } 467 }
422 public override OMV.Vector3 Torque { 468 public override OMV.Vector3 Torque {
423 get { return _torque; } 469 get { return _torque; }
424 set { _torque = value; 470 set { _torque = value;
425 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 471 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
426 } 472 }
427 } 473 }
428 public override float CollisionScore { 474 public override float CollisionScore {
429 get { return _collisionScore; } 475 get { return _collisionScore; }
430 set { _collisionScore = value; 476 set { _collisionScore = value;
431 } 477 }
432 } 478 }
433 public override OMV.Vector3 Acceleration { 479 public override OMV.Vector3 Acceleration {
434 get { return _acceleration; } 480 get { return _acceleration; }
435 set { _acceleration = value; } 481 set { _acceleration = value; }
436 } 482 }
437 public override OMV.Quaternion Orientation { 483 public override OMV.Quaternion Orientation {
438 get { 484 get {
439 if (!_linkset.IsRoot(this)) 485 if (!Linkset.IsRoot(this))
440 { 486 {
441 // Children move around because tied to parent. Get a fresh value. 487 // Children move around because tied to parent. Get a fresh value.
442 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); 488 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
443 } 489 }
444 return _orientation; 490 return _orientation;
445 } 491 }
446 set { 492 set {
447 _orientation = value; 493 _orientation = value;
448 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 494 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
449 _scene.TaintedObject("BSPrim.setOrientation", delegate() 495 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
450 { 496 {
451 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 497 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
452 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 498 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
453 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 499 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
454 }); 500 });
455 } 501 }
456 } 502 }
457 public override int PhysicsActorType { 503 // Go directly to Bullet to get/set the value.
458 get { return _physicsActorType; } 504 public override OMV.Quaternion ForceOrientation
459 set { _physicsActorType = value; 505 {
460 } 506 get
507 {
508 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
509 return _orientation;
510 }
511 set
512 {
513 _orientation = value;
514 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
515 }
461 } 516 }
462 public override bool IsPhysical { 517 public override int PhysicsActorType {
463 get { return _isPhysical; } 518 get { return _physicsActorType; }
519 set { _physicsActorType = value; }
520 }
521 public override bool IsPhysical {
522 get { return _isPhysical; }
464 set { 523 set {
465 _isPhysical = value; 524 if (_isPhysical != value)
466 _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
467 { 525 {
468 SetObjectDynamic(); 526 _isPhysical = value;
469 }); 527 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
470 } 528 {
529 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
530 SetObjectDynamic(true);
531 });
532 }
533 }
471 } 534 }
472 535
473 // An object is static (does not move) if selected or not physical 536 // An object is static (does not move) if selected or not physical
@@ -477,57 +540,196 @@ public sealed class BSPrim : PhysicsActor
477 } 540 }
478 541
479 // An object is solid if it's not phantom and if it's not doing VolumeDetect 542 // An object is solid if it's not phantom and if it's not doing VolumeDetect
480 private bool IsSolid 543 public bool IsSolid
481 { 544 {
482 get { return !IsPhantom && !_isVolumeDetect; } 545 get { return !IsPhantom && !_isVolumeDetect; }
483 } 546 }
484 547
485 // Make gravity work if the object is physical and not selected 548 // Make gravity work if the object is physical and not selected
486 // No locking here because only called when it is safe 549 // Called at taint-time!!
487 private void SetObjectDynamic() 550 private void SetObjectDynamic(bool forceRebuild)
551 {
552 // Recreate the physical object if necessary
553 CreateGeomAndObject(forceRebuild);
554 }
555
556 // Convert the simulator's physical properties into settings on BulletSim objects.
557 // There are four flags we're interested in:
558 // IsStatic: Object does not move, otherwise the object has mass and moves
559 // isSolid: other objects bounce off of this object
560 // isVolumeDetect: other objects pass through but can generate collisions
561 // collisionEvents: whether this object returns collision events
562 private void UpdatePhysicalParameters()
488 { 563 {
489 // RA: remove this for the moment. 564 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
490 // The problem is that dynamic objects are hulls so if we are becoming physical 565
491 // the shape has to be checked and possibly built. 566 // Mangling all the physical properties requires the object not be in the physical world.
492 // Maybe a VerifyCorrectPhysicalShape() routine? 567 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
493 // RecreateGeomAndObject(); 568 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
569
570 // Set up the object physicalness (does gravity and collisions move this object)
571 MakeDynamic(IsStatic);
572
573 // Update vehicle specific parameters
574 _vehicle.Refresh();
575
576 // Arrange for collision events if the simulator wants them
577 EnableCollisions(SubscribedEvents());
578
579 // Make solid or not (do things bounce off or pass through this object).
580 MakeSolid(IsSolid);
581
582 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
494 583
495 // Bullet wants static objects to have a mass of zero 584 // Rebuild its shape
496 float mass = IsStatic ? 0f : _mass; 585 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
497 586
498 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); 587 // Collision filter can be set only when the object is in the world
588 if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0)
589 {
590 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask);
591 }
499 592
500 // recompute any linkset parameters 593 // Recompute any linkset parameters.
501 _linkset.Refresh(this); 594 // When going from non-physical to physical, this re-enables the constraints that
595 // had been automatically disabled when the mass was set to zero.
596 Linkset.Refresh(this);
502 597
503 CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr); 598 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
504 // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf); 599 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
600 }
601
602 // "Making dynamic" means changing to and from static.
603 // When static, gravity does not effect the object and it is fixed in space.
604 // When dynamic, the object can fall and be pushed by others.
605 // This is independent of its 'solidness' which controls what passes through
606 // this object and what interacts with it.
607 private void MakeDynamic(bool makeStatic)
608 {
609 if (makeStatic)
610 {
611 // Become a Bullet 'static' object type
612 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
613 // Stop all movement
614 BulletSimAPI.ClearAllForces2(BSBody.ptr);
615 // Center of mass is at the center of the object
616 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation);
617 // Mass is zero which disables a bunch of physics stuff in Bullet
618 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
619 // There is no inertia in a static object
620 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
621 // There can be special things needed for implementing linksets
622 Linkset.MakeStatic(this);
623 // The activation state is 'disabled' so Bullet will not try to act on it
624 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
625
626 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
627 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
628 }
629 else
630 {
631 // Not a Bullet static object
632 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
633
634 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
635 BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
636 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
637
638 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
639 BulletSimAPI.ClearAllForces2(BSBody.ptr);
640
641 // A dynamic object has mass
642 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
643 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
644 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
645 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
646
647 // Various values for simulation limits
648 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
649 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
650 BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
651 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
652
653 // There might be special things needed for implementing linksets.
654 Linkset.MakeDynamic(this);
655
656 // Force activation of the object so Bullet will act on it.
657 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
658 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
659 BulletSimAPI.Activate2(BSBody.ptr, true);
660
661 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
662 BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
663 }
664 }
665
666 // "Making solid" means that other object will not pass through this object.
667 // To make transparent, we create a Bullet ghost object.
668 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
669 // the functions after this one set up the state of a possibly newly created collision body.
670 private void MakeSolid(bool makeSolid)
671 {
672 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
673 if (makeSolid)
674 {
675 // Verify the previous code created the correct shape for this type of thing.
676 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
677 {
678 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
679 }
680 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
681 }
682 else
683 {
684 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
685 {
686 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
687 }
688 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
689 BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
690 BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
691 }
692 }
693
694 // Turn on or off the flag controlling whether collision events are returned to the simulator.
695 private void EnableCollisions(bool wantsCollisionEvents)
696 {
697 if (wantsCollisionEvents)
698 {
699 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
700 }
701 else
702 {
703 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
704 }
505 } 705 }
506 706
507 // prims don't fly 707 // prims don't fly
508 public override bool Flying { 708 public override bool Flying {
509 get { return _flying; } 709 get { return _flying; }
510 set { _flying = value; } 710 set {
711 _flying = value;
712 }
511 } 713 }
512 public override bool SetAlwaysRun { 714 public override bool SetAlwaysRun {
513 get { return _setAlwaysRun; } 715 get { return _setAlwaysRun; }
514 set { _setAlwaysRun = value; } 716 set { _setAlwaysRun = value; }
515 } 717 }
516 public override bool ThrottleUpdates { 718 public override bool ThrottleUpdates {
517 get { return _throttleUpdates; } 719 get { return _throttleUpdates; }
518 set { _throttleUpdates = value; } 720 set { _throttleUpdates = value; }
519 } 721 }
520 public override bool IsColliding { 722 public override bool IsColliding {
521 get { return (_collidingStep == _scene.SimulationStep); } 723 get { return (CollidingStep == PhysicsScene.SimulationStep); }
522 set { _isColliding = value; } 724 set { _isColliding = value; }
523 } 725 }
524 public override bool CollidingGround { 726 public override bool CollidingGround {
525 get { return (_collidingGroundStep == _scene.SimulationStep); } 727 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
526 set { _collidingGround = value; } 728 set { _collidingGround = value; }
527 } 729 }
528 public override bool CollidingObj { 730 public override bool CollidingObj {
529 get { return _collidingObj; } 731 get { return _collidingObj; }
530 set { _collidingObj = value; } 732 set { _collidingObj = value; }
531 } 733 }
532 public bool IsPhantom { 734 public bool IsPhantom {
533 get { 735 get {
@@ -537,10 +739,19 @@ public sealed class BSPrim : PhysicsActor
537 return false; 739 return false;
538 } 740 }
539 } 741 }
540 public override bool FloatOnWater { 742 public override bool FloatOnWater {
541 set { _floatOnWater = value; } 743 set {
744 _floatOnWater = value;
745 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
746 {
747 if (_floatOnWater)
748 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
749 else
750 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
751 });
752 }
542 } 753 }
543 public override OMV.Vector3 RotationalVelocity { 754 public override OMV.Vector3 RotationalVelocity {
544 get { 755 get {
545 /* 756 /*
546 OMV.Vector3 pv = OMV.Vector3.Zero; 757 OMV.Vector3 pv = OMV.Vector3.Zero;
@@ -552,58 +763,60 @@ public sealed class BSPrim : PhysicsActor
552 */ 763 */
553 764
554 return _rotationalVelocity; 765 return _rotationalVelocity;
555 } 766 }
556 set { 767 set {
557 _rotationalVelocity = value; 768 _rotationalVelocity = value;
558 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 769 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
559 _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 770 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
560 { 771 {
561 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 772 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
562 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 773 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
563 }); 774 });
564 } 775 }
565 } 776 }
566 public override bool Kinematic { 777 public override bool Kinematic {
567 get { return _kinematic; } 778 get { return _kinematic; }
568 set { _kinematic = value; 779 set { _kinematic = value;
569 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); 780 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
570 } 781 }
571 } 782 }
572 public override float Buoyancy { 783 public override float Buoyancy {
573 get { return _buoyancy; } 784 get { return _buoyancy; }
574 set { 785 set {
575 _buoyancy = value; 786 _buoyancy = value;
576 _scene.TaintedObject("BSPrim.setBuoyancy", delegate() 787 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
577 { 788 {
578 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 789 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
579 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); 790 // Buoyancy is faked by changing the gravity applied to the object
791 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
792 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
580 }); 793 });
581 } 794 }
582 } 795 }
583 796
584 // Used for MoveTo 797 // Used for MoveTo
585 public override OMV.Vector3 PIDTarget { 798 public override OMV.Vector3 PIDTarget {
586 set { _PIDTarget = value; } 799 set { _PIDTarget = value; }
587 } 800 }
588 public override bool PIDActive { 801 public override bool PIDActive {
589 set { _usePID = value; } 802 set { _usePID = value; }
590 } 803 }
591 public override float PIDTau { 804 public override float PIDTau {
592 set { _PIDTau = value; } 805 set { _PIDTau = value; }
593 } 806 }
594 807
595 // Used for llSetHoverHeight and maybe vehicle height 808 // Used for llSetHoverHeight and maybe vehicle height
596 // Hover Height will override MoveTo target's Z 809 // Hover Height will override MoveTo target's Z
597 public override bool PIDHoverActive { 810 public override bool PIDHoverActive {
598 set { _useHoverPID = value; } 811 set { _useHoverPID = value; }
599 } 812 }
600 public override float PIDHoverHeight { 813 public override float PIDHoverHeight {
601 set { _PIDHoverHeight = value; } 814 set { _PIDHoverHeight = value; }
602 } 815 }
603 public override PIDHoverType PIDHoverType { 816 public override PIDHoverType PIDHoverType {
604 set { _PIDHoverType = value; } 817 set { _PIDHoverType = value; }
605 } 818 }
606 public override float PIDHoverTau { 819 public override float PIDHoverTau {
607 set { _PIDHoverTao = value; } 820 set { _PIDHoverTao = value; }
608 } 821 }
609 822
@@ -624,10 +837,10 @@ public sealed class BSPrim : PhysicsActor
624 } 837 }
625 else 838 else
626 { 839 {
627 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 840 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
628 return; 841 return;
629 } 842 }
630 _scene.TaintedObject("BSPrim.AddForce", delegate() 843 PhysicsScene.TaintedObject("BSPrim.AddForce", delegate()
631 { 844 {
632 OMV.Vector3 fSum = OMV.Vector3.Zero; 845 OMV.Vector3 fSum = OMV.Vector3.Zero;
633 lock (m_accumulatedForces) 846 lock (m_accumulatedForces)
@@ -638,42 +851,19 @@ public sealed class BSPrim : PhysicsActor
638 } 851 }
639 m_accumulatedForces.Clear(); 852 m_accumulatedForces.Clear();
640 } 853 }
641 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force); 854 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
642 BulletSimAPI.AddObjectForce2(Body.Ptr, fSum); 855 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
856 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
643 }); 857 });
644 } 858 }
645 859
646 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 860 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
647 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 861 // 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); 862 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
649 } 863 }
650 public override void SetMomentum(OMV.Vector3 momentum) { 864 public override void SetMomentum(OMV.Vector3 momentum) {
651 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 865 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
652 } 866 }
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 867 #region Mass Calculation
678 868
679 private float CalculateMass() 869 private float CalculateMass()
@@ -683,8 +873,8 @@ public sealed class BSPrim : PhysicsActor
683 873
684 float returnMass = 0; 874 float returnMass = 0;
685 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 875 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
686 float hollowVolume = hollowAmount * hollowAmount; 876 float hollowVolume = hollowAmount * hollowAmount;
687 877
688 switch (_pbs.ProfileShape) 878 switch (_pbs.ProfileShape)
689 { 879 {
690 case ProfileShape.Square: 880 case ProfileShape.Square:
@@ -720,16 +910,16 @@ public sealed class BSPrim : PhysicsActor
720 910
721 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 911 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
722 { 912 {
723 //a tube 913 //a tube
724 914
725 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 915 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
726 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 916 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
727 volume -= volume*tmp*tmp; 917 volume -= volume*tmp*tmp;
728 918
729 if (hollowAmount > 0.0) 919 if (hollowAmount > 0.0)
730 { 920 {
731 hollowVolume *= hollowAmount; 921 hollowVolume *= hollowAmount;
732 922
733 switch (_pbs.HollowShape) 923 switch (_pbs.HollowShape)
734 { 924 {
735 case HollowShape.Square: 925 case HollowShape.Square:
@@ -788,7 +978,7 @@ public sealed class BSPrim : PhysicsActor
788 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 978 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
789 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 979 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
790 volume *= (1.0f - tmp * tmp); 980 volume *= (1.0f - tmp * tmp);
791 981
792 if (hollowAmount > 0.0) 982 if (hollowAmount > 0.0)
793 { 983 {
794 984
@@ -967,296 +1157,64 @@ public sealed class BSPrim : PhysicsActor
967 if (returnMass <= 0) 1157 if (returnMass <= 0)
968 returnMass = 0.0001f; 1158 returnMass = 0.0001f;
969 1159
970 if (returnMass > _scene.MaximumObjectMass) 1160 if (returnMass > PhysicsScene.MaximumObjectMass)
971 returnMass = _scene.MaximumObjectMass; 1161 returnMass = PhysicsScene.MaximumObjectMass;
972 1162
973 return returnMass; 1163 return returnMass;
974 }// end CalculateMass 1164 }// end CalculateMass
975 #endregion Mass Calculation 1165 #endregion Mass Calculation
976 1166
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 1167 // Copy prim's info into the BulletSim shape description structure
1233 public void FillShapeInfo(out ShapeData shape) 1168 public void FillShapeInfo(out ShapeData shape)
1234 { 1169 {
1235 shape.ID = _localID; 1170 shape.ID = LocalID;
1236 shape.Type = _shapeType; 1171 shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
1237 shape.Position = _position; 1172 shape.Position = _position;
1238 shape.Rotation = _orientation; 1173 shape.Rotation = _orientation;
1239 shape.Velocity = _velocity; 1174 shape.Velocity = _velocity;
1240 shape.Scale = _scale; 1175 shape.Scale = _scale;
1241 shape.Mass = _isPhysical ? _mass : 0f; 1176 shape.Mass = _isPhysical ? _mass : 0f;
1242 shape.Buoyancy = _buoyancy; 1177 shape.Buoyancy = _buoyancy;
1243 shape.HullKey = _hullKey; 1178 shape.HullKey = 0;
1244 shape.MeshKey = _meshKey; 1179 shape.MeshKey = 0;
1245 shape.Friction = _friction; 1180 shape.Friction = _friction;
1246 shape.Restitution = _restitution; 1181 shape.Restitution = _restitution;
1247 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; 1182 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1248 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1183 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1184 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1185 shape.Size = _size;
1249 } 1186 }
1250
1251
1252 // Rebuild the geometry and object. 1187 // Rebuild the geometry and object.
1253 // This is called when the shape changes so we need to recreate the mesh/hull. 1188 // 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 1189 // Called at taint-time!!!
1255 private void RecreateGeomAndObject() 1190 private void CreateGeomAndObject(bool forceRebuild)
1256 { 1191 {
1257 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); 1192 ShapeData shapeData;
1258 if (CreateGeom(true)) 1193 FillShapeInfo(out shapeData);
1259 CreateObject(); 1194
1195 // If this prim is part of a linkset, we must remove and restore the physical
1196 // links of the body is rebuilt.
1197 bool needToRestoreLinkset = false;
1198
1199 // Create the correct physical representation for this type of object.
1200 // Updates BSBody and BSShape with the new information.
1201 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1202 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs,
1203 null, delegate(BulletBody dBody)
1204 {
1205 // Called if the current prim body is about to be destroyed.
1206 // Remove all the physical dependencies on the old body.
1207 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1208 });
1209
1210 if (needToRestoreLinkset)
1211 {
1212 // If physical body dependencies were removed, restore them
1213 Linkset.RestoreBodyDependencies(this);
1214 }
1215
1216 // Make sure the properties are set on the new object
1217 UpdatePhysicalParameters();
1260 return; 1218 return;
1261 } 1219 }
1262 1220
@@ -1277,7 +1235,7 @@ public sealed class BSPrim : PhysicsActor
1277 const float ACCELERATION_TOLERANCE = 0.01f; 1235 const float ACCELERATION_TOLERANCE = 0.01f;
1278 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1236 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1279 1237
1280 public void UpdateProperties(EntityProperties entprop) 1238 public override void UpdateProperties(EntityProperties entprop)
1281 { 1239 {
1282 /* 1240 /*
1283 UpdatedProperties changed = 0; 1241 UpdatedProperties changed = 0;
@@ -1325,7 +1283,7 @@ public sealed class BSPrim : PhysicsActor
1325 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1283 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1326 1284
1327 // Updates only for individual prims and for the root object of a linkset. 1285 // Updates only for individual prims and for the root object of a linkset.
1328 if (_linkset.IsRoot(this)) 1286 if (Linkset.IsRoot(this))
1329 { 1287 {
1330 // Assign to the local variables so the normal set action does not happen 1288 // Assign to the local variables so the normal set action does not happen
1331 _position = entprop.Position; 1289 _position = entprop.Position;
@@ -1334,69 +1292,24 @@ public sealed class BSPrim : PhysicsActor
1334 _acceleration = entprop.Acceleration; 1292 _acceleration = entprop.Acceleration;
1335 _rotationalVelocity = entprop.RotationalVelocity; 1293 _rotationalVelocity = entprop.RotationalVelocity;
1336 1294
1337 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", 1295 PositionSanityCheck2(true);
1338 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1296
1339 // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1297 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1340 // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1298 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1299
1300 // BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr);
1341 1301
1342 base.RequestPhysicsterseUpdate(); 1302 base.RequestPhysicsterseUpdate();
1343 } 1303 }
1344 /* 1304 /*
1345 else 1305 else
1346 { 1306 {
1347 // For debugging, we also report the movement of children 1307 // For debugging, we can also report the movement of children
1348 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1308 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1349 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1309 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1350 entprop.Acceleration, entprop.RotationalVelocity); 1310 entprop.Acceleration, entprop.RotationalVelocity);
1351 } 1311 }
1352 */ 1312 */
1353 } 1313 }
1354
1355 // I've collided with something
1356 CollisionEventUpdate collisionCollection;
1357 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1358 {
1359 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1360
1361 // The following lines make IsColliding() and IsCollidingGround() work
1362 _collidingStep = _scene.SimulationStep;
1363 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1364 {
1365 _collidingGroundStep = _scene.SimulationStep;
1366 }
1367
1368 // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
1369
1370 // if someone is subscribed to collision events....
1371 if (_subscribedEventsMs != 0) {
1372 // throttle the collisions to the number of milliseconds specified in the subscription
1373 int nowTime = _scene.SimulationNowTime;
1374 if (nowTime >= _nextCollisionOkTime) {
1375 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
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 }
1401} 1314}
1402} 1315}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..aaed7de 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,33 +39,28 @@ 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// Move all logic out of the C++ code and into the C# code for easier future modifications.
43// Test with multiple regions in one simulator 43// Test sculpties (verified that they don't work)
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably 44// Compute physics FPS reasonably
47// Based on material, set density and friction 45// Based on material, set density and friction
48// More efficient memory usage when passing hull information from BSPrim to BulletSim 46// 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? 47// 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) 48// 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 49// At the moment, physical and phantom causes object to drop through the terrain
53// Physical phantom objects and related typing (collision options ) 50// 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. 51// Check out llVolumeDetect. Must do something for that.
52// Use collision masks for collision with terrain and phantom objects
53// 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? 54// 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. 55// 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 56// 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 57// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 58// 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. 59// 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? 60// Add PID movement operations. What does ScenePresence.MoveToTarget do?
66// Check terrain size. 128 or 127? 61// Check terrain size. 128 or 127?
67// Raycast 62// Raycast
68// 63//
69namespace OpenSim.Region.Physics.BulletSPlugin 64namespace OpenSim.Region.Physics.BulletSPlugin
70{ 65{
71public class BSScene : PhysicsScene, IPhysicsParameters 66public class BSScene : PhysicsScene, IPhysicsParameters
@@ -73,62 +68,59 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 68 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 69 private static readonly string LogHeader = "[BULLETS SCENE]";
75 70
76 public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } 71 // The name of the region we're working for.
72 public string RegionName { get; private set; }
77 73
78 public string BulletSimVersion = "?"; 74 public string BulletSimVersion = "?";
79 75
80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 76 public Dictionary<uint, BSPhysObject> PhysObjects;
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 77 public BSShapeCollection Shapes;
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); 78
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>(); 79 // Keeping track of the objects with collisions so we can report begin and end of a collision
84 private List<BSPrim> m_vehicles = new List<BSPrim>(); 80 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
85 private float[] m_heightMap; 81 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
86 private float m_waterLevel; 82 // Keep track of all the avatars so we can send them a collision event
87 private uint m_worldID; 83 // every tick so OpenSim will update its animation.
88 public uint WorldID { get { return m_worldID; } } 84 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
85
86 // List of all the objects that have vehicle properties and should be called
87 // to update each physics step.
88 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
89 89
90 // let my minuions use my logger 90 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } } 91 public ILog Logger { get { return m_log; } }
92 92
93 private bool m_initialized = false; 93 // If non-zero, the number of simulation steps between calls to the physics
94 94 // engine to output detailed physics stats. Debug logging level must be on also.
95 private int m_detailedStatsStep = 0; 95 private int m_detailedStatsStep = 0;
96 96
97 public IMesher mesher; 97 public IMesher mesher;
98 private float m_meshLOD; 98 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 99 public float MeshLOD { get; private set; }
100 { 100 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 101 public float MeshMegaPrimThreshold { get; private set; }
102 } 102 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 103
109 private BulletSim m_worldSim; 104 public uint WorldID { get; private set; }
110 public BulletSim World 105 public BulletSim World { get; private set; }
111 { 106
112 get { return m_worldSim; } 107 // All the constraints that have been allocated in this instance.
113 } 108 public BSConstraintCollection Constraints { get; private set; }
114 private BSConstraintCollection m_constraintCollection;
115 public BSConstraintCollection Constraints
116 {
117 get { return m_constraintCollection; }
118 }
119 109
110 // Simulation parameters
120 private int m_maxSubSteps; 111 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 112 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 113 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 114 public long SimulationStep { get { return m_simulationStep; } }
124 115
125 public float LastSimulatedTimestep { get; private set; }
126
127 // A value of the time now so all the collision and update routines do not have to get their own 116 // 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 117 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 118 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 119
120 // True if initialized and ready to do simulation steps
121 private bool m_initialized = false;
131 122
123 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 124 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 125 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 126 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +129,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 129 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 130 private GCHandle m_updateArrayPinnedHandle;
139 131
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 132 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 133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
142 134
143 public float PID_D { get; private set; } // derivative 135 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional 136 public float PID_P { get; private set; } // proportional
145 137
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 138 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 139 public const uint GROUNDPLANE_ID = 1;
140 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
141
142 private float m_waterLevel;
143 public BSTerrainManager TerrainManager { get; private set; }
148 144
149 public ConfigurationParameters Params 145 public ConfigurationParameters Params
150 { 146 {
@@ -154,13 +150,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
154 { 150 {
155 get { return new Vector3(0f, 0f, Params.gravity); } 151 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 152 }
157 153 // Just the Z value of the gravity
158 private float m_maximumObjectMass; 154 public float DefaultGravityZ
159 public float MaximumObjectMass
160 { 155 {
161 get { return m_maximumObjectMass; } 156 get { return Params.gravity; }
162 } 157 }
163 158
159 public float MaximumObjectMass { get; private set; }
160
161 // When functions in the unmanaged code must be called, it is only
162 // done at a known time just before the simulation step. The taint
163 // system saves all these function calls and executes them in
164 // order before the simulation.
164 public delegate void TaintCallback(); 165 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 166 private struct TaintCallbackEntry
166 { 167 {
@@ -172,15 +173,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 callback = c; 173 callback = c;
173 } 174 }
174 } 175 }
176 private Object _taintLock = new Object(); // lock for using the next object
175 private List<TaintCallbackEntry> _taintedObjects; 177 private List<TaintCallbackEntry> _taintedObjects;
176 private Object _taintLock = new Object();
177 178
178 // A pointer to an instance if this structure is passed to the C++ code 179 // A pointer to an instance if this structure is passed to the C++ code
180 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 181 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 182 GCHandle m_paramsHandle;
181 183
182 public bool ShouldDebugLog { get; private set; } 184 // Handle to the callback used by the unmanaged code to call into the managed code.
183 185 // Used for debug logging.
186 // Need to store the handle in a persistant variable so it won't be freed.
184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 187 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
185 188
186 // Sometimes you just have to log everything. 189 // Sometimes you just have to log everything.
@@ -189,17 +192,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private string m_physicsLoggingDir; 192 private string m_physicsLoggingDir;
190 private string m_physicsLoggingPrefix; 193 private string m_physicsLoggingPrefix;
191 private int m_physicsLoggingFileMinutes; 194 private int m_physicsLoggingFileMinutes;
195 // 'true' of the vehicle code is to log lots of details
196 public bool VehicleLoggingEnabled { get; private set; }
192 197
193 private bool m_vehicleLoggingEnabled; 198 #region Construction and Initialization
194 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
195
196 public BSScene(string identifier) 199 public BSScene(string identifier)
197 { 200 {
198 m_initialized = false; 201 m_initialized = false;
202 // we are passed the name of the region we're working for.
203 RegionName = identifier;
199 } 204 }
200 205
201 public override void Initialise(IMesher meshmerizer, IConfigSource config) 206 public override void Initialise(IMesher meshmerizer, IConfigSource config)
202 { 207 {
208 mesher = meshmerizer;
209 _taintedObjects = new List<TaintCallbackEntry>();
210 PhysObjects = new Dictionary<uint, BSPhysObject>();
211 Shapes = new BSShapeCollection(this);
212
203 // Allocate pinned memory to pass parameters. 213 // Allocate pinned memory to pass parameters.
204 m_params = new ConfigurationParameters[1]; 214 m_params = new ConfigurationParameters[1];
205 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 215 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,7 +225,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 225
216 // Enable very detailed logging. 226 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 227 // 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. 228 // can be left in and every call doesn't have to check for null.
219 if (m_physicsLoggingEnabled) 229 if (m_physicsLoggingEnabled)
220 { 230 {
221 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 231 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -225,38 +235,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 235 PhysicsLogging = new Logging.LogWriter();
226 } 236 }
227 237
228 // Get the version of the DLL 238 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 239 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) 240 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 241 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 242 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 243 if (PhysicsLogging.Enabled)
244 // 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); 245 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 246 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 247 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 } 248 }
244 249
245 _taintedObjects = new List<TaintCallbackEntry>(); 250 // Get the version of the DLL
251 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
252 // BulletSimVersion = BulletSimAPI.GetVersion();
253 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 254
247 mesher = meshmerizer; 255 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 256 // a child in a mega-region.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 257 // Turns out that Bullet really doesn't care about the extents of the simulated
258 // area. It tracks active objects no matter where they are.
259 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
250 260
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 261 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 262 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 263 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 264 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
265 m_DebugLogCallbackHandle);
255 266
256 // Initialization to support the transition to a new API which puts most of the logic 267 // Initialization to support the transition to a new API which puts most of the logic
257 // into the C# code so it is easier to modify and add to. 268 // into the C# code so it is easier to modify and add to.
258 m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); 269 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
259 m_constraintCollection = new BSConstraintCollection(World); 270
271 Constraints = new BSConstraintCollection(World);
272
273 TerrainManager = new BSTerrainManager(this);
274 TerrainManager.CreateInitialGroundPlaneAndTerrain();
260 275
261 m_initialized = true; 276 m_initialized = true;
262 } 277 }
@@ -281,10 +296,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 296 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 297 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 298 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 299 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 300 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 301 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 302 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
303
304 // Do any replacements in the parameters
305 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 306 }
289 } 307 }
290 } 308 }
@@ -309,13 +327,51 @@ public class BSScene : PhysicsScene, IPhysicsParameters
309 { 327 {
310 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 328 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
311 } 329 }
312 330
313 // Called directly from unmanaged code so don't do much 331 // Called directly from unmanaged code so don't do much
314 private void BulletLoggerPhysLog(string msg) 332 private void BulletLoggerPhysLog(string msg)
315 { 333 {
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 334 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
317 } 335 }
318 336
337 public override void Dispose()
338 {
339 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
340
341 // make sure no stepping happens while we're deleting stuff
342 m_initialized = false;
343
344 TerrainManager.ReleaseGroundPlaneAndTerrain();
345
346 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
347 {
348 kvp.Value.Destroy();
349 }
350 PhysObjects.Clear();
351
352 // Now that the prims are all cleaned up, there should be no constraints left
353 if (Constraints != null)
354 {
355 Constraints.Dispose();
356 Constraints = null;
357 }
358
359 if (Shapes != null)
360 {
361 Shapes.Dispose();
362 Shapes = null;
363 }
364
365 // Anything left in the unmanaged code should be cleaned out
366 BulletSimAPI.Shutdown(WorldID);
367
368 // Not logging any more
369 PhysicsLogging.Close();
370 }
371 #endregion // Construction and Initialization
372
373 #region Prim and Avatar addition and removal
374
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 375 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 376 {
321 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 377 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -329,7 +385,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 385 if (!m_initialized) return null;
330 386
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 387 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 388 lock (PhysObjects) PhysObjects.Add(localID, actor);
389
390 // TODO: Remove kludge someday.
391 // We must generate a collision for avatars whether they collide or not.
392 // This is required by OpenSim to update avatar animations, etc.
393 lock (m_avatars) m_avatars.Add(actor);
394
333 return actor; 395 return actor;
334 } 396 }
335 397
@@ -344,7 +406,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 406 {
345 try 407 try
346 { 408 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 409 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
410 // Remove kludge someday
411 lock (m_avatars) m_avatars.Remove(bsactor);
348 } 412 }
349 catch (Exception e) 413 catch (Exception e)
350 { 414 {
@@ -362,11 +426,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 426 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 427 if (bsprim != null)
364 { 428 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 429 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 430 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 431 try
368 { 432 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 433 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 434 }
371 catch (Exception e) 435 catch (Exception e)
372 { 436 {
@@ -388,18 +452,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 452
389 if (!m_initialized) return null; 453 if (!m_initialized) return null;
390 454
391 // DetailLog("{0},AddPrimShape,call", localID); 455 DetailLog("{0},AddPrimShape,call", localID);
392 456
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 457 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 458 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 459 return prim;
396 } 460 }
397 461
398 // This is a call from the simulator saying that some physical property has been updated. 462 // 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 463 // The BulletSim driver senses the changing of relevant properties so this taint
400 // information call is not needed. 464 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 465 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 466
467 #endregion // Prim and Avatar addition and removal
468
469 #region Simulation
403 // Simulate one timestep 470 // Simulate one timestep
404 public override float Simulate(float timeStep) 471 public override float Simulate(float timeStep)
405 { 472 {
@@ -408,34 +475,46 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 475 int collidersCount = 0;
409 IntPtr collidersPtr; 476 IntPtr collidersPtr;
410 477
411 LastSimulatedTimestep = timeStep; 478 int beforeTime = 0;
479 int simTime = 0;
412 480
413 // prevent simulation until we've been initialized 481 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 482 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 483
418 // update the prim states while we know the physics engine is not busy 484 // update the prim states while we know the physics engine is not busy
485 int numTaints = _taintedObjects.Count;
419 ProcessTaints(); 486 ProcessTaints();
420 487
421 // Some of the prims operate with special vehicle properties 488 // Some of the prims operate with special vehicle properties
422 ProcessVehicles(timeStep); 489 ProcessVehicles(timeStep);
490 numTaints += _taintedObjects.Count;
423 ProcessTaints(); // the vehicles might have added taints 491 ProcessTaints(); // the vehicles might have added taints
424 492
425 // step the physical world one interval 493 // step the physical world one interval
426 m_simulationStep++; 494 m_simulationStep++;
427 int numSubSteps = 0; 495 int numSubSteps = 0;
496
497 // Sometimes needed for debugging to find out what happened before the step
498 // PhysicsLogging.Flush();
499
428 try 500 try
429 { 501 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 502 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
503
504 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 505 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 506
507 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
508 DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
509 DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
433 } 510 }
434 catch (Exception e) 511 catch (Exception e)
435 { 512 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 513 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); 514 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 515 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
516 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
517 updatedEntityCount = 0;
439 collidersCount = 0; 518 collidersCount = 0;
440 } 519 }
441 520
@@ -443,7 +522,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 522 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 523
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 524 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 525 SimulationNowTime = Util.EnvironmentTickCount();
447 526
448 // If there were collisions, process them by sending the event to the prim. 527 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 528 // Collisions must be processed before updates.
@@ -460,21 +539,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
460 } 539 }
461 } 540 }
462 541
542 // This is a kludge to get avatar movement updates.
543 // the simulator expects collisions for avatars even if there are have been no collisions. This updates
544 // avatar animations and stuff.
545 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
546 foreach (BSPhysObject bsp in m_avatars)
547 bsp.SendCollisions();
548
463 // The above SendCollision's batch up the collisions on the objects. 549 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 550 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 551 if (ObjectsWithCollisions.Count > 0)
466 bsp.SendCollisions(); 552 {
467 m_primsWithCollisions.Clear(); 553 foreach (BSPhysObject bsp in ObjectsWithCollisions)
554 if (!m_avatars.Contains(bsp)) // don't call avatars twice
555 if (!bsp.SendCollisions())
556 {
557 // If the object is done colliding, see that it's removed from the colliding list
558 ObjectsWithNoMoreCollisions.Add(bsp);
559 }
560 }
468 561
469 // This is a kludge to get avatar movement updated. 562 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
470 // Don't send collisions only if there were collisions -- send everytime. 563 // Not done above because it is inside an iteration of ObjectWithCollisions.
471 // ODE sends collisions even if there are none and this is used to update 564 if (ObjectsWithNoMoreCollisions.Count > 0)
472 // avatar animations and stuff. 565 {
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 566 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
474 // bsc.SendCollisions(); 567 ObjectsWithCollisions.Remove(po);
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 568 ObjectsWithNoMoreCollisions.Clear();
476 kvp.Value.SendCollisions(); 569 }
477 m_avatarsWithCollisions.Clear();
478 570
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 571 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 572 if (updatedEntityCount > 0)
@@ -482,17 +574,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 574 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 575 {
484 EntityProperties entprop = m_updateArray[ii]; 576 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 577 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 578 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
487 {
488 prim.UpdateProperties(entprop);
489 continue;
490 }
491 BSCharacter actor;
492 if (m_avatars.TryGetValue(entprop.ID, out actor))
493 { 579 {
494 actor.UpdateProperties(entprop); 580 pobj.UpdateProperties(entprop);
495 continue;
496 } 581 }
497 } 582 }
498 } 583 }
@@ -506,121 +591,89 @@ public class BSScene : PhysicsScene, IPhysicsParameters
506 } 591 }
507 } 592 }
508 593
509 // this is a waste since the outside routine also calcuates the physics simulation 594 // 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. 595 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); 596 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
512 // return (timeStep * (float)simulateTotalTime); 597 return numSubSteps * m_fixedTimeStep * 1000;
513
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 } 598 }
522 599
523 // Something has collided 600 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 601 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 602 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 603 if (localID <= TerrainManager.HighestTerrainID)
527 { 604 {
528 return; // don't send collisions to the terrain 605 return; // don't send collisions to the terrain
529 } 606 }
530 607
531 ActorTypes type = ActorTypes.Prim; 608 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 609 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 610 {
534 else if (m_avatars.ContainsKey(collidingWith)) 611 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent; 612 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; 613 return;
542 } 614 }
543 BSCharacter actor; 615
544 if (m_avatars.TryGetValue(localID, out actor)) { 616 // 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); 617 BSPhysObject collidee = null;
546 m_avatarsWithCollisions.Add(actor); 618 PhysObjects.TryGetValue(collidingWith, out collidee);
547 return; 619
620 DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
621
622 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
623 {
624 // If a collision was posted, remember to send it to the simulator
625 ObjectsWithCollisions.Add(collider);
548 } 626 }
627
549 return; 628 return;
550 } 629 }
551 630
552 public override void GetResults() { } 631 #endregion // Simulation
553 632
554 public override void SetTerrain(float[] heightMap) { 633 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 634
562 // Someday we will have complex terrain with caves and tunnels 635 #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 636
569 public float GetTerrainHeightAtXY(float tX, float tY) 637 public override void SetTerrain(float[] heightMap) {
570 { 638 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 } 639 }
575 640
576 public override void SetWaterLevel(float baseheight) 641 public override void SetWaterLevel(float baseheight)
577 { 642 {
578 m_waterLevel = baseheight; 643 m_waterLevel = baseheight;
579 // TODO: pass to physics engine so things will float?
580 } 644 }
581 public float GetWaterLevel() 645 // Someday....
646 public float GetWaterLevelAtXYZ(Vector3 loc)
582 { 647 {
583 return m_waterLevel; 648 return m_waterLevel;
584 } 649 }
585 650
586 public override void DeleteTerrain() 651 public override void DeleteTerrain()
587 { 652 {
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 653 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
589 } 654 }
590 655
591 public override void Dispose() 656 // Although no one seems to check this, I do support combining.
657 public override bool SupportsCombining()
592 { 658 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 659 return TerrainManager.SupportsCombining();
594 660 }
595 // make sure no stepping happens while we're deleting stuff 661 // This call says I am a child to region zero in a mega-region. 'pScene' is that
596 m_initialized = false; 662 // of region zero, 'offset' is my offset from regions zero's origin, and
597 663 // 'extents' is the largest XY that is handled in my region.
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 664 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
599 { 665 {
600 kvp.Value.Destroy(); 666 TerrainManager.Combine(pScene, offset, extents);
601 } 667 }
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 668
620 // Not logging any more 669 // Unhook all the combining that I know about.
621 PhysicsLogging.Close(); 670 public override void UnCombine(PhysicsScene pScene)
671 {
672 TerrainManager.UnCombine(pScene);
622 } 673 }
623 674
675 #endregion // Terrain
676
624 public override Dictionary<uint, float> GetTopColliders() 677 public override Dictionary<uint, float> GetTopColliders()
625 { 678 {
626 return new Dictionary<uint, float>(); 679 return new Dictionary<uint, float>();
@@ -628,121 +681,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
628 681
629 public override bool IsThreaded { get { return false; } } 682 public override bool IsThreaded { get { return false; } }
630 683
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 684 // 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. 685 // 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. 686 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -751,7 +689,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
751 if (!m_initialized) return; 689 if (!m_initialized) return;
752 690
753 lock (_taintLock) 691 lock (_taintLock)
692 {
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 693 _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
694 }
695
755 return; 696 return;
756 } 697 }
757 698
@@ -789,13 +730,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
789 730
790 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 731 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
791 { 732 {
792 if (newType == Vehicle.TYPE_NONE) 733 RemoveVehiclePrim(vehic);
793 { 734 if (newType != Vehicle.TYPE_NONE)
794 RemoveVehiclePrim(vehic);
795 }
796 else
797 { 735 {
798 // make it so the scene will call us each tick to do vehicle things 736 // make it so the scene will call us each tick to do vehicle things
799 AddVehiclePrim(vehic); 737 AddVehiclePrim(vehic);
800 } 738 }
801 } 739 }
@@ -827,17 +765,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
827 } 765 }
828 766
829 // Some prims have extra vehicle actions 767 // Some prims have extra vehicle actions
830 // no locking because only called when physics engine is not busy 768 // Called at taint time!
831 private void ProcessVehicles(float timeStep) 769 private void ProcessVehicles(float timeStep)
832 { 770 {
833 foreach (BSPrim prim in m_vehicles) 771 foreach (BSPhysObject pobj in m_vehicles)
834 { 772 {
835 prim.StepVehicle(timeStep); 773 pobj.StepVehicle(timeStep);
836 } 774 }
837 } 775 }
838 #endregion Vehicles 776 #endregion Vehicles
839 777
840 #region Parameters 778 #region INI and command line parameter processing
841 779
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 780 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 781 delegate float ParamGet(BSScene scene);
@@ -869,7 +807,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
869 // getters and setters. 807 // getters and setters.
870 // It is easiest to find an existing definition and copy it. 808 // It is easiest to find an existing definition and copy it.
871 // Parameter values are floats. Booleans are converted to a floating value. 809 // Parameter values are floats. Booleans are converted to a floating value.
872 // 810 //
873 // A ParameterDefn() takes the following parameters: 811 // A ParameterDefn() takes the following parameters:
874 // -- the text name of the parameter. This is used for console input and ini file. 812 // -- 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. 813 // -- a short text description of the parameter. This shows up in the console listing.
@@ -888,25 +826,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 826 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 827 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 828 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 829 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 830 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 831 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 832 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 833 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 834 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 835 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 836 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
899 837
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 838 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 839 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 840 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 841 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 842 (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)", 843 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
844 16f,
845 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
846 (s) => { return s.MeshMegaPrimLOD; },
847 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
848 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
849 10f,
850 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
851 (s) => { return s.MeshMegaPrimThreshold; },
852 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
853 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 854 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 855 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 856 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 857 (s,p,l,v) => { s.SculptLOD = v; } ),
910 858
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 859 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 860 10f,
@@ -930,9 +878,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 878 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 879 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 880 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 881 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 882 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 883 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 884
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 885 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 886 2200f,
@@ -976,42 +924,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
976 0f, 924 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 925 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 926 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 927 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ),
980 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 928 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 929 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 930 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 931 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 932 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ),
985 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 933 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 934 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 935 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 936 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 937 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ),
990 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 938 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 939 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 940 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 941 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 942 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
995 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 943 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 944 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 945 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 946 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 947 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
1000 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 948 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 949 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 950 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 951 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 952 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 953 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 954 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 955 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 956 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 957 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 958 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 959 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 960 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 961 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 962 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
1015 963
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 964 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 965 0.5f,
@@ -1029,44 +977,44 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1029 (s) => { return s.m_params[0].terrainRestitution; }, 977 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 978 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
1031 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 979 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 980 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 981 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 982 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 983 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1036 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 984 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 985 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 986 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 987 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 988 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 989 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 990 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 991 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 992 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 993 (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", 994 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1047 0.37f, 995 0.37f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 996 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 997 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 998 (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", 999 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 1000 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1001 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 1002 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 1003 (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", 1004 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 1005 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 1006 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1007 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1008 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 1009
1062 1010
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1011 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1064 0f, // zero to disable 1012 0f,
1065 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, 1013 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, 1014 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1067 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), 1015 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1068 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", 1016 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1069 0f, // zero to disable 1017 0f,
1070 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, 1018 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, 1019 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1072 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), 1020 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
@@ -1081,12 +1029,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1081 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, 1029 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1082 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), 1030 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1083 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", 1031 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1084 ConfigurationParameters.numericFalse, 1032 ConfigurationParameters.numericTrue,
1085 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1033 (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; }, 1034 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1087 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1035 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1088 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1036 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1089 ConfigurationParameters.numericFalse, 1037 ConfigurationParameters.numericTrue,
1090 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1038 (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; }, 1039 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1092 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1040 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1121,8 +1069,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1069 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1070 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1071 (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", 1072 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1073 0.1f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1074 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1075 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1076 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
@@ -1131,18 +1079,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1079 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1080 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1081 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1082 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1083 40,
1084 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1085 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1086 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1087
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1088 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1089 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1090 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1091 (s) => { return (float)s.m_detailedStatsStep; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1092 (s,p,l,v) => { s.m_detailedStatsStep = (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 }; 1093 };
1147 1094
1148 // Convert a boolean to our numeric true and false values 1095 // Convert a boolean to our numeric true and false values
@@ -1200,11 +1147,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1147
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1148 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1149
1150 // This creates an array in the correct format for returning the list of
1151 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1152 private void BuildParameterTable()
1204 { 1153 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1154 if (SettableParameters.Length < ParameterDefinitions.Length)
1206 { 1155 {
1207
1208 List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); 1156 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1209 for (int ii = 0; ii < ParameterDefinitions.Length; ii++) 1157 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1210 { 1158 {
@@ -1250,18 +1198,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1250 } 1198 }
1251 1199
1252 // check to see if we are updating a parameter for a particular or all of the prims 1200 // 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) 1201 protected void UpdateParameterObject(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 { 1202 {
1263 List<uint> operateOn; 1203 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1204 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val); 1205 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 } 1206 }
1267 1207
@@ -1284,11 +1224,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1224 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs) 1225 foreach (uint lID in objectIDs)
1286 { 1226 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); 1227 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1288 } 1228 }
1289 }); 1229 });
1290 break; 1230 break;
1291 default: 1231 default:
1292 // setting only one localID 1232 // setting only one localID
1293 TaintedUpdateParameter(parm, localID, val); 1233 TaintedUpdateParameter(parm, localID, val);
1294 break; 1234 break;
@@ -1302,7 +1242,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1302 string xparm = parm.ToLower(); 1242 string xparm = parm.ToLower();
1303 float xval = val; 1243 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1244 TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1245 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
1306 }); 1246 });
1307 } 1247 }
1308 1248
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
new file mode 100755
index 0000000..399a133
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -0,0 +1,737 @@
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 physical objects
55 private struct HullDesc
56 {
57 public IntPtr ptr;
58 public int referenceCount;
59 public DateTime lastReferenced;
60 }
61
62 private struct BodyDesc
63 {
64 public IntPtr ptr;
65 // Bodies are only used once so reference count is always either one or zero
66 public int referenceCount;
67 public DateTime lastReferenced;
68 }
69
70 private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
71 private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73
74 public BSShapeCollection(BSScene physScene)
75 {
76 PhysicsScene = physScene;
77 }
78
79 public void Dispose()
80 {
81 // TODO!!!!!!!!!
82 }
83
84 // Callbacks called just before either the body or shape is destroyed.
85 // Mostly used for changing bodies out from under Linksets.
86 // Useful for other cases where parameters need saving.
87 // Passing 'null' says no callback.
88 public delegate void ShapeDestructionCallback(BulletShape shape);
89 public delegate void BodyDestructionCallback(BulletBody body);
90
91 // Called to update/change the body and shape for an object.
92 // First checks the shape and updates that if necessary then makes
93 // sure the body is of the right type.
94 // Return 'true' if either the body or the shape changed.
95 // Called at taint-time!!
96 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
97 ShapeData shapeData, PrimitiveBaseShape pbs,
98 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
99 {
100 bool ret = false;
101
102 // This lock could probably be pushed down lower but building shouldn't take long
103 lock (m_collectionActivityLock)
104 {
105 // Do we have the correct geometry for this type of object?
106 // Updates prim.BSShape with information/pointers to requested shape
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
108 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body
111 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
112 prim.BSShape, shapeData, bodyCallback);
113 ret = newGeom || newBody;
114 }
115 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
116 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
117
118 return ret;
119 }
120
121 // Track another user of a body
122 // We presume the caller has allocated the body.
123 // Bodies only have one user so the reference count is either 1 or 0.
124 public void ReferenceBody(BulletBody body, bool atTaintTime)
125 {
126 lock (m_collectionActivityLock)
127 {
128 BodyDesc bodyDesc;
129 if (Bodies.TryGetValue(body.ID, out bodyDesc))
130 {
131 bodyDesc.referenceCount++;
132 DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
133 }
134 else
135 {
136 // New entry
137 bodyDesc.ptr = body.ptr;
138 bodyDesc.referenceCount = 1;
139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
140 }
141 bodyDesc.lastReferenced = System.DateTime.Now;
142 Bodies[body.ID] = bodyDesc;
143 }
144 }
145
146 // Release the usage of a body.
147 // Called when releasing use of a BSBody. BSShape is handled separately.
148 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
149 {
150 if (body.ptr == IntPtr.Zero)
151 return;
152
153 lock (m_collectionActivityLock)
154 {
155 BodyDesc bodyDesc;
156 if (Bodies.TryGetValue(body.ID, out bodyDesc))
157 {
158 bodyDesc.referenceCount--;
159 bodyDesc.lastReferenced = System.DateTime.Now;
160 Bodies[body.ID] = bodyDesc;
161 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
162
163 // If body is no longer being used, free it -- bodies are never shared.
164 if (bodyDesc.referenceCount == 0)
165 {
166 Bodies.Remove(body.ID);
167 BSScene.TaintCallback removeOperation = delegate()
168 {
169 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
170 body.ID, body.ptr.ToString("X"));
171 // If the caller needs to know the old body is going away, pass the event up.
172 if (bodyCallback != null) bodyCallback(body);
173
174 // Zero any reference to the shape so it is not freed when the body is deleted.
175 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
176 // It may have already been removed from the world in which case the next is a NOOP.
177 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
178 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
179 };
180 // If already in taint-time, do the operations now. Otherwise queue for later.
181 if (inTaintTime)
182 removeOperation();
183 else
184 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
185 }
186 }
187 else
188 {
189 DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
190 }
191 }
192 }
193
194 // Track the datastructures and use count for a shape.
195 // When creating a hull, this is called first to reference the mesh
196 // and then again to reference the hull.
197 // Meshes and hulls for the same shape have the same hash key.
198 // NOTE that native shapes are not added to the mesh list or removed.
199 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
200 private bool ReferenceShape(BulletShape shape)
201 {
202 bool ret = false;
203 switch (shape.type)
204 {
205 case ShapeData.PhysicsShapeType.SHAPE_MESH:
206 MeshDesc meshDesc;
207 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
208 {
209 // There is an existing instance of this mesh.
210 meshDesc.referenceCount++;
211 DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
212 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
213 }
214 else
215 {
216 // This is a new reference to a mesh
217 meshDesc.ptr = shape.ptr;
218 // We keep a reference to the underlying IMesh data so a hull can be built
219 meshDesc.referenceCount = 1;
220 DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
221 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
222 ret = true;
223 }
224 meshDesc.lastReferenced = System.DateTime.Now;
225 Meshes[shape.shapeKey] = meshDesc;
226 break;
227 case ShapeData.PhysicsShapeType.SHAPE_HULL:
228 HullDesc hullDesc;
229 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
230 {
231 // There is an existing instance of this hull.
232 hullDesc.referenceCount++;
233 DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
234 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
235 }
236 else
237 {
238 // This is a new reference to a hull
239 hullDesc.ptr = shape.ptr;
240 hullDesc.referenceCount = 1;
241 DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
242 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
243 ret = true;
244
245 }
246 hullDesc.lastReferenced = System.DateTime.Now;
247 Hulls[shape.shapeKey] = hullDesc;
248 break;
249 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
250 break;
251 default:
252 // Native shapes are not tracked and they don't go into any list
253 break;
254 }
255 return ret;
256 }
257
258 // Release the usage of a shape.
259 // The collisionObject is released since it is a copy of the real collision shape.
260 public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback)
261 {
262 if (shape.ptr == IntPtr.Zero)
263 return;
264
265 BSScene.TaintCallback dereferenceOperation = delegate()
266 {
267 switch (shape.type)
268 {
269 case ShapeData.PhysicsShapeType.SHAPE_HULL:
270 DereferenceHull(shape, shapeCallback);
271 break;
272 case ShapeData.PhysicsShapeType.SHAPE_MESH:
273 DereferenceMesh(shape, shapeCallback);
274 break;
275 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
276 break;
277 default:
278 // Native shapes are not tracked and are released immediately
279 if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
280 {
281 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
282 BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime);
283 if (shapeCallback != null) shapeCallback(shape);
284 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
285 }
286 break;
287 }
288 };
289 if (atTaintTime)
290 {
291 lock (m_collectionActivityLock)
292 {
293 dereferenceOperation();
294 }
295 }
296 else
297 {
298 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
299 }
300 }
301
302 // Count down the reference count for a mesh shape
303 // Called at taint-time.
304 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
305 {
306 MeshDesc meshDesc;
307 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
308 {
309 meshDesc.referenceCount--;
310 // TODO: release the Bullet storage
311 if (shapeCallback != null) shapeCallback(shape);
312 meshDesc.lastReferenced = System.DateTime.Now;
313 Meshes[shape.shapeKey] = meshDesc;
314 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
315 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
316
317 }
318 }
319
320 // Count down the reference count for a hull shape
321 // Called at taint-time.
322 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
323 {
324 HullDesc hullDesc;
325 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
326 {
327 hullDesc.referenceCount--;
328 // TODO: release the Bullet storage (aging old entries?)
329 if (shapeCallback != null) shapeCallback(shape);
330 hullDesc.lastReferenced = System.DateTime.Now;
331 Hulls[shape.shapeKey] = hullDesc;
332 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
333 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
334 }
335 }
336
337 // Create the geometry information in Bullet for later use.
338 // The objects needs a hull if it's physical otherwise a mesh is enough.
339 // No locking here because this is done when we know physics is not simulating.
340 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
341 // Returns 'true' if the geometry was rebuilt.
342 // Called at taint-time!
343 private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
344 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
345 {
346 bool ret = false;
347 bool haveShape = false;
348 bool nativeShapePossible = true;
349
350 // If the prim attributes are simple, this could be a simple Bullet native shape
351 if (nativeShapePossible
352 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
353 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
354 && pbs.ProfileHollow == 0
355 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
356 && pbs.PathBegin == 0 && pbs.PathEnd == 0
357 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
358 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
359 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
360 {
361 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
362 {
363 haveShape = true;
364 if (forceRebuild
365 || prim.Scale != shapeData.Size
366 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
367 )
368 {
369 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
370 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
371 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
372 prim.LocalID, forceRebuild, prim.BSShape);
373 }
374 }
375 else
376 {
377 haveShape = true;
378 if (forceRebuild
379 || prim.Scale != shapeData.Size
380 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
381 )
382 {
383 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
384 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
385 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
386 prim.LocalID, forceRebuild, prim.BSShape);
387 }
388 }
389 }
390 // If a simple shape is not happening, create a mesh and possibly a hull.
391 // Note that if it's a native shape, the check for physical/non-physical is not
392 // made. Native shapes are best used in either case.
393 if (!haveShape)
394 {
395 if (prim.IsPhysical)
396 {
397 // Update prim.BSShape to reference a hull of this shape.
398 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
399 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
400 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
401 }
402 else
403 {
404 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
405 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
406 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
407 }
408 }
409 return ret;
410 }
411
412 // Creates a native shape and assignes it to prim.BSShape
413 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
414 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
415 ShapeDestructionCallback shapeCallback)
416 {
417 BulletShape newShape;
418
419 shapeData.Type = shapeType;
420 // Bullet native objects are scaled by the Bullet engine so pass the size in
421 prim.Scale = shapeData.Size;
422 shapeData.Scale = shapeData.Size;
423
424 // release any previous shape
425 DereferenceShape(prim.BSShape, true, shapeCallback);
426
427 // Native shapes are always built independently.
428 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
429 newShape.shapeKey = (ulong)shapeKey;
430 newShape.isNativeShape = true;
431
432 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
433 // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
434
435 prim.BSShape = newShape;
436 return true;
437 }
438
439 // Builds a mesh shape in the physical world and updates prim.BSShape.
440 // Dereferences previous shape in BSShape and adds a reference for this new shape.
441 // Returns 'true' of a mesh was actually built. Otherwise .
442 // Called at taint-time!
443 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
444 ShapeDestructionCallback shapeCallback)
445 {
446 BulletShape newShape = new BulletShape(IntPtr.Zero);
447
448 float lod;
449 ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
450
451 // if this new shape is the same as last time, don't recreate the mesh
452 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
453 return false;
454
455 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
456 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
457
458 // Since we're recreating new, get rid of the reference to the previous shape
459 DereferenceShape(prim.BSShape, true, shapeCallback);
460
461 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
462
463 ReferenceShape(newShape);
464
465 // meshes are already scaled by the meshmerizer
466 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
467 prim.BSShape = newShape;
468
469 return true; // 'true' means a new shape has been added to this prim
470 }
471
472 private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
473 {
474 IMesh meshData = null;
475 IntPtr meshPtr;
476 MeshDesc meshDesc;
477 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
478 {
479 // If the mesh has already been built just use it.
480 meshPtr = meshDesc.ptr;
481 }
482 else
483 {
484 // Pass false for physicalness as this creates some sort of bounding box which we don't need
485 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
486
487 int[] indices = meshData.getIndexListAsInt();
488 List<OMV.Vector3> vertices = meshData.getVertexList();
489
490 float[] verticesAsFloats = new float[vertices.Count * 3];
491 int vi = 0;
492 foreach (OMV.Vector3 vv in vertices)
493 {
494 verticesAsFloats[vi++] = vv.X;
495 verticesAsFloats[vi++] = vv.Y;
496 verticesAsFloats[vi++] = vv.Z;
497 }
498
499 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
500 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
501
502 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
503 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
504 }
505 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
506 newShape.shapeKey = newMeshKey;
507
508 return newShape;
509 }
510
511 // See that hull shape exists in the physical world and update prim.BSShape.
512 // We could be creating the hull because scale changed or whatever.
513 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
514 ShapeDestructionCallback shapeCallback)
515 {
516 BulletShape newShape;
517
518 float lod;
519 ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
520
521 // if the hull hasn't changed, don't rebuild it
522 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
523 return false;
524
525 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
526 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
527
528 // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
529 DereferenceShape(prim.BSShape, true, shapeCallback);
530
531 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
532
533 ReferenceShape(newShape);
534
535 // hulls are already scaled by the meshmerizer
536 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
537 prim.BSShape = newShape;
538 return true; // 'true' means a new shape has been added to this prim
539 }
540
541 List<ConvexResult> m_hulls;
542 private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
543 {
544
545 IntPtr hullPtr;
546 HullDesc hullDesc;
547 if (Hulls.TryGetValue(newHullKey, out hullDesc))
548 {
549 // If the hull shape already is created, just use it.
550 hullPtr = hullDesc.ptr;
551 }
552 else
553 {
554 // Build a new hull in the physical world
555 // Pass false for physicalness as this creates some sort of bounding box which we don't need
556 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
557
558 int[] indices = meshData.getIndexListAsInt();
559 List<OMV.Vector3> vertices = meshData.getVertexList();
560
561 //format conversion from IMesh format to DecompDesc format
562 List<int> convIndices = new List<int>();
563 List<float3> convVertices = new List<float3>();
564 for (int ii = 0; ii < indices.GetLength(0); ii++)
565 {
566 convIndices.Add(indices[ii]);
567 }
568 foreach (OMV.Vector3 vv in vertices)
569 {
570 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
571 }
572
573 // setup and do convex hull conversion
574 m_hulls = new List<ConvexResult>();
575 DecompDesc dcomp = new DecompDesc();
576 dcomp.mIndices = convIndices;
577 dcomp.mVertices = convVertices;
578 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
579 // create the hull into the _hulls variable
580 convexBuilder.process(dcomp);
581
582 // Convert the vertices and indices for passing to unmanaged.
583 // The hull information is passed as a large floating point array.
584 // The format is:
585 // convHulls[0] = number of hulls
586 // convHulls[1] = number of vertices in first hull
587 // convHulls[2] = hull centroid X coordinate
588 // convHulls[3] = hull centroid Y coordinate
589 // convHulls[4] = hull centroid Z coordinate
590 // convHulls[5] = first hull vertex X
591 // convHulls[6] = first hull vertex Y
592 // convHulls[7] = first hull vertex Z
593 // convHulls[8] = second hull vertex X
594 // ...
595 // convHulls[n] = number of vertices in second hull
596 // convHulls[n+1] = second hull centroid X coordinate
597 // ...
598 //
599 // TODO: is is very inefficient. Someday change the convex hull generator to return
600 // data structures that do not need to be converted in order to pass to Bullet.
601 // And maybe put the values directly into pinned memory rather than marshaling.
602 int hullCount = m_hulls.Count;
603 int totalVertices = 1; // include one for the count of the hulls
604 foreach (ConvexResult cr in m_hulls)
605 {
606 totalVertices += 4; // add four for the vertex count and centroid
607 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
608 }
609 float[] convHulls = new float[totalVertices];
610
611 convHulls[0] = (float)hullCount;
612 int jj = 1;
613 foreach (ConvexResult cr in m_hulls)
614 {
615 // copy vertices for index access
616 float3[] verts = new float3[cr.HullVertices.Count];
617 int kk = 0;
618 foreach (float3 ff in cr.HullVertices)
619 {
620 verts[kk++] = ff;
621 }
622
623 // add to the array one hull's worth of data
624 convHulls[jj++] = cr.HullIndices.Count;
625 convHulls[jj++] = 0f; // centroid x,y,z
626 convHulls[jj++] = 0f;
627 convHulls[jj++] = 0f;
628 foreach (int ind in cr.HullIndices)
629 {
630 convHulls[jj++] = verts[ind].x;
631 convHulls[jj++] = verts[ind].y;
632 convHulls[jj++] = verts[ind].z;
633 }
634 }
635 // create the hull data structure in Bullet
636 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
637 }
638
639 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
640 newShape.shapeKey = newHullKey;
641
642 return newShape; // 'true' means a new shape has been added to this prim
643 }
644
645 // Callback from convex hull creater with a newly created hull.
646 // Just add it to our collection of hulls for this shape.
647 private void HullReturn(ConvexResult result)
648 {
649 m_hulls.Add(result);
650 return;
651 }
652
653 // Create a hash of all the shape parameters to be used as a key
654 // for this particular shape.
655 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
656 {
657 // level of detail based on size and type of the object
658 float lod = PhysicsScene.MeshLOD;
659 if (pbs.SculptEntry)
660 lod = PhysicsScene.SculptLOD;
661
662 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
663 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
664 lod = PhysicsScene.MeshMegaPrimLOD;
665
666 retLod = lod;
667 return (ulong)pbs.GetMeshKey(shapeData.Size, lod);
668 }
669 // For those who don't want the LOD
670 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
671 {
672 float lod;
673 return ComputeShapeKey(shapeData, pbs, out lod);
674 }
675
676 // Create a body object in Bullet.
677 // Updates prim.BSBody with the information about the new body if one is created.
678 // Returns 'true' if an object was actually created.
679 // Called at taint-time.
680 private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
681 ShapeData shapeData, BodyDestructionCallback bodyCallback)
682 {
683 bool ret = false;
684
685 // the mesh, hull or native shape must have already been created in Bullet
686 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
687
688 // If there is an existing body, verify it's of an acceptable type.
689 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
690 if (!mustRebuild)
691 {
692 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
693 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
694 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
695 {
696 // If the collisionObject is not the correct type for solidness, rebuild what's there
697 mustRebuild = true;
698 }
699
700 }
701
702 if (mustRebuild || forceRebuild)
703 {
704 DereferenceBody(prim.BSBody, true, bodyCallback);
705
706 BulletBody aBody;
707 IntPtr bodyPtr = IntPtr.Zero;
708 if (prim.IsSolid)
709 {
710 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
711 shapeData.ID, shapeData.Position, shapeData.Rotation);
712 // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
713 }
714 else
715 {
716 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
717 shapeData.ID, shapeData.Position, shapeData.Rotation);
718 // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
719 }
720 aBody = new BulletBody(shapeData.ID, bodyPtr);
721
722 ReferenceBody(aBody, true);
723
724 prim.BSBody = aBody;
725
726 ret = true;
727 }
728
729 return ret;
730 }
731
732 private void DetailLog(string msg, params Object[] args)
733 {
734 PhysicsScene.PhysicsLogging.Write(msg, args);
735 }
736}
737}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
new file mode 100755
index 0000000..70aa429
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,493 @@
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 // Everything collides with the ground plane.
118 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
119 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
120
121 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
122 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
123 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
124 float[] initialMap = new float[totalHeights];
125 for (int ii = 0; ii < totalHeights; ii++)
126 {
127 initialMap[ii] = HEIGHT_INITIALIZATION;
128 }
129 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
130 }
131
132 // Release all the terrain structures we might have allocated
133 public void ReleaseGroundPlaneAndTerrain()
134 {
135 if (m_groundPlane.ptr != IntPtr.Zero)
136 {
137 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
138 {
139 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
140 }
141 m_groundPlane.ptr = IntPtr.Zero;
142 }
143
144 ReleaseTerrain();
145 }
146
147 // Release all the terrain we have allocated
148 public void ReleaseTerrain()
149 {
150 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
151 {
152 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
153 {
154 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
155 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
156 }
157 }
158 m_heightMaps.Clear();
159 }
160
161 // The simulator wants to set a new heightmap for the terrain.
162 public void SetTerrain(float[] heightMap) {
163 float[] localHeightMap = heightMap;
164 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
165 {
166 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
167 {
168 // If a child of a mega-region, we shouldn't have any terrain allocated for us
169 ReleaseGroundPlaneAndTerrain();
170 // If doing the mega-prim stuff and we are the child of the zero region,
171 // the terrain is added to our parent
172 if (MegaRegionParentPhysicsScene is BSScene)
173 {
174 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
175 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
176 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
177 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
178 }
179 }
180 else
181 {
182 // If not doing the mega-prim thing, just change the terrain
183 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
184
185 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
186 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
187 }
188 });
189 }
190
191 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
192 // based on the passed information. The 'id' should be either the terrain id or
193 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
194 // The latter feature is for creating child terrains for mega-regions.
195 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
196 // then a new body and shape is created and the mapInfo is filled.
197 // This call is used for doing the initial terrain creation.
198 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
199 // terrain shape is created and added to the body.
200 // This call is most often used to update the heightMap and parameters of the terrain.
201 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
202 // calling this routine from initialization or taint-time routines) or whether to delay
203 // all the unmanaged activities to taint-time.
204 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
205 {
206 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
207 BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);
208
209 float minZ = float.MaxValue;
210 float maxZ = float.MinValue;
211 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
212
213 int heightMapSize = heightMap.Length;
214 for (int ii = 0; ii < heightMapSize; ii++)
215 {
216 float height = heightMap[ii];
217 if (height < minZ) minZ = height;
218 if (height > maxZ) maxZ = height;
219 }
220
221 // The shape of the terrain is from its base to its extents.
222 minCoords.Z = minZ;
223 maxCoords.Z = maxZ;
224
225 BulletHeightMapInfo mapInfo;
226 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
227 {
228 // If this is terrain we know about, it's easy to update
229
230 mapInfo.heightMap = heightMap;
231 mapInfo.minCoords = minCoords;
232 mapInfo.maxCoords = maxCoords;
233 mapInfo.minZ = minZ;
234 mapInfo.maxZ = maxZ;
235 mapInfo.sizeX = maxCoords.X - minCoords.X;
236 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
237 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
238 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
239
240 BSScene.TaintCallback rebuildOperation = delegate()
241 {
242 if (MegaRegionParentPhysicsScene != null)
243 {
244 // It's possible that Combine() was called after this code was queued.
245 // If we are a child of combined regions, we don't create any terrain for us.
246 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
247
248 // Get rid of any terrain that may have been allocated for us.
249 ReleaseGroundPlaneAndTerrain();
250
251 // I hate doing this, but just bail
252 return;
253 }
254
255 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
256 {
257 // Updating an existing terrain.
258 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
259 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
260
261 // Remove from the dynamics world because we're going to mangle this object
262 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
263
264 // Get rid of the old terrain
265 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
266 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
267 mapInfo.Ptr = IntPtr.Zero;
268
269 /*
270 // NOTE: This routine is half here because I can't get the terrain shape replacement
271 // to work. In the short term, the above three lines completely delete the old
272 // terrain and the code below recreates one from scratch.
273 // Hopefully the Bullet community will help me out on this one.
274
275 // First, release the old collision shape (there is only one terrain)
276 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
277
278 // Fill the existing height map info with the new location and size information
279 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
280 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
281
282 // Create a terrain shape based on the new info
283 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
284
285 // Stuff the shape into the existing terrain body
286 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
287 */
288 }
289 // else
290 {
291 // Creating a new terrain.
292 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
293 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
294
295 mapInfo.ID = id;
296 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
297 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
298
299 // The terrain object initial position is at the center of the object
300 Vector3 centerPos;
301 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
302 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
303 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
304
305 // Create the terrain shape from the mapInfo
306 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
307 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
308
309 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
310 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
311 id, centerPos, Quaternion.Identity));
312 }
313
314 // Make sure the entry is in the heightmap table
315 m_heightMaps[terrainRegionBase] = mapInfo;
316
317 // Set current terrain attributes
318 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
319 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
320 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
321 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
322
323 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
324 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
325
326 // Return the new terrain to the world of physical objects
327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
328
329 // redo its bounding box now that it is in the world
330 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
331
332 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
333 (uint)CollisionFilterGroups.TerrainFilter,
334 (uint)CollisionFilterGroups.TerrainMask);
335
336 // Make sure the new shape is processed.
337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
339
340 m_terrainModified = true;
341 };
342
343 // There is the option to do the changes now (we're already in 'taint time'), or
344 // to do the Bullet operations later.
345 if (atTaintTime)
346 rebuildOperation();
347 else
348 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
349 }
350 else
351 {
352 // We don't know about this terrain so either we are creating a new terrain or
353 // our mega-prim child is giving us a new terrain to add to the phys world
354
355 // if this is a child terrain, calculate a unique terrain id
356 uint newTerrainID = id;
357 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
358 newTerrainID = ++m_terrainCount;
359
360 float[] heightMapX = heightMap;
361 Vector3 minCoordsX = minCoords;
362 Vector3 maxCoordsX = maxCoords;
363
364 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
365 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
366
367 // Code that must happen at taint-time
368 BSScene.TaintCallback createOperation = delegate()
369 {
370 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
371 // Create a new mapInfo that will be filled with the new info
372 mapInfo = new BulletHeightMapInfo(id, heightMapX,
373 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
374 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
375 // Put the unfilled heightmap info into the collection of same
376 m_heightMaps.Add(terrainRegionBase, mapInfo);
377 // Build the terrain
378 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
379
380 m_terrainModified = true;
381 };
382
383 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
384 if (atTaintTime)
385 createOperation();
386 else
387 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
388 }
389 }
390
391 // Someday we will have complex terrain with caves and tunnels
392 public float GetTerrainHeightAtXYZ(Vector3 loc)
393 {
394 // For the moment, it's flat and convex
395 return GetTerrainHeightAtXY(loc.X, loc.Y);
396 }
397
398 // Given an X and Y, find the height of the terrain.
399 // Since we could be handling multiple terrains for a mega-region,
400 // the base of the region is calcuated assuming all regions are
401 // the same size and that is the default.
402 // Once the heightMapInfo is found, we have all the information to
403 // compute the offset into the array.
404 private float lastHeightTX = 999999f;
405 private float lastHeightTY = 999999f;
406 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
407 private float GetTerrainHeightAtXY(float tX, float tY)
408 {
409 // You'd be surprized at the number of times this routine is called
410 // with the same parameters as last time.
411 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
412 return lastHeight;
413
414 lastHeightTX = tX;
415 lastHeightTY = tY;
416 float ret = HEIGHT_GETHEIGHT_RET;
417
418 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
419 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
420 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
421
422 BulletHeightMapInfo mapInfo;
423 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
424 {
425 float regionX = tX - offsetX;
426 float regionY = tY - offsetY;
427 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
428 try
429 {
430 ret = mapInfo.heightMap[mapIndex];
431 }
432 catch
433 {
434 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
435 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
436 LogHeader, terrainBaseXY, regionX, regionY);
437 ret = HEIGHT_GETHEIGHT_RET;
438 }
439 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
440 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
441 }
442 else
443 {
444 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
445 LogHeader, PhysicsScene.RegionName, tX, tY);
446 }
447 m_terrainModified = false;
448 lastHeight = ret;
449 return ret;
450 }
451
452 // Although no one seems to check this, I do support combining.
453 public bool SupportsCombining()
454 {
455 return true;
456 }
457
458 // This routine is called two ways:
459 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
460 // extent of the combined regions. This is to inform the parent of the size
461 // of the combined regions.
462 // and one with 'offset' as the offset of the child region to the base region,
463 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
464 // child of its relative base and new parent.
465 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
466 {
467 m_worldOffset = offset;
468 m_worldMax = extents;
469 MegaRegionParentPhysicsScene = pScene;
470 if (pScene != null)
471 {
472 // We are a child.
473 // We want m_worldMax to be the highest coordinate of our piece of terrain.
474 m_worldMax = offset + DefaultRegionSize;
475 }
476 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
477 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
478 }
479
480 // Unhook all the combining that I know about.
481 public void UnCombine(PhysicsScene pScene)
482 {
483 // Just like ODE, for the moment a NOP
484 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
485 }
486
487
488 private void DetailLog(string msg, params Object[] args)
489 {
490 PhysicsScene.PhysicsLogging.Write(msg, args);
491 }
492}
493}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 504bd3c..a43880d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -33,38 +33,154 @@ 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 ulong shapeKey;
105 public bool isNativeShape;
106 // Hulls have an underlying mesh. A pointer to it is hidden here.
107 public override string ToString()
108 {
109 StringBuilder buff = new StringBuilder();
110 buff.Append("<p=");
111 buff.Append(ptr.ToString("X"));
112 buff.Append(",s=");
113 buff.Append(type.ToString());
114 buff.Append(",k=");
115 buff.Append(shapeKey.ToString("X"));
116 buff.Append(",n=");
117 buff.Append(isNativeShape.ToString());
118 buff.Append(">");
119 return buff.ToString();
120 }
50} 121}
51 122
123 // Constraint type values as defined by Bullet
124public enum ConstraintType : int
125{
126 POINT2POINT_CONSTRAINT_TYPE = 3,
127 HINGE_CONSTRAINT_TYPE,
128 CONETWIST_CONSTRAINT_TYPE,
129 D6_CONSTRAINT_TYPE,
130 SLIDER_CONSTRAINT_TYPE,
131 CONTACT_CONSTRAINT_TYPE,
132 D6_SPRING_CONSTRAINT_TYPE,
133 MAX_CONSTRAINT_TYPE
134}
135
136// An allocated Bullet btConstraint
52public struct BulletConstraint 137public struct BulletConstraint
53{ 138{
54 public BulletConstraint(IntPtr xx) { Ptr = xx; } 139 public BulletConstraint(IntPtr xx)
140 {
141 ptr = xx;
142 }
143 public IntPtr ptr;
144}
145
146// An allocated HeightMapThing which holds various heightmap info.
147// Made a class rather than a struct so there would be only one
148// instance of this and C# will pass around pointers rather
149// than making copies.
150public class BulletHeightMapInfo
151{
152 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
153 ID = id;
154 Ptr = xx;
155 heightMap = hm;
156 terrainRegionBase = new Vector2(0f, 0f);
157 minCoords = new Vector3(100f, 100f, 25f);
158 maxCoords = new Vector3(101f, 101f, 26f);
159 minZ = maxZ = 0f;
160 sizeX = sizeY = 256f;
161 }
162 public uint ID;
55 public IntPtr Ptr; 163 public IntPtr Ptr;
164 public float[] heightMap;
165 public Vector2 terrainRegionBase;
166 public Vector3 minCoords;
167 public Vector3 maxCoords;
168 public float sizeX, sizeY;
169 public float minZ, maxZ;
170 public BulletShape terrainShape;
171 public BulletBody terrainBody;
56} 172}
57 173
58// =============================================================================== 174// ===============================================================================
59[StructLayout(LayoutKind.Sequential)] 175[StructLayout(LayoutKind.Sequential)]
60public struct ConvexHull 176public struct ConvexHull
61{ 177{
62 Vector3 Offset; 178 Vector3 Offset;
63 int VertexCount; 179 int VertexCount;
64 Vector3[] Vertices; 180 Vector3[] Vertices;
65} 181}
66[StructLayout(LayoutKind.Sequential)] 182[StructLayout(LayoutKind.Sequential)]
67public struct ShapeData 183public struct ShapeData
68{ 184{
69 public enum PhysicsShapeType 185 public enum PhysicsShapeType
70 { 186 {
@@ -75,7 +191,9 @@ public struct ShapeData
75 SHAPE_CYLINDER = 4, 191 SHAPE_CYLINDER = 4,
76 SHAPE_SPHERE = 5, 192 SHAPE_SPHERE = 5,
77 SHAPE_MESH = 6, 193 SHAPE_MESH = 6,
78 SHAPE_HULL = 7 194 SHAPE_HULL = 7,
195 SHAPE_GROUNDPLANE = 8,
196 SHAPE_TERRAIN = 9,
79 }; 197 };
80 public uint ID; 198 public uint ID;
81 public PhysicsShapeType Type; 199 public PhysicsShapeType Type;
@@ -91,13 +209,24 @@ 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 }
98} 227}
99[StructLayout(LayoutKind.Sequential)] 228[StructLayout(LayoutKind.Sequential)]
100public struct SweepHit 229public struct SweepHit
101{ 230{
102 public uint ID; 231 public uint ID;
103 public float Fraction; 232 public float Fraction;
@@ -174,12 +303,36 @@ public struct ConfigurationParameters
174 public float linkConstraintTransMotorMaxForce; 303 public float linkConstraintTransMotorMaxForce;
175 public float linkConstraintERP; 304 public float linkConstraintERP;
176 public float linkConstraintCFM; 305 public float linkConstraintCFM;
306 public float linkConstraintSolverIterations;
177 307
178 public const float numericTrue = 1f; 308 public const float numericTrue = 1f;
179 public const float numericFalse = 0f; 309 public const float numericFalse = 0f;
180} 310}
181 311
182// Values used by Bullet and BulletSim to control collisions 312
313// The states a bullet collision object can have
314public enum ActivationState : uint
315{
316 ACTIVE_TAG = 1,
317 ISLAND_SLEEPING,
318 WANTS_DEACTIVATION,
319 DISABLE_DEACTIVATION,
320 DISABLE_SIMULATION,
321}
322
323public enum CollisionObjectTypes : int
324{
325 CO_COLLISION_OBJECT = 1 << 0,
326 CO_RIGID_BODY = 1 << 1,
327 CO_GHOST_OBJECT = 1 << 2,
328 CO_SOFT_BODY = 1 << 3,
329 CO_HF_FLUID = 1 << 4,
330 CO_USER_TYPE = 1 << 5,
331}
332
333// Values used by Bullet and BulletSim to control object properties.
334// Bullet's "CollisionFlags" has more to do with operations on the
335// object (if collisions happen, if gravity effects it, ...).
183public enum CollisionFlags : uint 336public enum CollisionFlags : uint
184{ 337{
185 CF_STATIC_OBJECT = 1 << 0, 338 CF_STATIC_OBJECT = 1 << 0,
@@ -191,11 +344,55 @@ public enum CollisionFlags : uint
191 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 344 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
192 // Following used by BulletSim to control collisions 345 // Following used by BulletSim to control collisions
193 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 346 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
194 BS_VOLUME_DETECT_OBJECT = 1 << 11, 347 BS_FLOATS_ON_WATER = 1 << 11,
195 BS_PHANTOM_OBJECT = 1 << 12, 348 BS_NONE = 0,
196 BS_PHYSICAL_OBJECT = 1 << 13, 349 BS_ALL = 0xFFFFFFFF,
350
351 // These are the collision flags switched depending on physical state.
352 // The other flags are used for other things and should not be fooled with.
353 BS_ACTIVE = CF_STATIC_OBJECT
354 | CF_KINEMATIC_OBJECT
355 | CF_NO_CONTACT_RESPONSE
356};
357
358// Values for collisions groups and masks
359public enum CollisionFilterGroups : uint
360{
361 // Don't use the bit definitions!! Define the use in a
362 // filter/mask definition below. This way collision interactions
363 // are more easily debugged.
364 BNoneFilter = 0,
365 BDefaultFilter = 1 << 0,
366 BStaticFilter = 1 << 1,
367 BKinematicFilter = 1 << 2,
368 BDebrisFilter = 1 << 3,
369 BSensorTrigger = 1 << 4,
370 BCharacterFilter = 1 << 5,
371 BAllFilter = 0xFFFFFFFF,
372 // Filter groups defined by BulletSim
373 BGroundPlaneFilter = 1 << 10,
374 BTerrainFilter = 1 << 11,
375 BRaycastFilter = 1 << 12,
376 BSolidFilter = 1 << 13,
377
378 // The collsion filters and masked are defined in one place -- don't want them scattered
379 AvatarFilter = BCharacterFilter,
380 AvatarMask = BAllFilter,
381 ObjectFilter = BSolidFilter,
382 ObjectMask = BAllFilter,
383 StaticObjectFilter = BStaticFilter,
384 StaticObjectMask = BAllFilter,
385 VolumeDetectFilter = BSensorTrigger,
386 VolumeDetectMask = ~BSensorTrigger,
387 TerrainFilter = BTerrainFilter,
388 TerrainMask = BAllFilter & ~BStaticFilter,
389 GroundPlaneFilter = BAllFilter,
390 GroundPlaneMask = BAllFilter
391
197}; 392};
198 393
394
395
199// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 396// 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. 397// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
201public enum ConstraintParams : int 398public enum ConstraintParams : int
@@ -221,14 +418,22 @@ public enum ConstraintParamAxis : int
221// =============================================================================== 418// ===============================================================================
222static class BulletSimAPI { 419static class BulletSimAPI {
223 420
421// Link back to the managed code for outputting log messages
422[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
423public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
424
224[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
225[return: MarshalAs(UnmanagedType.LPStr)] 426[return: MarshalAs(UnmanagedType.LPStr)]
226public static extern string GetVersion(); 427public static extern string GetVersion();
227 428
228[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 429[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
229public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 430public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
230 int maxCollisions, IntPtr collisionArray, 431 int maxCollisions, IntPtr collisionArray,
231 int maxUpdates, IntPtr updateArray); 432 int maxUpdates, IntPtr updateArray,
433 DebugLogCallback logRoutine);
434
435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
436public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
232 437
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 438[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 439public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
@@ -242,19 +447,19 @@ public static extern bool UpdateParameter(uint worldID, uint localID,
242 447
243// =============================================================================== 448// ===============================================================================
244[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
245public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 450public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
246 out int updatedEntityCount, 451 out int updatedEntityCount,
247 out IntPtr updatedEntitiesPtr, 452 out IntPtr updatedEntitiesPtr,
248 out int collidersCount, 453 out int collidersCount,
249 out IntPtr collidersPtr); 454 out IntPtr collidersPtr);
250 455
251[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 456[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
252public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, 457public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
253 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls 458 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
254 ); 459 );
255 460
256[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
257public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, 462public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
258 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, 463 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
259 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices 464 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
260 ); 465 );
@@ -268,23 +473,6 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
268[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
269public static extern bool CreateObject(uint worldID, ShapeData shapeData); 474public static extern bool CreateObject(uint worldID, ShapeData shapeData);
270 475
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] 476[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
289public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 477public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
290 478
@@ -300,6 +488,7 @@ public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 veloc
300[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 488[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
301public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); 489public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
302 490
491// Set the current force acting on the object
303[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 492[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
304public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); 493public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
305 494
@@ -342,8 +531,6 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
342public static extern void DumpBulletStatistics(); 531public static extern void DumpBulletStatistics();
343 532
344// Log a debug message 533// Log a debug message
345[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
346public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 534[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
348public static extern void SetDebugLogCallback(DebugLogCallback callback); 535public static extern void SetDebugLogCallback(DebugLogCallback callback);
349 536
@@ -358,6 +545,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 545// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
359// and the old code is removed. 546// and the old code is removed.
360 547
548// Functions use while converting from API1 to API2. Can be removed when totally converted.
361[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
362public static extern IntPtr GetSimHandle2(uint worldID); 550public static extern IntPtr GetSimHandle2(uint worldID);
363 551
@@ -368,6 +556,7 @@ public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
368public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); 556public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
369 557
370// =============================================================================== 558// ===============================================================================
559// Initialization and simulation
371[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
372public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 561public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
373 int maxCollisions, IntPtr collisionArray, 562 int maxCollisions, IntPtr collisionArray,
@@ -377,14 +566,14 @@ public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
377public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 566public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
378 567
379[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 568[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
380public static extern void SetHeightmap2(IntPtr world, float[] heightmap); 569public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
381 570
382[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 571[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
383public static extern void Shutdown2(IntPtr sim); 572public static extern void Shutdown2(IntPtr sim);
384 573
385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 574[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
386public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, 575public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
387 out int updatedEntityCount, 576 out int updatedEntityCount,
388 out IntPtr updatedEntitiesPtr, 577 out IntPtr updatedEntitiesPtr,
389 out int collidersCount, 578 out int collidersCount,
390 out IntPtr collidersPtr); 579 out IntPtr collidersPtr);
@@ -392,24 +581,87 @@ public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSt
392[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
393public static extern bool PushUpdate2(IntPtr obj); 582public static extern bool PushUpdate2(IntPtr obj);
394 583
395/* 584// =====================================================================================
585// Mesh, hull, shape and body creation helper routines
396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
397public static extern IntPtr CreateMesh2(IntPtr world, int indicesCount, int* indices, int verticesCount, float* vertices ); 587public static extern IntPtr CreateMeshShape2(IntPtr world,
588 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
589 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
398 590
399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 591[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
400public static extern bool BuildHull2(IntPtr world, IntPtr mesh); 592public static extern IntPtr CreateHullShape2(IntPtr world,
593 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
401 594
402[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
403public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh); 596public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
404 597
405[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 598[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
406public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh); 599public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
407 600
408[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
409public static extern IntPtr CreateObject2(IntPtr world, ShapeData shapeData); 602public static extern bool IsNativeShape2(IntPtr shape);
410*/
411 603
412[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
605public static extern IntPtr CreateCompoundShape2(IntPtr sim);
606
607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
608public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
609
610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
611public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
612
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
614public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
615
616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
617public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
618
619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
620public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
621
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern int GetBodyType2(IntPtr obj);
624
625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
626public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
627
628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
629public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
630
631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
632public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
633
634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
635public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
636
637[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
638public static extern void ReleaseBodyInfo2(IntPtr obj);
639
640[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
641public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
642
643// =====================================================================================
644// Terrain creation and helper routines
645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
646public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
647 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
648
649[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
650public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
651 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
652
653[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
654public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
655
656[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
657public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
658
659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
660public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
661
662// =====================================================================================
663// Constraint creation and helper routines
664[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
413public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 665public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
414 Vector3 frame1loc, Quaternion frame1rot, 666 Vector3 frame1loc, Quaternion frame1rot,
415 Vector3 frame2loc, Quaternion frame2rot, 667 Vector3 frame2loc, Quaternion frame2rot,
@@ -433,7 +685,7 @@ public static extern void SetConstraintEnable2(IntPtr constrain, float numericTr
433public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); 685public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
434 686
435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 687[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
436public static extern bool SetFrames2(IntPtr constrain, 688public static extern bool SetFrames2(IntPtr constrain,
437 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); 689 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
438 690
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 691[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -460,11 +712,108 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams
460[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 712[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
461public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); 713public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
462 714
715// =====================================================================================
716// btCollisionWorld entries
717[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
718public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
719
720[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
721public static extern void UpdateAabbs2(IntPtr world);
722
723[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
724public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
725
726[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
727public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
728
729// =====================================================================================
730// btDynamicsWorld entries
463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 731[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
464public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); 732public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
465 733
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 734[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 735public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
736
737[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
738public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
739
740[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
741public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
742// =====================================================================================
743// btCollisionObject entries
744[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
745public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
746
747[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
748public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
749
750[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
751public static extern bool HasAnisotripicFriction2(IntPtr constrain);
752
753[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
754public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
755
756[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
757public static extern float GetContactProcessingThreshold2(IntPtr obj);
758
759[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
760public static extern bool IsStaticObject2(IntPtr obj);
761
762[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
763public static extern bool IsKinematicObject2(IntPtr obj);
764
765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
766public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
767
768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
769public static extern bool HasContactResponse2(IntPtr obj);
770
771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
772public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
773
774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
775public static extern IntPtr GetCollisionShape2(IntPtr obj);
776
777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
778public static extern int GetActivationState2(IntPtr obj);
779
780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
781public static extern void SetActivationState2(IntPtr obj, int state);
782
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern float GetDeactivationTime2(IntPtr obj);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void Activate2(IntPtr obj, bool forceActivation);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern bool IsActive2(IntPtr obj);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void SetRestitution2(IntPtr obj, float val);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern float GetRestitution2(IntPtr obj);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern void SetFriction2(IntPtr obj, float val);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern float GetFriction2(IntPtr obj);
809
810 /* Haven't defined the type 'Transform'
811[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
812public static extern Transform GetWorldTransform2(IntPtr obj);
813
814[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
815public static extern void setWorldTransform2(IntPtr obj, Transform trans);
816 */
468 817
469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 818[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
470public static extern Vector3 GetPosition2(IntPtr obj); 819public static extern Vector3 GetPosition2(IntPtr obj);
@@ -473,85 +822,293 @@ public static extern Vector3 GetPosition2(IntPtr obj);
473public static extern Quaternion GetOrientation2(IntPtr obj); 822public static extern Quaternion GetOrientation2(IntPtr obj);
474 823
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 824[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); 825public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
477 826
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 827[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity); 828public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
480 829
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 830[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); 831public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
483 832
833 /*
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); 835public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
486 836
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 837[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern bool AddObjectForce2(IntPtr obj, Vector3 force); 838public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
839 */
489 840
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); 842public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
492 843
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val); 845public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
495 846
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping); 848public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
498 849
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern bool SetDeactivationTime2(IntPtr obj, float val); 851public static extern float GetHitFraction2(IntPtr obj);
501 852
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); 854public static extern void SetHitFraction2(IntPtr obj, float val);
504 855
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); 857public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
507 858
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 859[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern bool SetFriction2(IntPtr obj, float val); 860public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
510 861
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 862[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern bool SetRestitution2(IntPtr obj, float val); 863public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
513 864
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 865[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val); 866public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
516 867
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); 869public static extern float GetCcdMotionThreshold2(IntPtr obj);
519 870
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 871[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); 872public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
873
874[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
875public static extern float GetCcdSweepSphereRadius2(IntPtr obj);
876
877[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
878public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val);
879
880[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
881public static extern IntPtr GetUserPointer2(IntPtr obj);
882
883[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
884public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
885
886// =====================================================================================
887// btRigidBody entries
888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
889public static extern void ApplyGravity2(IntPtr obj);
890
891[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
892public static extern void SetGravity2(IntPtr obj, Vector3 val);
893
894[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
895public static extern Vector3 GetGravity2(IntPtr obj);
896
897[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
898public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
899
900[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
901public static extern float GetLinearDamping2(IntPtr obj);
902
903[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
904public static extern float GetAngularDamping2(IntPtr obj);
905
906[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
907public static extern float GetLinearSleepingThreshold2(IntPtr obj);
908
909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
910public static extern float GetAngularSleepingThreshold2(IntPtr obj);
911
912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
913public static extern void ApplyDamping2(IntPtr obj, float timeStep);
914
915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
916public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
917
918[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
919public static extern Vector3 GetLinearFactor2(IntPtr obj);
920
921[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
922public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
923
924 /*
925[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
926public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
927 */
928
929[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
930public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
931
932// Add a force to the object as if its mass is one.
933[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
934public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
935
936// Set the force being applied to the object as if its mass is one.
937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
938public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
939
940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
941public static extern Vector3 GetTotalForce2(IntPtr obj);
942
943[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
944public static extern Vector3 GetTotalTorque2(IntPtr obj);
945
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
948
949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
950public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
951
952[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
953public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
954
955[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
956public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
957
958// Apply force at the given point. Will add torque to the object.
959[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
960public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
961
962// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
963[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
964public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
965
966// Apply impulse to the object's torque. Force is scaled by object's mass.
967[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
968public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
969
970// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
971[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
972public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
973
974[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
975public static extern void ClearForces2(IntPtr obj);
976
977[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
978public static extern void ClearAllForces2(IntPtr obj);
979
980[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
981public static extern void UpdateInertiaTensor2(IntPtr obj);
982
983[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
984public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
985
986 /*
987[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
988public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
989 */
990
991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
992public static extern Vector3 GetLinearVelocity2(IntPtr obj);
993
994[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
995public static extern Vector3 GetAngularVelocity2(IntPtr obj);
996
997[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
998public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
999
1000[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1001public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1002
1003[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1004public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1005
1006[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1007public static extern void Translate2(IntPtr obj, Vector3 trans);
1008
1009[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1010public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1011
1012[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1013public static extern bool WantsSleeping2(IntPtr obj);
1014
1015[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1016public static extern void SetAngularFactor2(IntPtr obj, float factor);
1017
1018[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1019public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1020
1021[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1022public static extern Vector3 GetAngularFactor2(IntPtr obj);
1023
1024[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1025public static extern bool IsInWorld2(IntPtr obj);
1026
1027[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1028public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1029
1030[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1031public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1032
1033[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1034public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1035
1036[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1037public static extern int GetNumConstraintRefs2(IntPtr obj);
1038
1039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1040public static extern Vector3 GetDeltaLinearVelocity2(IntPtr obj);
1041
1042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1043public static extern Vector3 GetDeltaAngularVelocity2(IntPtr obj);
1044
1045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1046public static extern Vector3 GetPushVelocity2(IntPtr obj);
1047
1048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1049public static extern Vector3 GetTurnVelocity2(IntPtr obj);
1050
1051[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1052public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1053
1054// =====================================================================================
1055// btCollisionShape entries
1056
1057[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1058public static extern float GetAngularMotionDisc2(IntPtr shape);
1059
1060[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1061public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1062
1063[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1064public static extern bool IsPolyhedral2(IntPtr shape);
1065
1066[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1067public static extern bool IsConvex2d2(IntPtr shape);
1068
1069[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1070public static extern bool IsConvex2(IntPtr shape);
1071
1072[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1073public static extern bool IsNonMoving2(IntPtr shape);
1074
1075[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1076public static extern bool IsConcave2(IntPtr shape);
522 1077
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1078[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags); 1079public static extern bool IsCompound2(IntPtr shape);
525 1080
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1081[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); 1082public static extern bool IsSoftBody2(IntPtr shape);
528 1083
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1084[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); 1085public static extern bool IsInfinite2(IntPtr shape);
531 1086
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1087[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); 1088public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
534 1089
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1090[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern bool UpdateInertiaTensor2(IntPtr obj); 1091public static extern Vector3 GetLocalScaling2(IntPtr shape);
537 1092
538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1093[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
539public static extern bool SetGravity2(IntPtr obj, Vector3 val); 1094public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
540 1095
541[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1096[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
542public static extern IntPtr ClearForces2(IntPtr obj); 1097public static extern int GetShapeType2(IntPtr shape);
543 1098
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1099[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr ClearAllForces2(IntPtr obj); 1100public static extern void SetMargin2(IntPtr shape, float val);
546 1101
547[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1102[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
548public static extern bool SetMargin2(IntPtr obj, float val); 1103public static extern float GetMargin2(IntPtr shape);
549 1104
1105// =====================================================================================
1106// Debugging
550[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
551public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); 1108public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
552 1109
553[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
554public static extern bool DestroyObject2(IntPtr world, uint id); 1111public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
555 1112
556[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
557public static extern void DumpPhysicsStatistics2(IntPtr sim); 1114public static extern void DumpPhysicsStatistics2(IntPtr sim);
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index a41c856..eb02536 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -63,6 +63,9 @@ namespace OpenSim.Region.Physics.OdePlugin
63 63
64 private bool m_isphysical; 64 private bool m_isphysical;
65 65
66 public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } }
67 private int m_expectedCollisionContacts = 0;
68
66 /// <summary> 69 /// <summary>
67 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. 70 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
68 /// </summary> 71 /// </summary>
@@ -150,7 +153,7 @@ namespace OpenSim.Region.Physics.OdePlugin
150 153
151 private PrimitiveBaseShape _pbs; 154 private PrimitiveBaseShape _pbs;
152 private OdeScene _parent_scene; 155 private OdeScene _parent_scene;
153 156
154 /// <summary> 157 /// <summary>
155 /// The physics space which contains prim geometries 158 /// The physics space which contains prim geometries
156 /// </summary> 159 /// </summary>
@@ -840,7 +843,7 @@ namespace OpenSim.Region.Physics.OdePlugin
840 int vertexStride, triStride; 843 int vertexStride, triStride;
841 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap 844 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
842 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage 845 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
843 846 m_expectedCollisionContacts = indexCount;
844 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory 847 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
845 848
846 // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at 849 // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at
@@ -1377,6 +1380,7 @@ Console.WriteLine("CreateGeom:");
1377 { 1380 {
1378//Console.WriteLine(" CreateGeom 1"); 1381//Console.WriteLine(" CreateGeom 1");
1379 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); 1382 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1383 m_expectedCollisionContacts = 3;
1380 } 1384 }
1381 catch (AccessViolationException) 1385 catch (AccessViolationException)
1382 { 1386 {
@@ -1391,6 +1395,7 @@ Console.WriteLine("CreateGeom:");
1391 { 1395 {
1392//Console.WriteLine(" CreateGeom 2"); 1396//Console.WriteLine(" CreateGeom 2");
1393 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); 1397 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1398 m_expectedCollisionContacts = 4;
1394 } 1399 }
1395 catch (AccessViolationException) 1400 catch (AccessViolationException)
1396 { 1401 {
@@ -1406,6 +1411,7 @@ Console.WriteLine("CreateGeom:");
1406 { 1411 {
1407//Console.WriteLine(" CreateGeom 3"); 1412//Console.WriteLine(" CreateGeom 3");
1408 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); 1413 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1414 m_expectedCollisionContacts = 4;
1409 } 1415 }
1410 catch (AccessViolationException) 1416 catch (AccessViolationException)
1411 { 1417 {
@@ -1421,6 +1427,7 @@ Console.WriteLine("CreateGeom:");
1421 { 1427 {
1422//Console.WriteLine(" CreateGeom 4"); 1428//Console.WriteLine(" CreateGeom 4");
1423 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); 1429 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1430 m_expectedCollisionContacts = 4;
1424 } 1431 }
1425 catch (AccessViolationException) 1432 catch (AccessViolationException)
1426 { 1433 {
@@ -1446,11 +1453,13 @@ Console.WriteLine("CreateGeom:");
1446 _parent_scene.geom_name_map.Remove(prim_geom); 1453 _parent_scene.geom_name_map.Remove(prim_geom);
1447 _parent_scene.actor_name_map.Remove(prim_geom); 1454 _parent_scene.actor_name_map.Remove(prim_geom);
1448 d.GeomDestroy(prim_geom); 1455 d.GeomDestroy(prim_geom);
1456 m_expectedCollisionContacts = 0;
1449 prim_geom = IntPtr.Zero; 1457 prim_geom = IntPtr.Zero;
1450 } 1458 }
1451 catch (System.AccessViolationException) 1459 catch (System.AccessViolationException)
1452 { 1460 {
1453 prim_geom = IntPtr.Zero; 1461 prim_geom = IntPtr.Zero;
1462 m_expectedCollisionContacts = 0;
1454 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); 1463 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1455 1464
1456 return false; 1465 return false;
@@ -2395,15 +2404,15 @@ Console.WriteLine(" JointCreateFixed");
2395 { 2404 {
2396 get 2405 get
2397 { 2406 {
2398 // Averate previous velocity with the new one so 2407 // Average previous velocity with the new one so
2399 // client object interpolation works a 'little' better 2408 // client object interpolation works a 'little' better
2400 if (_zeroFlag) 2409 if (_zeroFlag)
2401 return Vector3.Zero; 2410 return Vector3.Zero;
2402 2411
2403 Vector3 returnVelocity = Vector3.Zero; 2412 Vector3 returnVelocity = Vector3.Zero;
2404 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2; 2413 returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2'
2405 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2; 2414 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f;
2406 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2; 2415 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f;
2407 return returnVelocity; 2416 return returnVelocity;
2408 } 2417 }
2409 set 2418 set
@@ -2600,6 +2609,7 @@ Console.WriteLine(" JointCreateFixed");
2600 { 2609 {
2601 Vector3 pv = Vector3.Zero; 2610 Vector3 pv = Vector3.Zero;
2602 bool lastZeroFlag = _zeroFlag; 2611 bool lastZeroFlag = _zeroFlag;
2612 float m_minvelocity = 0;
2603 if (Body != (IntPtr)0) // FIXME -> or if it is a joint 2613 if (Body != (IntPtr)0) // FIXME -> or if it is a joint
2604 { 2614 {
2605 d.Vector3 vec = d.BodyGetPosition(Body); 2615 d.Vector3 vec = d.BodyGetPosition(Body);
@@ -2752,8 +2762,21 @@ Console.WriteLine(" JointCreateFixed");
2752 _acceleration = ((_velocity - m_lastVelocity) / 0.1f); 2762 _acceleration = ((_velocity - m_lastVelocity) / 0.1f);
2753 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); 2763 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f);
2754 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); 2764 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString());
2765
2766 // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing...
2767 // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large.
2768 // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles
2769 // adding these logical exclusion situations to maintain this where I think it was intended to be.
2770 if (m_throttleUpdates || m_usePID || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero))
2771 {
2772 m_minvelocity = 0.5f;
2773 }
2774 else
2775 {
2776 m_minvelocity = 0.02f;
2777 }
2755 2778
2756 if (_velocity.ApproxEquals(pv, 0.5f)) 2779 if (_velocity.ApproxEquals(pv, m_minvelocity))
2757 { 2780 {
2758 m_rotationalVelocity = pv; 2781 m_rotationalVelocity = pv;
2759 } 2782 }
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 929b019..7a50c4c 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -336,6 +336,7 @@ namespace OpenSim.Region.Physics.OdePlugin
336 336
337 public int geomContactPointsStartthrottle = 3; 337 public int geomContactPointsStartthrottle = 3;
338 public int geomUpdatesPerThrottledUpdate = 15; 338 public int geomUpdatesPerThrottledUpdate = 15;
339 private const int avatarExpectedContacts = 3;
339 340
340 public float bodyPIDD = 35f; 341 public float bodyPIDD = 35f;
341 public float bodyPIDG = 25; 342 public float bodyPIDG = 25;
@@ -474,6 +475,8 @@ namespace OpenSim.Region.Physics.OdePlugin
474 private OdePrim cp1; 475 private OdePrim cp1;
475 private OdeCharacter cc2; 476 private OdeCharacter cc2;
476 private OdePrim cp2; 477 private OdePrim cp2;
478 private int p1ExpectedPoints = 0;
479 private int p2ExpectedPoints = 0;
477 //private int cStartStop = 0; 480 //private int cStartStop = 0;
478 //private string cDictKey = ""; 481 //private string cDictKey = "";
479 482
@@ -498,6 +501,7 @@ namespace OpenSim.Region.Physics.OdePlugin
498 public int physics_logging_interval = 0; 501 public int physics_logging_interval = 0;
499 public bool physics_logging_append_existing_logfile = false; 502 public bool physics_logging_append_existing_logfile = false;
500 503
504
501 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); 505 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
502 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); 506 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
503 507
@@ -644,7 +648,7 @@ namespace OpenSim.Region.Physics.OdePlugin
644 648
645 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); 649 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
646 650
647 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); 651 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
648 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); 652 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
649 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); 653 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
650 654
@@ -1064,7 +1068,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1064 1068
1065 PhysicsActor p1; 1069 PhysicsActor p1;
1066 PhysicsActor p2; 1070 PhysicsActor p2;
1067 1071
1072 p1ExpectedPoints = 0;
1073 p2ExpectedPoints = 0;
1074
1068 if (!actor_name_map.TryGetValue(g1, out p1)) 1075 if (!actor_name_map.TryGetValue(g1, out p1))
1069 { 1076 {
1070 p1 = PANull; 1077 p1 = PANull;
@@ -1121,9 +1128,13 @@ namespace OpenSim.Region.Physics.OdePlugin
1121 switch (p1.PhysicsActorType) 1128 switch (p1.PhysicsActorType)
1122 { 1129 {
1123 case (int)ActorTypes.Agent: 1130 case (int)ActorTypes.Agent:
1131 p1ExpectedPoints = avatarExpectedContacts;
1124 p2.CollidingObj = true; 1132 p2.CollidingObj = true;
1125 break; 1133 break;
1126 case (int)ActorTypes.Prim: 1134 case (int)ActorTypes.Prim:
1135 if (p1 != null && p1 is OdePrim)
1136 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1137
1127 if (p2.Velocity.LengthSquared() > 0.0f) 1138 if (p2.Velocity.LengthSquared() > 0.0f)
1128 p2.CollidingObj = true; 1139 p2.CollidingObj = true;
1129 break; 1140 break;
@@ -1319,6 +1330,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1319 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && 1330 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1320 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) 1331 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1321 { 1332 {
1333 p2ExpectedPoints = avatarExpectedContacts;
1322 // Avatar is moving on terrain, use the movement terrain contact 1334 // Avatar is moving on terrain, use the movement terrain contact
1323 AvatarMovementTerrainContact.geom = curContact; 1335 AvatarMovementTerrainContact.geom = curContact;
1324 1336
@@ -1332,6 +1344,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1332 { 1344 {
1333 if (p2.PhysicsActorType == (int)ActorTypes.Agent) 1345 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1334 { 1346 {
1347 p2ExpectedPoints = avatarExpectedContacts;
1335 // Avatar is standing on terrain, use the non moving terrain contact 1348 // Avatar is standing on terrain, use the non moving terrain contact
1336 TerrainContact.geom = curContact; 1349 TerrainContact.geom = curContact;
1337 1350
@@ -1356,9 +1369,18 @@ namespace OpenSim.Region.Physics.OdePlugin
1356 } 1369 }
1357 1370
1358 if (p2 is OdePrim) 1371 if (p2 is OdePrim)
1359 material = ((OdePrim)p2).m_material; 1372 {
1360 1373 material = ((OdePrim) p2).m_material;
1374 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1375 }
1376
1377 // Unnessesary because p1 is defined above
1378 //if (p1 is OdePrim)
1379 // {
1380 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1381 // }
1361 //m_log.DebugFormat("Material: {0}", material); 1382 //m_log.DebugFormat("Material: {0}", material);
1383
1362 m_materialContacts[material, movintYN].geom = curContact; 1384 m_materialContacts[material, movintYN].geom = curContact;
1363 1385
1364 if (m_global_contactcount < maxContactsbeforedeath) 1386 if (m_global_contactcount < maxContactsbeforedeath)
@@ -1379,7 +1401,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1379 int material = (int)Material.Wood; 1401 int material = (int)Material.Wood;
1380 1402
1381 if (p2 is OdePrim) 1403 if (p2 is OdePrim)
1404 {
1382 material = ((OdePrim)p2).m_material; 1405 material = ((OdePrim)p2).m_material;
1406 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1407 }
1383 1408
1384 //m_log.DebugFormat("Material: {0}", material); 1409 //m_log.DebugFormat("Material: {0}", material);
1385 m_materialContacts[material, movintYN].geom = curContact; 1410 m_materialContacts[material, movintYN].geom = curContact;
@@ -1429,6 +1454,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1429 { 1454 {
1430 if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) 1455 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1431 { 1456 {
1457 p2ExpectedPoints = avatarExpectedContacts;
1432 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) 1458 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1433 { 1459 {
1434 // Avatar is moving on a prim, use the Movement prim contact 1460 // Avatar is moving on a prim, use the Movement prim contact
@@ -1458,7 +1484,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1458 int material = (int)Material.Wood; 1484 int material = (int)Material.Wood;
1459 1485
1460 if (p2 is OdePrim) 1486 if (p2 is OdePrim)
1487 {
1461 material = ((OdePrim)p2).m_material; 1488 material = ((OdePrim)p2).m_material;
1489 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1490 }
1462 1491
1463 //m_log.DebugFormat("Material: {0}", material); 1492 //m_log.DebugFormat("Material: {0}", material);
1464 m_materialContacts[material, 0].geom = curContact; 1493 m_materialContacts[material, 0].geom = curContact;
@@ -1479,8 +1508,8 @@ namespace OpenSim.Region.Physics.OdePlugin
1479 } 1508 }
1480 1509
1481 collision_accounting_events(p1, p2, maxDepthContact); 1510 collision_accounting_events(p1, p2, maxDepthContact);
1482 1511
1483 if (count > geomContactPointsStartthrottle) 1512 if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1484 { 1513 {
1485 // If there are more then 3 contact points, it's likely 1514 // If there are more then 3 contact points, it's likely
1486 // that we've got a pile of objects, so ... 1515 // that we've got a pile of objects, so ...