aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
authorDiva Canto2012-11-27 14:43:01 -0800
committerDiva Canto2012-11-27 14:43:01 -0800
commita82f699f4348ea1ab139ab338973c9cee04df712 (patch)
treed1bf4948670e1d207fe4f6c60f6b7771e1625839 /OpenSim/Region/Physics
parentPrevent the core Groups module from being enabled when its name doesn't match... (diff)
parentBulletSim: reorganize linear movement routine into separate subroutines enabl... (diff)
downloadopensim-SC_OLD-a82f699f4348ea1ab139ab338973c9cee04df712.zip
opensim-SC_OLD-a82f699f4348ea1ab139ab338973c9cee04df712.tar.gz
opensim-SC_OLD-a82f699f4348ea1ab139ab338973c9cee04df712.tar.bz2
opensim-SC_OLD-a82f699f4348ea1ab139ab338973c9cee04df712.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs39
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs579
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs6
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs191
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs273
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs9
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs120
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs80
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs75
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs421
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs170
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs339
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs262
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs220
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs3
16 files changed, 1670 insertions, 1121 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index f33c124..4c195e1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -78,11 +78,17 @@ public sealed class BSCharacter : BSPhysObject
78 private float _PIDHoverTao; 78 private float _PIDHoverTao;
79 79
80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
81 : base(parent_scene, localID, avName, "BSCharacter")
81 { 82 {
82 base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
83 _physicsActorType = (int)ActorTypes.Agent; 83 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 84 _position = pos;
85
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
85 _size = size; 88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
86 _flying = isFlying; 92 _flying = isFlying;
87 _orientation = OMV.Quaternion.Identity; 93 _orientation = OMV.Quaternion.Identity;
88 _velocity = OMV.Vector3.Zero; 94 _velocity = OMV.Vector3.Zero;
@@ -131,6 +137,10 @@ public sealed class BSCharacter : BSPhysObject
131 // Set the velocity and compute the proper friction 137 // Set the velocity and compute the proper friction
132 ForceVelocity = _velocity; 138 ForceVelocity = _velocity;
133 139
140 // This will enable or disable the flying buoyancy of the avatar.
141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying;
143
134 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
135 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
136 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
@@ -171,8 +181,7 @@ public sealed class BSCharacter : BSPhysObject
171 get 181 get
172 { 182 {
173 // Avatar capsule size is kept in the scale parameter. 183 // Avatar capsule size is kept in the scale parameter.
174 // return _size; 184 return _size;
175 return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z);
176 } 185 }
177 186
178 set { 187 set {
@@ -180,8 +189,8 @@ public sealed class BSCharacter : BSPhysObject
180 _size = value; 189 _size = value;
181 ComputeAvatarScale(_size); 190 ComputeAvatarScale(_size);
182 ComputeAvatarVolumeAndMass(); 191 ComputeAvatarVolumeAndMass();
183 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", 192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
184 LocalID, Scale, _avatarDensity, _avatarVolume, RawMass); 193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
185 194
186 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
187 { 196 {
@@ -199,9 +208,9 @@ public sealed class BSCharacter : BSPhysObject
199 set { BaseShape = value; } 208 set { BaseShape = value; }
200 } 209 }
201 // I want the physics engine to make an avatar capsule 210 // I want the physics engine to make an avatar capsule
202 public override ShapeData.PhysicsShapeType PreferredPhysicalShape 211 public override BSPhysicsShapeType PreferredPhysicalShape
203 { 212 {
204 get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; } 213 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
205 } 214 }
206 215
207 public override bool Grabbed { 216 public override bool Grabbed {
@@ -610,13 +619,19 @@ public sealed class BSCharacter : BSPhysObject
610 // The 'size' given by the simulator is the mid-point of the avatar 619 // The 'size' given by the simulator is the mid-point of the avatar
611 // and X and Y are unspecified. 620 // and X and Y are unspecified.
612 621
613 OMV.Vector3 newScale = OMV.Vector3.Zero; 622 OMV.Vector3 newScale = size;
614 newScale.X = PhysicsScene.Params.avatarCapsuleRadius; 623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
615 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; 624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
616 625
617 // From the total height, remove the capsule half spheres that are at each end 626 // From the total height, remove the capsule half spheres that are at each end
618 newScale.Z = size.Z- (newScale.X + newScale.Y); 627 // The 1.15f came from ODE. Not sure what this factors in.
619 Scale = newScale; 628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
629
630 // The total scale height is the central cylindar plus the caps on the two ends.
631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
632
633 // Convert diameters to radii and height to half height -- the way Bullet expects it.
634 Scale = newScale / 2f;
620 } 635 }
621 636
622 // set _avatarVolume and _mass based on capsule size, _density and Scale 637 // set _avatarVolume and _mass based on capsule size, _density and Scale
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..74eb9ab 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
80 private Quaternion m_referenceFrame = Quaternion.Identity; 80 private Quaternion m_referenceFrame = Quaternion.Identity;
81 81
82 // Linear properties 82 // Linear properties
83 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 84 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center 85 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 86 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
87 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 87 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
88 private float m_linearMotorDecayTimescale = 0; 88 private float m_linearMotorDecayTimescale = 0;
89 private float m_linearMotorTimescale = 0; 89 private float m_linearMotorTimescale = 0;
@@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
93 // private Vector3 m_linearMotorOffset = Vector3.Zero; 93 // private Vector3 m_linearMotorOffset = Vector3.Zero;
94 94
95 //Angular properties 95 //Angular properties
96 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 97 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
97 // private int m_angularMotorApply = 0; // application frame counter 98 // private int m_angularMotorApply = 0; // application frame counter
98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 99 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
@@ -124,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. 125 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
125 126
126 //Attractor properties 127 //Attractor properties
128 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
127 private float m_verticalAttractionEfficiency = 1.0f; // damped 129 private float m_verticalAttractionEfficiency = 1.0f; // damped
128 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 130 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
129 131
@@ -152,10 +154,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 154 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 155 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 156 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 157 m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
158 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 159 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 160 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 161 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
162 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 163 break;
160 case Vehicle.BANKING_EFFICIENCY: 164 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 165 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
@@ -185,33 +189,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 189 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 190 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 191 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 192 m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
193 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 194 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 195 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 196 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
197 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 198 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 200 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
201 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 202 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 203 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 204 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
205 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 206 break;
199 207
200 // These are vector properties but the engine lets you use a single float value to 208 // These are vector properties but the engine lets you use a single float value to
201 // set all of the components to the same value 209 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 210 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 211 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
212 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 213 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 214 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 215 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 216 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 217 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 218 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 219 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
220 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 221 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 222 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 223 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 224 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
225 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 226 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 227 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 228 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 238 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 239 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 240 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
241 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 242 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 243 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 244 // Limit requested angular speed to 2 rps= 4 pi rads/sec
@@ -234,14 +246,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 246 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 247 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 248 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 249 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 250 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 251 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 252 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 254 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 255 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 256 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 257 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
258 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 259 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 260 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 261 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 317 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 318 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 319 m_VehicleBuoyancy = 0;
306 320
307 m_linearDeflectionEfficiency = 1; 321 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 322 m_linearDeflectionTimescale = 1;
309 323
@@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 333
320 m_referenceFrame = Quaternion.Identity; 334 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 335 m_flags = (VehicleFlag)0;
336
322 break; 337 break;
323 338
324 case Vehicle.TYPE_SLED: 339 case Vehicle.TYPE_SLED:
@@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 366 m_bankingMix = 1;
352 367
353 m_referenceFrame = Quaternion.Identity; 368 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 369 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 370 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 371 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 372 | VehicleFlag.HOVER_UP_ONLY);
373 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
374 | VehicleFlag.LIMIT_ROLL_ONLY
375 | VehicleFlag.LIMIT_MOTOR_UP);
358 break; 376 break;
359 case Vehicle.TYPE_CAR: 377 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 378 m_linearMotorDirection = Vector3.Zero;
@@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 528 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 529 break;
512 } 530 }
531
532 // Update any physical parameters based on this type.
533 Refresh();
534
535 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
536 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
537 1f);
538 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
539
540 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
541 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
542 1f);
543 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
544
545 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
546 BSMotor.Infinite, BSMotor.InfiniteVector,
547 m_verticalAttractionEfficiency);
548 // Z goes away and we keep X and Y
549 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
550 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
551
552 // m_bankingMotor = new BSVMotor("BankingMotor", ...);
513 } 553 }
514 554
515 // Some of the properties of this prim may have changed. 555 // Some of the properties of this prim may have changed.
@@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
518 { 558 {
519 if (IsActive) 559 if (IsActive)
520 { 560 {
521 // Friction effects are handled by this vehicle code 561 m_vehicleMass = Prim.Linkset.LinksetMass;
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
524
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
526 562
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 563 // Friction effects are handled by this vehicle code
564 float friction = 0f;
565 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
566
567 // Moderate angular movement introduced by Bullet.
568 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
569 // Maybe compute linear and angular factor and damping from params.
570 float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
571 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
572
573 // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
574 // Vector3 localInertia = new Vector3(1f, 1f, 1f);
575 Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
576 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
577
578 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
579 Prim.LocalID, friction, localInertia, angularDamping);
528 } 580 }
529 } 581 }
530 582
@@ -551,111 +603,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin
551 { 603 {
552 if (!IsActive) return; 604 if (!IsActive) return;
553 605
554 // DEBUG
555 // Because Bullet does apply forces to the vehicle, our last computed
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564
565 MoveLinear(pTimestep); 606 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 607 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 608
571 LimitRotation(pTimestep); 609 LimitRotation(pTimestep);
572 610
573 // remember the position so next step we can limit absolute movement effects 611 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 612 m_lastPositionVector = Prim.ForcePosition;
575 613
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
577 Prim.LocalID,
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
580 Prim.Inertia,
581 m_vehicleMass
582 );
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 614 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 615 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
585 }// end Step 616 }
586 617
587 // Apply the effect of the linear motor. 618 // Apply the effect of the linear motor.
588 // Also does hover and float. 619 // Also does hover and float.
589 private void MoveLinear(float pTimestep) 620 private void MoveLinear(float pTimestep)
590 { 621 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 622 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
594 {
595 Vector3 origDir = m_linearMotorDirection; // DEBUG
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
599 623
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 624 // Rotate new object velocity from vehicle relative to world coordinates
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; 625 linearMotorContribution *= Prim.ForceOrientation;
602 m_lastLinearVelocityVector += addAmount;
603 626
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 627 // ==================================================================
605 m_linearMotorDirection *= (1f - decayFactor); 628 // Gravity and Buoyancy
629 // There is some gravity, make a gravity force vector that is applied after object velocity.
630 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
631 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
606 632
607 // Rotate new object velocity from vehicle relative to world coordinates 633 Vector3 pos = Prim.ForcePosition;
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; 634 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
609 635
610 // Apply friction for next time 636 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 637
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 638 Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 639
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 640 ComputeLinearBlockingEndPoint(pTimestep, ref pos);
617 } 641
618 else 642 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
619 { 643
620 // if what remains of direction is very small, zero it. 644 // ==================================================================
621 m_linearMotorDirection = Vector3.Zero; 645 Vector3 newVelocity = linearMotorContribution
622 m_lastLinearVelocityVector = Vector3.Zero; 646 + terrainHeightContribution
623 m_newVelocity = Vector3.Zero; 647 + hoverContribution
648 + limitMotorUpContribution;
649
650 // If not changing some axis, reduce out velocity
651 if ((m_flags & (VehicleFlag.NO_X)) != 0)
652 newVelocity.X = 0;
653 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
654 newVelocity.Y = 0;
655 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
656 newVelocity.Z = 0;
624 657
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 658 // ==================================================================
659 // Clamp REALLY high or low velocities
660 float newVelocityLengthSq = newVelocity.LengthSquared();
661 if (newVelocityLengthSq > 1e6f)
662 {
663 newVelocity /= newVelocity.Length();
664 newVelocity *= 1000f;
626 } 665 }
666 else if (newVelocityLengthSq < 1e-6f)
667 newVelocity = Vector3.Zero;
627 668
628 // m_newVelocity is velocity computed from linear motor in world coordinates 669 // ==================================================================
670 // Stuff new linear velocity into the vehicle
671 Prim.ForceVelocity = newVelocity;
672 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
629 673
630 // Gravity and Buoyancy 674 // Other linear forces are applied as forces.
631 // There is some gravity, make a gravity force vector that is applied after object velocity. 675 Vector3 totalDownForce = grav * m_vehicleMass;
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 676 if (totalDownForce != Vector3.Zero)
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 677 {
678 Prim.AddForce(totalDownForce, false);
679 }
634 680
635 /* 681 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... 682 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
637 // Preserve the current Z velocity 683 newVelocity, Prim.Velocity, totalDownForce);
638 Vector3 vel_now = m_prim.Velocity;
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
640 */
641 684
642 Vector3 pos = Prim.ForcePosition; 685 } // end MoveLinear()
643// 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);
644 686
687 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight)
688 {
689 Vector3 ret = Vector3.Zero;
645 // If below the terrain, move us above the ground a little. 690 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 691 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
648 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. 692 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
649 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; 693 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
650 // if (rotatedSize.Z < terrainHeight) 694 // if (rotatedSize.Z < terrainHeight)
651 if (pos.Z < terrainHeight) 695 if (pos.Z < terrainHeight)
652 { 696 {
697 // TODO: correct position by applying force rather than forcing position.
653 pos.Z = terrainHeight + 2; 698 pos.Z = terrainHeight + 2;
654 Prim.ForcePosition = pos; 699 Prim.ForcePosition = pos;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 700 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
656 } 701 }
702 return ret;
703 }
704
705 public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight)
706 {
707 Vector3 ret = Vector3.Zero;
657 708
658 // Check if hovering
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 709 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 710 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 711 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -694,28 +744,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
694 // RA: where does the 50 come from? 744 // RA: where does the 50 come from?
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 745 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
696 // Replace Vertical speed with correction figure if significant 746 // Replace Vertical speed with correction figure if significant
697 if (Math.Abs(verticalError) > 0.01f) 747 if (verticalError > 0.01f)
698 { 748 {
699 m_newVelocity.Z += verticalCorrectionVelocity; 749 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
700 //KF: m_VhoverEfficiency is not yet implemented 750 //KF: m_VhoverEfficiency is not yet implemented
701 } 751 }
702 else if (verticalError < -0.01) 752 else if (verticalError < -0.01)
703 { 753 {
704 m_newVelocity.Z -= verticalCorrectionVelocity; 754 ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
705 }
706 else
707 {
708 m_newVelocity.Z = 0f;
709 } 755 }
710 } 756 }
711 757
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); 758 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
759 Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
713 } 760 }
714 761
762 return ret;
763 }
764
765 public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
766 {
767 bool changed = false;
768
715 Vector3 posChange = pos - m_lastPositionVector; 769 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 770 if (m_BlockingEndPoint != Vector3.Zero)
717 { 771 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 772 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 773 {
721 pos.X -= posChange.X + 1; 774 pos.X -= posChange.X + 1;
@@ -748,75 +801,45 @@ namespace OpenSim.Region.Physics.BulletSPlugin
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 801 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 802 }
750 } 803 }
804 return changed;
805 }
751 806
752 #region downForce 807 public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
753 Vector3 downForce = Vector3.Zero; 808 {
754 809 Vector3 ret = Vector3.Zero;
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 810 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 811 {
757 // If the vehicle is motoring into the sky, get it going back down. 812 // If the vehicle is motoring into the sky, get it going back down.
758 // Is this an angular force or both linear and angular??
759 float distanceAboveGround = pos.Z - terrainHeight; 813 float distanceAboveGround = pos.Z - terrainHeight;
760 if (distanceAboveGround > 2f) 814 if (distanceAboveGround > 1f)
761 { 815 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); 816 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 817 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 818 ret = new Vector3(0, 0, -distanceAboveGround);
765 } 819 }
766 // TODO: this calculation is all wrong. From the description at 820 // TODO: this calculation is all wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 821 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 822 // has a decay factor. This says this force should
769 // be computed with a motor. 823 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 824 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
771 Prim.LocalID, distanceAboveGround, downForce); 825 Prim.LocalID, distanceAboveGround, ret);
772 } 826 }
773 #endregion // downForce 827 return ret;
774 828 }
775 // If not changing some axis, reduce out velocity
776 if ((m_flags & (VehicleFlag.NO_X)) != 0)
777 m_newVelocity.X = 0;
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
779 m_newVelocity.Y = 0;
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
781 m_newVelocity.Z = 0;
782
783 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f)
785 {
786 m_newVelocity /= m_newVelocity.Length();
787 m_newVelocity *= 1000f;
788 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f)
790 m_newVelocity = Vector3.Zero;
791
792 // Stuff new linear velocity into the vehicle
793 Prim.ForceVelocity = m_newVelocity;
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
795
796 Vector3 totalDownForce = downForce + grav;
797 if (totalDownForce != Vector3.Zero)
798 {
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 }
802
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
805
806 } // end MoveLinear()
807 829
808 // ======================================================================= 830 // =======================================================================
831 // =======================================================================
809 // Apply the effect of the angular motor. 832 // Apply the effect of the angular motor.
810 private void MoveAngular(float pTimestep) 833 private void MoveAngular(float pTimestep)
811 { 834 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 835 // m_angularMotorDirection // angular velocity requested by LSL motor
813 // m_angularMotorApply // application frame counter
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down) 836 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
815 // m_angularMotorTimescale // motor angular velocity ramp up rate 837 // m_angularMotorTimescale // motor angular velocity ramp up time
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate 838 // m_angularMotorDecayTimescale // motor angular velocity decay rate
817 // m_angularFrictionTimescale // body angular velocity decay rate 839 // m_angularFrictionTimescale // body angular velocity decay rate
818 // m_lastAngularVelocity // what was last applied to body 840 // m_lastAngularVelocity // what was last applied to body
819 841
842 /*
820 if (m_angularMotorDirection.LengthSquared() > 0.0001) 843 if (m_angularMotorDirection.LengthSquared() > 0.0001)
821 { 844 {
822 Vector3 origVel = m_angularMotorVelocity; 845 Vector3 origVel = m_angularMotorVelocity;
@@ -835,59 +858,152 @@ namespace OpenSim.Region.Physics.BulletSPlugin
835 { 858 {
836 m_angularMotorVelocity = Vector3.Zero; 859 m_angularMotorVelocity = Vector3.Zero;
837 } 860 }
861 */
862
863 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
838 864
839 #region Vertical attactor 865 // ==================================================================
866 // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
867 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
868 {
869 angularMotorContribution.X = 0f;
870 angularMotorContribution.Y = 0f;
871 VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
872 }
840 873
841 Vector3 vertattr = Vector3.Zero; 874 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844 875
845 // If vertical attaction timescale is reasonable and we applied an angular force last time... 876 Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 877
878 Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
879
880 // ==================================================================
881 m_lastVertAttractor = verticalAttractionContribution;
882
883 // Sum velocities
884 m_lastAngularVelocity = angularMotorContribution
885 + verticalAttractionContribution
886 + bankingContribution
887 + deflectionContribution;
888
889 // ==================================================================
890 //Offset section
891 if (m_linearMotorOffset != Vector3.Zero)
892 {
893 //Offset of linear velocity doesn't change the linear velocity,
894 // but causes a torque to be applied, for example...
895 //
896 // IIIII >>> IIIII
897 // IIIII >>> IIIII
898 // IIIII >>> IIIII
899 // ^
900 // | Applying a force at the arrow will cause the object to move forward, but also rotate
901 //
902 //
903 // The torque created is the linear velocity crossed with the offset
904
905 // TODO: this computation should be in the linear section
906 // because that is where we know the impulse being applied.
907 Vector3 torqueFromOffset = Vector3.Zero;
908 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
909 if (float.IsNaN(torqueFromOffset.X))
910 torqueFromOffset.X = 0;
911 if (float.IsNaN(torqueFromOffset.Y))
912 torqueFromOffset.Y = 0;
913 if (float.IsNaN(torqueFromOffset.Z))
914 torqueFromOffset.Z = 0;
915 torqueFromOffset *= m_vehicleMass;
916 Prim.ApplyTorqueImpulse(torqueFromOffset, true);
917 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
918 }
919
920 // ==================================================================
921 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
922 {
923 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
924 Prim.ZeroAngularMotion(true);
925 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
926 }
927 else
847 { 928 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; 929 // Apply to the body.
849 if (Prim.IsColliding) 930 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); 931 // Since we are stuffing the angular velocity directly into the object, the computed
932 // velocity needs to be scaled by the timestep.
933 // Also remove any motion that is on the object so added motion is only from vehicle.
934 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
935 - Prim.ForceRotationalVelocity);
936 // Unscale the force by the angular factor so it overwhelmes the Bullet additions.
937 Prim.ForceRotationalVelocity = applyAngularForce;
938
939 VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
940 Prim.LocalID,
941 angularMotorContribution, verticalAttractionContribution,
942 bankingContribution, deflectionContribution,
943 applyAngularForce, m_lastAngularVelocity
944 );
945 }
946 }
851 947
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 948 public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
949 {
950 Vector3 ret = Vector3.Zero;
853 951
854 // Create a vector of the vehicle "up" in world coordinates 952 // If vertical attaction timescale is reasonable and we applied an angular force last time...
953 if (m_verticalAttractionTimescale < 500)
954 {
955 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
956 verticalError.Normalize();
957 m_verticalAttractionMotor.SetCurrent(verticalError);
958 m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
959 ret = m_verticalAttractionMotor.Step(pTimestep);
960 /*
961 // Take a vector pointing up and convert it from world to vehicle relative coords.
855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; 962 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no 963 verticalError.Normalize();
857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its 964
858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall 965 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be 966 // is now leaning to one side (rotated around the X axis) and the Y value will
860 // modulated to prevent a stable inverted body. 967 // go from zero (nearly straight up) to one (completely to the side) or leaning
861 968 // front-to-back (rotated around the Y axis) and the value of X will be between
862 // Error is 0 (no error) to +/- 2 (max error) 969 // zero and one.
863 if (verticalError.Z < 0.0f) 970 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
971
972 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
973 if (verticalError.Z < 0f)
864 { 974 {
865 verticalError.X = 2.0f - verticalError.X; 975 verticalError.X = 2f - verticalError.X;
866 verticalError.Y = 2.0f - verticalError.Y; 976 verticalError.Y = 2f - verticalError.Y;
867 } 977 }
868 // scale it by VAservo (timestep and timescale)
869 verticalError = verticalError * VAservo;
870 978
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y 979 // Y error means needed rotation around X axis and visa versa.
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X. 980 verticalAttractionContribution.X = verticalError.Y;
873 // Z is not changed. 981 verticalAttractionContribution.Y = - verticalError.X;
874 vertattr.X = verticalError.Y; 982 verticalAttractionContribution.Z = 0f;
875 vertattr.Y = - verticalError.X; 983
876 vertattr.Z = 0f; 984 // scale by the time scale and timestep
985 Vector3 unscaledContrib = verticalAttractionContribution;
986 verticalAttractionContribution /= m_verticalAttractionTimescale;
987 verticalAttractionContribution *= pTimestep;
877 988
878 // scaling appears better usingsquare-law 989 // apply efficiency
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity; 990 Vector3 preEfficiencyContrib = verticalAttractionContribution;
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 991 float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
881 vertattr.X += bounce * angularVelocity.X; 992 verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
882 vertattr.Y += bounce * angularVelocity.Y;
883 993
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 994 VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); 995 Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
996 m_verticalAttractionEfficiency, efficencySquared,
997 verticalAttractionContribution);
998 */
886 999
887 } 1000 }
888 #endregion // Vertical attactor 1001 return ret;
1002 }
889 1003
890 #region Deflection 1004 public Vector3 ComputeAngularDeflection(float pTimestep)
1005 {
1006 Vector3 ret = Vector3.Zero;
891 1007
892 if (m_angularDeflectionEfficiency != 0) 1008 if (m_angularDeflectionEfficiency != 0)
893 { 1009 {
@@ -899,32 +1015,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); 1015 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900 1016
901 // Scale by efficiency and timescale 1017 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; 1018 ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
1019
1020 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
903 1021
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct. 1022 // This deflection computation is not correct.
907 deflection = Vector3.Zero; 1023 ret = Vector3.Zero;
908 } 1024 }
1025 return ret;
1026 }
909 1027
910 #endregion 1028 public Vector3 ComputeAngularBanking(float pTimestep)
911 1029 {
912 #region Banking 1030 Vector3 ret = Vector3.Zero;
913 1031
914 if (m_bankingEfficiency != 0) 1032 if (m_bankingEfficiency != 0)
915 { 1033 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1034 Vector3 dir = Vector3.One * Prim.ForceOrientation;
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); 1035 float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns 1036 //Changes which way it banks in and out of turns
919 1037
920 //Use the square of the efficiency, as it looks much more how SL banking works 1038 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency); 1039 float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
922 if (m_bankingEfficiency < 0) 1040 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative! 1041 effSquared *= -1; //Keep the negative!
924 1042
925 float mix = Math.Abs(m_bankingMix); 1043 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0) 1044 if (m_angularMotorVelocity.X == 0)
927 { 1045 {
1046 // The vehicle is stopped
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) 1047 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 { 1048 {
930 Vector3 axisAngle; 1049 Vector3 axisAngle;
@@ -938,101 +1057,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
938 }*/ 1057 }*/
939 } 1058 }
940 else 1059 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; 1060 {
1061 ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
1062 }
1063
1064 //If they are colliding, we probably shouldn't shove the prim around... probably
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) 1065 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 { 1066 {
945 float angVelZ = m_angularMotorVelocity.X*-1; 1067 float angVelZ = m_angularMotorVelocity.X * -1;
946 /*if(angVelZ > mix) 1068 /*if(angVelZ > mix)
947 angVelZ = mix; 1069 angVelZ = mix;
948 else if(angVelZ < -mix) 1070 else if(angVelZ < -mix)
949 angVelZ = -mix;*/ 1071 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs 1072 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); 1073 Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
952 if (bankingRot.X > 3) 1074 if (bankingRot.X > 3)
953 bankingRot.X = 3; 1075 bankingRot.X = 3;
954 else if (bankingRot.X < -3) 1076 else if (bankingRot.X < -3)
955 bankingRot.X = -3; 1077 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation; 1078 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot; 1079 ret += bankingRot;
958 } 1080 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; 1081 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", 1082 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); 1083 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
962 } 1084 }
1085 return ret;
1086 }
963 1087
964 #endregion
965
966 m_lastVertAttractor = vertattr;
967
968 // Sum velocities
969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
970
971 #region Linear Motor Offset
972
973 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero)
975 {
976 //Offset of linear velocity doesn't change the linear velocity,
977 // but causes a torque to be applied, for example...
978 //
979 // IIIII >>> IIIII
980 // IIIII >>> IIIII
981 // IIIII >>> IIIII
982 // ^
983 // | Applying a force at the arrow will cause the object to move forward, but also rotate
984 //
985 //
986 // The torque created is the linear velocity crossed with the offset
987
988 // NOTE: this computation does should be in the linear section
989 // because there we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X))
993 torqueFromOffset.X = 0;
994 if (float.IsNaN(torqueFromOffset.Y))
995 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass;
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 }
1002
1003 #endregion
1004
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1006 {
1007 m_lastAngularVelocity.X = 0;
1008 m_lastAngularVelocity.Y = 0;
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
1010 }
1011
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1013 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
1015 Prim.ZeroAngularMotion(true);
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
1017 }
1018 else
1019 {
1020 // Apply to the body.
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
1022 // Since we are stuffing the angular velocity directly into the object, the computed
1023 // velocity needs to be scaled by the timestep.
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
1025 Prim.ForceRotationalVelocity = applyAngularForce;
1026
1027 // Decay the angular movement for next time
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
1029 m_lastAngularVelocity *= Vector3.One - decayamount;
1030
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
1033 }
1034 } //end MoveAngular
1035 1088
1089 // This is from previous instantiations of XXXDynamics.cs.
1090 // Applies roll reference frame.
1091 // TODO: is this the right way to separate the code to do this operation?
1092 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1093 internal void LimitRotation(float timestep)
1037 { 1094 {
1038 Quaternion rotq = Prim.ForceOrientation; 1095 Quaternion rotq = Prim.ForceOrientation;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 436e043..0df4310 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -82,9 +82,9 @@ public abstract class BSLinkset
82 82
83 // Some linksets have a preferred physical shape. 83 // Some linksets have a preferred physical shape.
84 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. 84 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
85 public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 85 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
86 { 86 {
87 return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; 87 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 } 88 }
89 89
90 // Linksets move around the children so the linkset might need to compute the child position 90 // Linksets move around the children so the linkset might need to compute the child position
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 3238c85..b9c2cf9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -42,12 +42,12 @@ public sealed class BSLinksetCompound : BSLinkset
42 } 42 }
43 43
44 // For compound implimented linksets, if there are children, use compound shape for the root. 44 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 46 {
47 ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; 47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 48 if (IsRoot(requestor) && HasAnyChildren)
49 { 49 {
50 ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; 50 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
51 } 51 }
52 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); 52 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
53 return ret; 53 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..663b6f4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,191 @@
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 System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53 // Names must be in the order of the above enum.
54 public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
55 "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
56 public static string[] MaterialAttribs = { "Density", "Friction", "Restitution",
57 "ccdMotionThreshold", "ccdSweptSphereRadius" };
58
59 public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 ccdMotionThreshold = ccdM;
66 ccdSweptSphereRadius = ccdS;
67 }
68 public string type;
69 public float density;
70 public float friction;
71 public float restitution;
72 public float ccdMotionThreshold;
73 public float ccdSweptSphereRadius;
74}
75
76public static class BSMaterials
77{
78 public static MaterialAttributes[] Attributes;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84 }
85
86 // This is where all the default material attributes are defined.
87 public static void InitializeFromDefaults(ConfigurationParameters parms)
88 {
89 // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
90 // "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
91 float dFriction = parms.defaultFriction;
92 float dRestitution = parms.defaultRestitution;
93 float dDensity = parms.defaultDensity;
94 float dCcdM = parms.ccdMotionThreshold;
95 float dCcdS = parms.ccdSweptSphereRadius;
96 Attributes[(int)MaterialAttributes.Material.Stone] =
97 new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
98 Attributes[(int)MaterialAttributes.Material.Metal] =
99 new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
100 Attributes[(int)MaterialAttributes.Material.Glass] =
101 new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
102 Attributes[(int)MaterialAttributes.Material.Wood] =
103 new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
104 Attributes[(int)MaterialAttributes.Material.Flesh] =
105 new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
106 Attributes[(int)MaterialAttributes.Material.Plastic] =
107 new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
108 Attributes[(int)MaterialAttributes.Material.Rubber] =
109 new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
110 Attributes[(int)MaterialAttributes.Material.Light] =
111 new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
112 Attributes[(int)MaterialAttributes.Material.Avatar] =
113 new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
114
115 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
116 new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
117 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
118 new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
119 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
120 new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
121 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
122 new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
123 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
124 new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
125 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
126 new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
127 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
128 new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
129 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
130 new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
131 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
132 new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
133 }
134
135 // Under the [BulletSim] section, one can change the individual material
136 // attribute values. The format of the configuration parameter is:
137 // <materialName><Attribute>["Physical"] = floatValue
138 // For instance:
139 // [BulletSim]
140 // StoneFriction = 0.2
141 // FleshRestitutionPhysical = 0.8
142 // Materials can have different parameters for their static and
143 // physical instantiations. When setting the non-physical value,
144 // both values are changed. Setting the physical value only changes
145 // the physical value.
146 public static void InitializefromParameters(IConfig pConfig)
147 {
148 int matType = 0;
149 foreach (string matName in MaterialAttributes.MaterialNames)
150 {
151 foreach (string attribName in MaterialAttributes.MaterialAttribs)
152 {
153 string paramName = matName + attribName;
154 if (pConfig.Contains(paramName))
155 {
156 float paramValue = pConfig.GetFloat(paramName);
157 SetAttributeValue(matType, attribName, paramValue);
158 // set the physical value also
159 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
160 }
161 paramName += "Physical";
162 if (pConfig.Contains(paramName))
163 {
164 float paramValue = pConfig.GetFloat(paramName);
165 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
166 }
167 }
168 matType++;
169 }
170 }
171
172 private static void SetAttributeValue(int matType, string attribName, float val)
173 {
174 MaterialAttributes thisAttrib = Attributes[matType];
175 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
176 if (fieldInfo != null)
177 {
178 fieldInfo.SetValue(thisAttrib, val);
179 Attributes[matType] = thisAttrib;
180 }
181 }
182
183 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
184 {
185 int ind = (int)type;
186 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
187 return Attributes[ind];
188 }
189
190}
191}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..e91bfa8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,169 @@
1using System; 1using System;
2using System.Collections.Generic; 2using System.Collections.Generic;
3using System.Text; 3using System.Text;
4using OpenMetaverse; 4using OpenMetaverse;
5 5
6namespace OpenSim.Region.Physics.BulletSPlugin 6namespace OpenSim.Region.Physics.BulletSPlugin
7{ 7{
8public abstract class BSMotor 8public abstract class BSMotor
9{ 9{
10 public virtual void Reset() { } 10 // Timescales and other things can be turned off by setting them to 'infinite'.
11 public virtual void Zero() { } 11 public const float Infinite = 10000f;
12} 12 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
13// Can all the incremental stepping be replaced with motor classes? 13
14public class BSVMotor : BSMotor 14 public BSMotor(string useName)
15{ 15 {
16 public Vector3 FrameOfReference { get; set; } 16 UseName = useName;
17 public Vector3 Offset { get; set; } 17 PhysicsScene = null;
18 18 }
19 public float TimeScale { get; set; } 19 public virtual void Reset() { }
20 public float TargetValueDecayTimeScale { get; set; } 20 public virtual void Zero() { }
21 public Vector3 CurrentValueReductionTimescale { get; set; } 21
22 public float Efficiency { get; set; } 22 public string UseName { get; private set; }
23 23 // Used only for outputting debug information. Might not be set so check for null.
24 public Vector3 TargetValue { get; private set; } 24 public BSScene PhysicsScene { get; set; }
25 public Vector3 CurrentValue { get; private set; } 25 protected void MDetailLog(string msg, params Object[] parms)
26 26 {
27 27 if (PhysicsScene != null)
28 28 {
29 BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 29 if (PhysicsScene.VehicleLoggingEnabled)
30 { 30 {
31 TimeScale = timeScale; 31 PhysicsScene.DetailLog(msg, parms);
32 TargetValueDecayTimeScale = decayTimeScale; 32 }
33 CurrentValueReductionTimescale = frictionTimeScale; 33 }
34 Efficiency = efficiency; 34 }
35 } 35}
36 public void SetCurrent(Vector3 current) 36// Can all the incremental stepping be replaced with motor classes?
37 { 37public class BSVMotor : BSMotor
38 CurrentValue = current; 38{
39 } 39 public Vector3 FrameOfReference { get; set; }
40 public void SetTarget(Vector3 target) 40 public Vector3 Offset { get; set; }
41 { 41
42 TargetValue = target; 42 public float TimeScale { get; set; }
43 } 43 public float TargetValueDecayTimeScale { get; set; }
44 public Vector3 Step(float timeStep) 44 public Vector3 FrictionTimescale { get; set; }
45 { 45 public float Efficiency { get; set; }
46 if (CurrentValue.LengthSquared() > 0.001f) 46
47 { 47 public Vector3 TargetValue { get; private set; }
48 // Vector3 origDir = Target; // DEBUG 48 public Vector3 CurrentValue { get; private set; }
49 // Vector3 origVel = CurrentValue; // DEBUG 49
50 50 public BSVMotor(string useName)
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete 51 : base(useName)
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; 52 {
53 CurrentValue += addAmount; 53 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
54 54 Efficiency = 1f;
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 55 FrictionTimescale = BSMotor.InfiniteVector;
56 TargetValue *= (1f - decayFactor); 56 CurrentValue = TargetValue = Vector3.Zero;
57 57 }
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; 58 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
59 CurrentValue *= (Vector3.One - frictionFactor); 59 : this(useName)
60 } 60 {
61 else 61 TimeScale = timeScale;
62 { 62 TargetValueDecayTimeScale = decayTimeScale;
63 // if what remains of direction is very small, zero it. 63 FrictionTimescale = frictionTimeScale;
64 TargetValue = Vector3.Zero; 64 Efficiency = efficiency;
65 CurrentValue = Vector3.Zero; 65 CurrentValue = TargetValue = Vector3.Zero;
66 66 }
67 // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 67 public void SetCurrent(Vector3 current)
68 } 68 {
69 return CurrentValue; 69 CurrentValue = current;
70 } 70 }
71} 71 public void SetTarget(Vector3 target)
72 72 {
73public class BSFMotor : BSMotor 73 TargetValue = target;
74{ 74 }
75 public float TimeScale { get; set; } 75 public Vector3 Step(float timeStep)
76 public float DecayTimeScale { get; set; } 76 {
77 public float Friction { get; set; } 77 Vector3 returnCurrent = Vector3.Zero;
78 public float Efficiency { get; set; } 78 if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
79 79 {
80 public float Target { get; private set; } 80 Vector3 origTarget = TargetValue; // DEBUG
81 public float CurrentValue { get; private set; } 81 Vector3 origCurrVal = CurrentValue; // DEBUG
82 82
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) 83 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
84 { 84 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
85 } 85 CurrentValue += addAmount;
86 public void SetCurrent(float target) 86
87 { 87 returnCurrent = CurrentValue;
88 } 88
89 public void SetTarget(float target) 89 // The desired value reduces to zero which also reduces the difference with current.
90 { 90 // If the decay time is infinite, don't decay at all.
91 } 91 float decayFactor = 0f;
92 public float Step(float timeStep) 92 if (TargetValueDecayTimeScale != BSMotor.Infinite)
93 { 93 {
94 return 0f; 94 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
95 } 95 TargetValue *= (1f - decayFactor);
96} 96 }
97public class BSPIDMotor : BSMotor 97
98{ 98 Vector3 frictionFactor = Vector3.Zero;
99 // TODO: write and use this one 99 if (FrictionTimescale != BSMotor.InfiniteVector)
100 BSPIDMotor() 100 {
101 { 101 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
102 } 102 frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
103} 103 frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
104} 104 frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
105 CurrentValue *= (Vector3.One - frictionFactor);
106 }
107
108 MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
109 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
110 timeStep, TimeScale, addAmount,
111 TargetValueDecayTimeScale, decayFactor,
112 FrictionTimescale, frictionFactor);
113 MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
114 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
115 addAmount, decayFactor, frictionFactor, returnCurrent);
116 }
117 else
118 {
119 // Difference between what we have and target is small. Motor is done.
120 CurrentValue = Vector3.Zero;
121 TargetValue = Vector3.Zero;
122
123 MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
124 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
125
126 }
127 return returnCurrent;
128 }
129 public override string ToString()
130 {
131 return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
132 UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
133 }
134}
135
136public class BSFMotor : BSMotor
137{
138 public float TimeScale { get; set; }
139 public float DecayTimeScale { get; set; }
140 public float Friction { get; set; }
141 public float Efficiency { get; set; }
142
143 public float Target { get; private set; }
144 public float CurrentValue { get; private set; }
145
146 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
147 : base(useName)
148 {
149 }
150 public void SetCurrent(float target)
151 {
152 }
153 public void SetTarget(float target)
154 {
155 }
156 public float Step(float timeStep)
157 {
158 return 0f;
159 }
160}
161public class BSPIDMotor : BSMotor
162{
163 // TODO: write and use this one
164 public BSPIDMotor(string useName)
165 : base(useName)
166 {
167 }
168}
169}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index e803072..f6a890e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -47,7 +47,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
47 */ 47 */
48public abstract class BSPhysObject : PhysicsActor 48public abstract class BSPhysObject : PhysicsActor
49{ 49{
50 protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName) 50 protected BSPhysObject()
51 {
52 }
53 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
51 { 54 {
52 PhysicsScene = parentScene; 55 PhysicsScene = parentScene;
53 LocalID = localID; 56 LocalID = localID;
@@ -91,9 +94,9 @@ public abstract class BSPhysObject : PhysicsActor
91 public PrimitiveBaseShape BaseShape { get; protected set; } 94 public PrimitiveBaseShape BaseShape { get; protected set; }
92 // Some types of objects have preferred physical representations. 95 // Some types of objects have preferred physical representations.
93 // Returns SHAPE_UNKNOWN if there is no preference. 96 // Returns SHAPE_UNKNOWN if there is no preference.
94 public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape 97 public virtual BSPhysicsShapeType PreferredPhysicalShape
95 { 98 {
96 get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; } 99 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
97 } 100 }
98 101
99 // When the physical properties are updated, an EntityProperty holds the update values. 102 // When the physical properties are updated, an EntityProperty holds the update values.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 14eb505..c62c79a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -47,7 +47,6 @@ public sealed class BSPrim : BSPhysObject
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. 48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50 // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
51 50
52 private bool _grabbed; 51 private bool _grabbed;
53 private bool _isSelected; 52 private bool _isSelected;
@@ -88,13 +87,13 @@ public sealed class BSPrim : BSPhysObject
88 87
89 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
90 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
90 : base(parent_scene, localID, primName, "BSPrim")
91 { 91 {
92 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 92 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
93 base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
94 _physicsActorType = (int)ActorTypes.Prim; 93 _physicsActorType = (int)ActorTypes.Prim;
95 _position = pos; 94 _position = pos;
96 _size = size; 95 _size = size;
97 Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 96 Scale = size; // the scale will be set by CreateGeom depending on object type
98 _orientation = rotation; 97 _orientation = rotation;
99 _buoyancy = 1f; 98 _buoyancy = 1f;
100 _velocity = OMV.Vector3.Zero; 99 _velocity = OMV.Vector3.Zero;
@@ -155,6 +154,8 @@ public sealed class BSPrim : BSPhysObject
155 public override OMV.Vector3 Size { 154 public override OMV.Vector3 Size {
156 get { return _size; } 155 get { return _size; }
157 set { 156 set {
157 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built.
158 _size = value; 159 _size = value;
159 ForceBodyShapeRebuild(false); 160 ForceBodyShapeRebuild(false);
160 } 161 }
@@ -170,7 +171,7 @@ public sealed class BSPrim : BSPhysObject
170 } 171 }
171 } 172 }
172 // Whatever the linkset wants is what I want. 173 // Whatever the linkset wants is what I want.
173 public override ShapeData.PhysicsShapeType PreferredPhysicalShape 174 public override BSPhysicsShapeType PreferredPhysicalShape
174 { get { return Linkset.PreferredPhysicalShape(this); } } 175 { get { return Linkset.PreferredPhysicalShape(this); } }
175 176
176 public override bool ForceBodyShapeRebuild(bool inTaintTime) 177 public override bool ForceBodyShapeRebuild(bool inTaintTime)
@@ -274,19 +275,19 @@ public sealed class BSPrim : BSPhysObject
274 if (!Linkset.IsRoot(this)) 275 if (!Linkset.IsRoot(this))
275 _position = Linkset.Position(this); 276 _position = Linkset.Position(this);
276 277
277 // don't do the GetObjectPosition for root elements because this function is called a zillion times 278 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
278 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 279 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
279 return _position; 280 return _position;
280 } 281 }
281 set { 282 set {
282 // If you must push the position into the physics engine, use ForcePosition. 283 // If the position must be forced into the physics engine, use ForcePosition.
283 if (_position == value) 284 if (_position == value)
284 { 285 {
285 return; 286 return;
286 } 287 }
287 _position = value; 288 _position = value;
288 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
289 PositionSanityCheck(); 290 PositionSanityCheck(false);
290 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
291 { 292 {
292 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
@@ -302,7 +303,7 @@ public sealed class BSPrim : BSPhysObject
302 } 303 }
303 set { 304 set {
304 _position = value; 305 _position = value;
305 PositionSanityCheck(); 306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better.
306 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
307 ActivateIfPhysical(false); 308 ActivateIfPhysical(false);
308 } 309 }
@@ -311,52 +312,42 @@ public sealed class BSPrim : BSPhysObject
311 // Check that the current position is sane and, if not, modify the position to make it so. 312 // Check that the current position is sane and, if not, modify the position to make it so.
312 // Check for being below terrain and being out of bounds. 313 // Check for being below terrain and being out of bounds.
313 // Returns 'true' of the position was made sane by some action. 314 // Returns 'true' of the position was made sane by some action.
314 private bool PositionSanityCheck() 315 private bool PositionSanityCheck(bool inTaintTime)
315 { 316 {
316 bool ret = false; 317 bool ret = false;
317 318
318 // If totally below the ground, move the prim up
319 // TODO: figure out the right solution for this... only for dynamic objects?
320 /*
321 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
320 OMV.Vector3 upForce = OMV.Vector3.Zero;
322 if (Position.Z < terrainHeight) 321 if (Position.Z < terrainHeight)
323 { 322 {
324 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
325 _position.Z = terrainHeight + 2.0f; 324 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
326 upForce.Z = (terrainHeight - Position.Z) * 1f;
326 ret = true; 327 ret = true;
327 } 328 }
328 */ 329
329 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
330 { 331 {
331 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
332 // TODO: a floating motor so object will bob in the water 333 // TODO: a floating motor so object will bob in the water
333 if (Position.Z < waterHeight) 334 if (Math.Abs(Position.Z - waterHeight) > 0.1f)
334 { 335 {
335 _position.Z = waterHeight; 336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f;
336 ret = true; 338 ret = true;
337 } 339 }
338 } 340 }
339 341
340 // TODO: check for out of bounds 342 // TODO: check for out of bounds
341 return ret;
342 }
343 343
344 // A version of the sanity check that also makes sure a new position value is 344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
345 // pushed to the physics engine. This routine would be used by anyone 345 // TODO: This should be intergrated with a geneal physics action mechanism.
346 // who is not already pushing the value. 346 // TODO: This should be moderated with PID'ness.
347 private bool PositionSanityCheck(bool inTaintTime) 347 if (ret)
348 {
349 bool ret = false;
350 if (PositionSanityCheck())
351 { 348 {
352 // The new position value must be pushed into the physics engine but we can't 349 // Apply upforce and overcome gravity.
353 // just assign to "Position" because of potential call loops. 350 AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
354 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate()
355 {
356 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
357 ForcePosition = _position;
358 });
359 ret = true;
360 } 351 }
361 return ret; 352 return ret;
362 } 353 }
@@ -940,6 +931,7 @@ public sealed class BSPrim : BSPhysObject
940 public override void AddForce(OMV.Vector3 force, bool pushforce) { 931 public override void AddForce(OMV.Vector3 force, bool pushforce) {
941 AddForce(force, pushforce, false); 932 AddForce(force, pushforce, false);
942 } 933 }
934 // Applying a force just adds this to the total force on the object.
943 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 935 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
944 // for an object, doesn't matter if force is a pushforce or not 936 // for an object, doesn't matter if force is a pushforce or not
945 if (force.IsFinite()) 937 if (force.IsFinite())
@@ -971,6 +963,7 @@ public sealed class BSPrim : BSPhysObject
971 }); 963 });
972 } 964 }
973 965
966 // An impulse force is scaled by the mass of the object.
974 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) 967 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
975 { 968 {
976 OMV.Vector3 applyImpulse = impulse; 969 OMV.Vector3 applyImpulse = impulse;
@@ -1387,67 +1380,34 @@ public sealed class BSPrim : BSPhysObject
1387 1380
1388 public override void UpdateProperties(EntityProperties entprop) 1381 public override void UpdateProperties(EntityProperties entprop)
1389 { 1382 {
1390 /* 1383 // Updates only for individual prims and for the root object of a linkset.
1391 UpdatedProperties changed = 0; 1384 if (Linkset.IsRoot(this))
1392 // assign to the local variables so the normal set action does not happen
1393 // if (_position != entprop.Position)
1394 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1395 {
1396 _position = entprop.Position;
1397 changed |= UpdatedProperties.Position;
1398 }
1399 // if (_orientation != entprop.Rotation)
1400 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1401 {
1402 _orientation = entprop.Rotation;
1403 changed |= UpdatedProperties.Rotation;
1404 }
1405 // if (_velocity != entprop.Velocity)
1406 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1407 {
1408 _velocity = entprop.Velocity;
1409 changed |= UpdatedProperties.Velocity;
1410 }
1411 // if (_acceleration != entprop.Acceleration)
1412 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1413 {
1414 _acceleration = entprop.Acceleration;
1415 changed |= UpdatedProperties.Acceleration;
1416 }
1417 // if (_rotationalVelocity != entprop.RotationalVelocity)
1418 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1419 {
1420 _rotationalVelocity = entprop.RotationalVelocity;
1421 changed |= UpdatedProperties.RotationalVel;
1422 }
1423 if (changed != 0)
1424 { 1385 {
1425 // Only update the position of single objects and linkset roots 1386 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1426 if (this._parentPrim == null) 1387 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1388 if (_vehicle.IsActive)
1427 { 1389 {
1428 base.RequestPhysicsterseUpdate(); 1390 entprop.RotationalVelocity = OMV.Vector3.Zero;
1429 } 1391 }
1430 }
1431 */
1432
1433 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1434 1392
1435 // Updates only for individual prims and for the root object of a linkset. 1393 // Assign directly to the local variables so the normal set action does not happen
1436 if (Linkset.IsRoot(this))
1437 {
1438 // Assign to the local variables so the normal set action does not happen
1439 _position = entprop.Position; 1394 _position = entprop.Position;
1440 _orientation = entprop.Rotation; 1395 _orientation = entprop.Rotation;
1441 _velocity = entprop.Velocity; 1396 _velocity = entprop.Velocity;
1442 _acceleration = entprop.Acceleration; 1397 _acceleration = entprop.Acceleration;
1443 _rotationalVelocity = entprop.RotationalVelocity; 1398 _rotationalVelocity = entprop.RotationalVelocity;
1444 1399
1400 // The sanity check can change the velocity and/or position.
1401 if (PositionSanityCheck(true))
1402 {
1403 entprop.Position = _position;
1404 entprop.Velocity = _velocity;
1405 }
1406
1445 // remember the current and last set values 1407 // remember the current and last set values
1446 LastEntityProperties = CurrentEntityProperties; 1408 LastEntityProperties = CurrentEntityProperties;
1447 CurrentEntityProperties = entprop; 1409 CurrentEntityProperties = entprop;
1448 1410
1449 PositionSanityCheck(true);
1450
1451 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; 1411 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1452 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1412 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1453 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); 1413 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 1cc607a..09b1423 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,23 +39,10 @@ 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// Test sculpties (verified that they don't work)
43// Compute physics FPS reasonably
44// Based on material, set density and friction 42// Based on material, set density and friction
45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
48// At the moment, physical and phantom causes object to drop through the terrain
49// Physical phantom objects and related typing (collision options )
50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim 43// More efficient memory usage when passing hull information from BSPrim to BulletSim
53// Should prim.link() and prim.delink() membership checking happen at taint time?
54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 44// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
56// Implement LockAngularMotion 45// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
59// Add PID movement operations. What does ScenePresence.MoveToTarget do? 46// Add PID movement operations. What does ScenePresence.MoveToTarget do?
60// Check terrain size. 128 or 127? 47// Check terrain size. 128 or 127?
61// Raycast 48// Raycast
@@ -234,6 +221,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 221 if (m_physicsLoggingEnabled)
235 { 222 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 223 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
224 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 225 }
238 else 226 else
239 { 227 {
@@ -308,6 +296,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
308 // Do any replacements in the parameters 296 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 297 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 298 }
299
300 // The material characteristics.
301 BSMaterials.InitializeFromDefaults(Params);
302 if (pConfig != null)
303 {
304 BSMaterials.InitializefromParameters(pConfig);
305 }
311 } 306 }
312 } 307 }
313 308
@@ -520,9 +515,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 515 collidersCount = 0;
521 } 516 }
522 517
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 518 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
524 519
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 520 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 521 SimulationNowTime = Util.EnvironmentTickCount();
527 522
528 // If there were collisions, process them by sending the event to the prim. 523 // If there were collisions, process them by sending the event to the prim.
@@ -568,6 +563,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
568 ObjectsWithCollisions.Remove(po); 563 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 564 ObjectsWithNoMoreCollisions.Clear();
570 } 565 }
566 // Done with collisions.
571 567
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 568 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 569 if (updatedEntityCount > 0)
@@ -591,9 +587,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
591 587
592 // The physics engine returns the number of milliseconds it simulated this call. 588 // The physics engine returns the number of milliseconds it simulated this call.
593 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 589 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
594 // We multiply by 55 to give a recognizable running rate (55 or less). 590 // Multiply by 55 to give a nominal frame rate of 55.
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 591 return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
596 // return timeStep * 1000 * 55;
597 } 592 }
598 593
599 // Something has collided 594 // Something has collided
@@ -683,7 +678,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
683 #region Taints 678 #region Taints
684 679
685 // Calls to the PhysicsActors can't directly call into the physics engine 680 // Calls to the PhysicsActors can't directly call into the physics engine
686 // because it might be busy. We delay changes to a known time. 681 // because it might be busy. We delay changes to a known time.
687 // We rely on C#'s closure to save and restore the context for the delegate. 682 // We rely on C#'s closure to save and restore the context for the delegate.
688 public void TaintedObject(String ident, TaintCallback callback) 683 public void TaintedObject(String ident, TaintCallback callback)
689 { 684 {
@@ -712,7 +707,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
712 // here just before the physics engine is called to step the simulation. 707 // here just before the physics engine is called to step the simulation.
713 public void ProcessTaints() 708 public void ProcessTaints()
714 { 709 {
715 InTaintTime = true; 710 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints(); 711 ProcessRegularTaints();
717 ProcessPostTaintTaints(); 712 ProcessPostTaintTaints();
718 InTaintTime = false; 713 InTaintTime = false;
@@ -758,6 +753,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
758 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); 753 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
759 } 754 }
760 */ 755 */
756
761 // swizzle a new list into the list location so we can process what's there 757 // swizzle a new list into the list location so we can process what's there
762 List<TaintCallbackEntry> oldList; 758 List<TaintCallbackEntry> oldList;
763 lock (_taintLock) 759 lock (_taintLock)
@@ -787,8 +783,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
787 // will replace any previous operation by the same object. 783 // will replace any previous operation by the same object.
788 public void PostTaintObject(String ident, uint ID, TaintCallback callback) 784 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
789 { 785 {
790 if (!m_initialized) return;
791
792 string uniqueIdent = ident + "-" + ID.ToString(); 786 string uniqueIdent = ident + "-" + ID.ToString();
793 lock (_taintLock) 787 lock (_taintLock)
794 { 788 {
@@ -864,13 +858,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
864 } 858 }
865 } 859 }
866 860
861 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom) 862 public bool AssertInTaintTime(string whereFrom)
868 { 863 {
869 if (!InTaintTime) 864 if (!InTaintTime)
870 { 865 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); 866 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
872 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); 867 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
873 Util.PrintCallStack(); 868 Util.PrintCallStack(); // Prints the stack into the DEBUG log file.
874 } 869 }
875 return InTaintTime; 870 return InTaintTime;
876 } 871 }
@@ -1069,7 +1064,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1069 (s,p,l,v) => { s.PID_P = v; } ), 1064 (s,p,l,v) => { s.PID_P = v; } ),
1070 1065
1071 new ParameterDefn("DefaultFriction", "Friction factor used on new objects", 1066 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
1072 0.5f, 1067 0.2f,
1073 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, 1068 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
1074 (s) => { return s.m_params[0].defaultFriction; }, 1069 (s) => { return s.m_params[0].defaultFriction; },
1075 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), 1070 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
@@ -1084,7 +1079,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1084 (s) => { return s.m_params[0].defaultRestitution; }, 1079 (s) => { return s.m_params[0].defaultRestitution; },
1085 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), 1080 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
1086 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", 1081 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
1087 0f, 1082 0.04f,
1088 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, 1083 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
1089 (s) => { return s.m_params[0].collisionMargin; }, 1084 (s) => { return s.m_params[0].collisionMargin; },
1090 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), 1085 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
@@ -1145,8 +1140,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1145 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, 1140 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1146 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), 1141 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
1147 1142
1143 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
1144 (float)BSTerrainPhys.TerrainImplementation.Mesh,
1145 (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
1146 (s) => { return s.m_params[0].terrainImplementation; },
1147 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1148 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1148 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1149 0.5f, 1149 0.3f,
1150 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1150 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1151 (s) => { return s.m_params[0].terrainFriction; }, 1151 (s) => { return s.m_params[0].terrainFriction; },
1152 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), 1152 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
@@ -1160,13 +1160,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1160 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1160 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1161 (s) => { return s.m_params[0].terrainRestitution; }, 1161 (s) => { return s.m_params[0].terrainRestitution; },
1162 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), 1162 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1163 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
1164 0.04f,
1165 (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainCollisionMargin; },
1167 (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
1168
1163 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1169 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1164 0.2f, 1170 0.2f,
1165 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1171 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].avatarFriction; }, 1172 (s) => { return s.m_params[0].avatarFriction; },
1167 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1173 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1168 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 1174 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1169 10f, 1175 10.0f,
1170 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, 1176 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1171 (s) => { return s.m_params[0].avatarStandingFriction; }, 1177 (s) => { return s.m_params[0].avatarStandingFriction; },
1172 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), 1178 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@@ -1180,11 +1186,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1180 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 1186 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1181 (s) => { return s.m_params[0].avatarRestitution; }, 1187 (s) => { return s.m_params[0].avatarRestitution; },
1182 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), 1188 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1183 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", 1189 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
1184 0.37f, 1190 0.6f,
1185 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 1191 (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
1186 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 1192 (s) => { return s.m_params[0].avatarCapsuleWidth; },
1187 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 1193 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
1194 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
1195 0.45f,
1196 (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
1197 (s) => { return s.m_params[0].avatarCapsuleDepth; },
1198 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
1188 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 1199 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1189 1.5f, 1200 1.5f,
1190 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1201 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
@@ -1196,6 +1207,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1196 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1207 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1197 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1208 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1198 1209
1210 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
1211 0.95f,
1212 (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
1213 (s) => { return s.m_params[0].vehicleAngularDamping; },
1214 (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
1199 1215
1200 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1216 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1201 0f, 1217 0f,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 29a23c0..892c34b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -178,7 +178,7 @@ public sealed class BSShapeCollection : IDisposable
178 bool ret = false; 178 bool ret = false;
179 switch (shape.type) 179 switch (shape.type)
180 { 180 {
181 case ShapeData.PhysicsShapeType.SHAPE_MESH: 181 case BSPhysicsShapeType.SHAPE_MESH:
182 MeshDesc meshDesc; 182 MeshDesc meshDesc;
183 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) 183 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
184 { 184 {
@@ -201,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable
201 meshDesc.lastReferenced = System.DateTime.Now; 201 meshDesc.lastReferenced = System.DateTime.Now;
202 Meshes[shape.shapeKey] = meshDesc; 202 Meshes[shape.shapeKey] = meshDesc;
203 break; 203 break;
204 case ShapeData.PhysicsShapeType.SHAPE_HULL: 204 case BSPhysicsShapeType.SHAPE_HULL:
205 HullDesc hullDesc; 205 HullDesc hullDesc;
206 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) 206 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
207 { 207 {
@@ -224,7 +224,7 @@ public sealed class BSShapeCollection : IDisposable
224 hullDesc.lastReferenced = System.DateTime.Now; 224 hullDesc.lastReferenced = System.DateTime.Now;
225 Hulls[shape.shapeKey] = hullDesc; 225 Hulls[shape.shapeKey] = hullDesc;
226 break; 226 break;
227 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 227 case BSPhysicsShapeType.SHAPE_UNKNOWN:
228 break; 228 break;
229 default: 229 default:
230 // Native shapes are not tracked and they don't go into any list 230 // Native shapes are not tracked and they don't go into any list
@@ -255,16 +255,16 @@ public sealed class BSShapeCollection : IDisposable
255 { 255 {
256 switch (shape.type) 256 switch (shape.type)
257 { 257 {
258 case ShapeData.PhysicsShapeType.SHAPE_HULL: 258 case BSPhysicsShapeType.SHAPE_HULL:
259 DereferenceHull(shape, shapeCallback); 259 DereferenceHull(shape, shapeCallback);
260 break; 260 break;
261 case ShapeData.PhysicsShapeType.SHAPE_MESH: 261 case BSPhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback); 262 DereferenceMesh(shape, shapeCallback);
263 break; 263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_COMPOUND: 264 case BSPhysicsShapeType.SHAPE_COMPOUND:
265 DereferenceCompound(shape, shapeCallback); 265 DereferenceCompound(shape, shapeCallback);
266 break; 266 break;
267 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 267 case BSPhysicsShapeType.SHAPE_UNKNOWN:
268 break; 268 break;
269 default: 269 default:
270 break; 270 break;
@@ -352,28 +352,28 @@ public sealed class BSShapeCollection : IDisposable
352 BulletShape shapeInfo = new BulletShape(cShape); 352 BulletShape shapeInfo = new BulletShape(cShape);
353 if (TryGetMeshByPtr(cShape, out meshDesc)) 353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 354 {
355 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_MESH; 355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 356 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 357 }
358 else 358 else
359 { 359 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 360 if (TryGetHullByPtr(cShape, out hullDesc))
361 { 361 {
362 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL; 362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 363 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 364 }
365 else 365 else
366 { 366 {
367 if (BulletSimAPI.IsCompound2(cShape)) 367 if (BulletSimAPI.IsCompound2(cShape))
368 { 368 {
369 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; 369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 370 }
371 else 371 else
372 { 372 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 373 if (BulletSimAPI.IsNativeShape2(cShape))
374 { 374 {
375 shapeInfo.isNativeShape = true; 375 shapeInfo.isNativeShape = true;
376 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
377 } 377 }
378 } 378 }
379 } 379 }
@@ -381,7 +381,7 @@ public sealed class BSShapeCollection : IDisposable
381 381
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 383
384 if (shapeInfo.type != ShapeData.PhysicsShapeType.SHAPE_UNKNOWN) 384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 385 {
386 DereferenceShape(shapeInfo, true, null); 386 DereferenceShape(shapeInfo, true, null);
387 } 387 }
@@ -405,11 +405,11 @@ public sealed class BSShapeCollection : IDisposable
405 bool ret = false; 405 bool ret = false;
406 bool haveShape = false; 406 bool haveShape = false;
407 407
408 if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 409 {
410 // an avatar capsule is close to a native shape (it is not shared) 410 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
412 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); 412 FixedShapeKey.KEY_CAPSULE, shapeCallback);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 414 ret = true;
415 haveShape = true; 415 haveShape = true;
@@ -417,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable
417 417
418 // Compound shapes are handled special as they are rebuilt from scratch. 418 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created. 419 // This isn't too great a hardship since most of the child shapes will already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND) 420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 421 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 422 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
@@ -460,11 +460,11 @@ public sealed class BSShapeCollection : IDisposable
460 haveShape = true; 460 haveShape = true;
461 if (forceRebuild 461 if (forceRebuild
462 || prim.Scale != prim.Size 462 || prim.Scale != prim.Size
463 || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE 463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 464 )
465 { 465 {
466 ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE, 466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); 467 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape); 469 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 470 }
@@ -474,11 +474,11 @@ public sealed class BSShapeCollection : IDisposable
474 haveShape = true; 474 haveShape = true;
475 if (forceRebuild 475 if (forceRebuild
476 || prim.Scale != prim.Size 476 || prim.Scale != prim.Size
477 || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX 477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 478 )
479 { 479 {
480 ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX, 480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); 481 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape); 483 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 484 }
@@ -519,15 +519,12 @@ public sealed class BSShapeCollection : IDisposable
519 // Creates a native shape and assignes it to prim.BSShape. 519 // Creates a native shape and assignes it to prim.BSShape.
520 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). 520 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
521 private bool GetReferenceToNativeShape(BSPhysObject prim, 521 private bool GetReferenceToNativeShape(BSPhysObject prim,
522 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 522 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
523 ShapeDestructionCallback shapeCallback) 523 ShapeDestructionCallback shapeCallback)
524 { 524 {
525 // release any previous shape 525 // release any previous shape
526 DereferenceShape(prim.PhysShape, true, shapeCallback); 526 DereferenceShape(prim.PhysShape, true, shapeCallback);
527 527
528 // Bullet native objects are scaled by the Bullet engine so pass the size in
529 prim.Scale = prim.Size;
530
531 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
532 529
533 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
@@ -538,8 +535,8 @@ public sealed class BSShapeCollection : IDisposable
538 return true; 535 return true;
539 } 536 }
540 537
541 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType, 538 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
542 ShapeData.FixedShapeKey shapeKey) 539 FixedShapeKey shapeKey)
543 { 540 {
544 BulletShape newShape; 541 BulletShape newShape;
545 // Need to make sure the passed shape information is for the native type. 542 // Need to make sure the passed shape information is for the native type.
@@ -547,12 +544,13 @@ public sealed class BSShapeCollection : IDisposable
547 nativeShapeData.Type = shapeType; 544 nativeShapeData.Type = shapeType;
548 nativeShapeData.ID = prim.LocalID; 545 nativeShapeData.ID = prim.LocalID;
549 nativeShapeData.Scale = prim.Scale; 546 nativeShapeData.Scale = prim.Scale;
550 nativeShapeData.Size = prim.Scale; 547 nativeShapeData.Size = prim.Scale; // unneeded, I think.
551 nativeShapeData.MeshKey = (ulong)shapeKey; 548 nativeShapeData.MeshKey = (ulong)shapeKey;
552 nativeShapeData.HullKey = (ulong)shapeKey; 549 nativeShapeData.HullKey = (ulong)shapeKey;
553 550
554 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
555 { 552 {
553 // The proper scale has been calculated in the prim.
556 newShape = new BulletShape( 554 newShape = new BulletShape(
557 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
558 , shapeType); 556 , shapeType);
@@ -560,6 +558,9 @@ public sealed class BSShapeCollection : IDisposable
560 } 558 }
561 else 559 else
562 { 560 {
561 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size;
563 nativeShapeData.Scale = prim.Scale;
563 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); 564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
564 } 565 }
565 if (newShape.ptr == IntPtr.Zero) 566 if (newShape.ptr == IntPtr.Zero)
@@ -585,7 +586,7 @@ public sealed class BSShapeCollection : IDisposable
585 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
586 587
587 // if this new shape is the same as last time, don't recreate the mesh 588 // if this new shape is the same as last time, don't recreate the mesh
588 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) 589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
589 return false; 590 return false;
590 591
591 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
@@ -643,7 +644,7 @@ public sealed class BSShapeCollection : IDisposable
643 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
644 } 645 }
645 } 646 }
646 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
647 newShape.shapeKey = newMeshKey; 648 newShape.shapeKey = newMeshKey;
648 649
649 return newShape; 650 return newShape;
@@ -659,7 +660,7 @@ public sealed class BSShapeCollection : IDisposable
659 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 660 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
660 661
661 // if the hull hasn't changed, don't rebuild it 662 // if the hull hasn't changed, don't rebuild it
662 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) 663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
663 return false; 664 return false;
664 665
665 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
@@ -780,7 +781,7 @@ public sealed class BSShapeCollection : IDisposable
780 } 781 }
781 } 782 }
782 783
783 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
784 newShape.shapeKey = newHullKey; 785 newShape.shapeKey = newHullKey;
785 786
786 return newShape; // 'true' means a new shape has been added to this prim 787 return newShape; // 'true' means a new shape has been added to this prim
@@ -803,7 +804,7 @@ public sealed class BSShapeCollection : IDisposable
803 // DereferenceShape(prim.PhysShape, true, shapeCallback); 804 // DereferenceShape(prim.PhysShape, true, shapeCallback);
804 805
805 BulletShape cShape = new BulletShape( 806 BulletShape cShape = new BulletShape(
806 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND); 807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
807 808
808 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
809 CreateGeomMeshOrHull(prim, shapeCallback); 810 CreateGeomMeshOrHull(prim, shapeCallback);
@@ -894,7 +895,7 @@ public sealed class BSShapeCollection : IDisposable
894 895
895 // While we figure out the real problem, stick a simple native shape on the object. 896 // While we figure out the real problem, stick a simple native shape on the object.
896 BulletShape fillinShape = 897 BulletShape fillinShape =
897 BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX); 898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
898 899
899 return fillinShape; 900 return fillinShape;
900 } 901 }
@@ -940,7 +941,7 @@ public sealed class BSShapeCollection : IDisposable
940 else 941 else
941 { 942 {
942 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
943 prim.LocalID, prim.ForcePosition, prim.ForceOrientation); 944 prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
945 } 946 }
946 aBody = new BulletBody(prim.LocalID, bodyPtr); 947 aBody = new BulletBody(prim.LocalID, bodyPtr);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index 5e2c4a8..96cd55e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -1,213 +1,208 @@
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 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq; 30using System.Linq;
31using System.Text; 31using System.Text;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public abstract class BSShape 35public abstract class BSShape
36{ 36{
37 public IntPtr ptr { get; set; } 37 public IntPtr ptr { get; set; }
38 public ShapeData.PhysicsShapeType type { get; set; } 38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; } 39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; } 40 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; } 41 public DateTime lastReferenced { get; set; }
42 42
43 protected void Initialize() 43 public BSShape()
44 { 44 {
45 ptr = IntPtr.Zero; 45 ptr = IntPtr.Zero;
46 type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; 46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0; 47 key = 0;
48 referenceCount = 0; 48 referenceCount = 0;
49 lastReferenced = DateTime.Now; 49 lastReferenced = DateTime.Now;
50 } 50 }
51 51
52 // Get a reference to a physical shape. Create if it doesn't exist 52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 { 54 {
55 BSShape ret = null; 55 BSShape ret = null;
56 56
57 if (prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
58 { 58 {
59 // an avatar capsule is close to a native shape (it is not shared) 59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 ShapeData.FixedShapeKey.KEY_CAPSULE); 61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); 62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 } 63 }
64 64
65 // Compound shapes are handled special as they are rebuilt from scratch. 65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created. 66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND) 67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 { 68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added 69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim); 70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); 71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 } 72 }
73 73
74 if (ret == null) 74 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76 76
77 return ret; 77 return ret;
78 } 78 }
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
80 { 80 {
81 return null; 81 return null;
82 } 82 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
84 { 84 {
85 return null; 85 return null;
86 } 86 }
87 87
88 // Release the use of a physical shape. 88 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene); 89 public abstract void Dereference(BSScene physicsScene);
90 90
91 // All shapes have a static call to get a reference to the physical shape 91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference(); 92 // protected abstract static BSShape GetReference();
93 93
94 public override string ToString() 94 public override string ToString()
95 { 95 {
96 StringBuilder buff = new StringBuilder(); 96 StringBuilder buff = new StringBuilder();
97 buff.Append("<p="); 97 buff.Append("<p=");
98 buff.Append(ptr.ToString("X")); 98 buff.Append(ptr.ToString("X"));
99 buff.Append(",s="); 99 buff.Append(",s=");
100 buff.Append(type.ToString()); 100 buff.Append(type.ToString());
101 buff.Append(",k="); 101 buff.Append(",k=");
102 buff.Append(key.ToString("X")); 102 buff.Append(key.ToString("X"));
103 buff.Append(",c="); 103 buff.Append(",c=");
104 buff.Append(referenceCount.ToString()); 104 buff.Append(referenceCount.ToString());
105 buff.Append(">"); 105 buff.Append(">");
106 return buff.ToString(); 106 return buff.ToString();
107 } 107 }
108} 108}
109 109
110public class BSShapeNull : BSShape 110public class BSShapeNull : BSShape
111{ 111{
112 public BSShapeNull() 112 public BSShapeNull() : base()
113 { 113 {
114 base.Initialize(); 114 }
115 } 115 public static BSShape GetReference() { return new BSShapeNull(); }
116 public static BSShape GetReference() { return new BSShapeNull(); } 116 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
117 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 117}
118} 118
119 119public class BSShapeNative : BSShape
120public class BSShapeNative : BSShape 120{
121{ 121 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
122 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; 122 public BSShapeNative() : base()
123 public BSShapeNative() 123 {
124 { 124 }
125 base.Initialize(); 125 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
126 } 126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 127 {
128 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey) 128 // Native shapes are not shared and are always built anew.
129 { 129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
130 // Native shapes are not shared and are always built anew. 130 }
131 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 131
132 } 132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
133 133 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
134 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 134 {
135 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey) 135 ShapeData nativeShapeData = new ShapeData();
136 { 136 nativeShapeData.Type = shapeType;
137 ShapeData nativeShapeData = new ShapeData(); 137 nativeShapeData.ID = prim.LocalID;
138 nativeShapeData.Type = shapeType; 138 nativeShapeData.Scale = prim.Scale;
139 nativeShapeData.ID = prim.LocalID; 139 nativeShapeData.Size = prim.Scale;
140 nativeShapeData.Scale = prim.Scale; 140 nativeShapeData.MeshKey = (ulong)shapeKey;
141 nativeShapeData.Size = prim.Scale; 141 nativeShapeData.HullKey = (ulong)shapeKey;
142 nativeShapeData.MeshKey = (ulong)shapeKey; 142
143 nativeShapeData.HullKey = (ulong)shapeKey; 143
144 144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 145 {
146 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
147 { 147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); 148 }
149 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 149 else
150 } 150 {
151 else 151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
152 { 152 }
153 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); 153 if (ptr == IntPtr.Zero)
154 } 154 {
155 if (ptr == IntPtr.Zero) 155 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
156 { 156 LogHeader, prim.LocalID, shapeType);
157 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 157 }
158 LogHeader, prim.LocalID, shapeType); 158 type = shapeType;
159 } 159 key = (UInt64)shapeKey;
160 type = shapeType; 160 }
161 key = (UInt64)shapeKey; 161 // Make this reference to the physical shape go away since native shapes are not shared.
162 } 162 public override void Dereference(BSScene physicsScene)
163 // Make this reference to the physical shape go away since native shapes are not shared. 163 {
164 public override void Dereference(BSScene physicsScene) 164 // Native shapes are not tracked and are released immediately
165 { 165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 // Native shapes are not tracked and are released immediately 166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
167 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); 167 ptr = IntPtr.Zero;
168 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); 168 // Garbage collection will free up this instance.
169 ptr = IntPtr.Zero; 169 }
170 // Garbage collection will free up this instance. 170}
171 } 171
172} 172public class BSShapeMesh : BSShape
173 173{
174public class BSShapeMesh : BSShape 174 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
175{ 175 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
176 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 176
177 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 177 public BSShapeMesh() : base()
178 178 {
179 public BSShapeMesh() 179 }
180 { 180 public static BSShape GetReference() { return new BSShapeNull(); }
181 base.Initialize(); 181 public override void Dereference(BSScene physicsScene) { }
182 } 182}
183 public static BSShape GetReference() { return new BSShapeNull(); } 183
184 public override void Dereference(BSScene physicsScene) { } 184public class BSShapeHull : BSShape
185} 185{
186 186 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
187public class BSShapeHull : BSShape 187 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
188{ 188
189 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 189 public BSShapeHull() : base()
190 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 190 {
191 191 }
192 public BSShapeHull() 192 public static BSShape GetReference() { return new BSShapeNull(); }
193 { 193 public override void Dereference(BSScene physicsScene) { }
194 base.Initialize(); 194}
195 } 195
196 public static BSShape GetReference() { return new BSShapeNull(); } 196public class BSShapeCompound : BSShape
197 public override void Dereference(BSScene physicsScene) { } 197{
198} 198 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
199 199 public BSShapeCompound() : base()
200public class BSShapeCompound : BSShape 200 {
201{ 201 }
202 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 202 public static BSShape GetReference(BSPhysObject prim)
203 public BSShapeCompound() 203 {
204 { 204 return new BSShapeNull();
205 base.Initialize(); 205 }
206 } 206 public override void Dereference(BSScene physicsScene) { }
207 public static BSShape GetReference(BSPhysObject prim) 207}
208 { 208}
209 return new BSShapeNull();
210 }
211 public override void Dereference(BSScene physicsScene) { }
212}
213}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
new file mode 100755
index 0000000..1450f66
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -0,0 +1,170 @@
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 sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHeightMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
97
98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
100 BSPhysicsShapeType.SHAPE_TERRAIN);
101
102 // The terrain object initial position is at the center of the object
103 Vector3 centerPos;
104 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
107
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111
112 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
117
118 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
120
121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr,
125 (uint)CollisionFilterGroups.TerrainFilter,
126 (uint)CollisionFilterGroups.TerrainMask);
127
128 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
130
131 return;
132 }
133
134 // If there is information in m_mapInfo pointing to physical structures, release same.
135 private void ReleaseHeightMapTerrain()
136 {
137 if (m_mapInfo != null)
138 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero)
140 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
142 // Frees both the body and the shape.
143 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
144 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
145 }
146 }
147 m_mapInfo = null;
148 }
149
150 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos)
152 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154
155 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
156 try
157 {
158 ret = m_mapInfo.heightMap[mapIndex];
159 }
160 catch
161 {
162 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
163 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
164 LogHeader, m_mapInfo.terrainRegionBase, pos);
165 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
166 }
167 return ret;
168 }
169}
170}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 7c34af2..cd623f1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -40,6 +40,32 @@ using OpenMetaverse;
40 40
41namespace OpenSim.Region.Physics.BulletSPlugin 41namespace OpenSim.Region.Physics.BulletSPlugin
42{ 42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 public BSScene PhysicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 PhysicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos);
66}
67
68// ==========================================================================================
43public sealed class BSTerrainManager 69public sealed class BSTerrainManager
44{ 70{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
@@ -54,8 +80,6 @@ public sealed class BSTerrainManager
54 // amount to make sure that a bounding box is built for the terrain. 80 // amount to make sure that a bounding box is built for the terrain.
55 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 81 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
56 82
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. 83 // 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); 84 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
61 85
@@ -67,11 +91,10 @@ public sealed class BSTerrainManager
67 91
68 // If doing mega-regions, if we're region zero we will be managing multiple 92 // 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. 93 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; 94 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
71 95
72 // True of the terrain has been modified. 96 // Flags used to know when to recalculate the height.
73 // Used to force recalculation of terrain height after terrain has been modified 97 private bool m_terrainModified = false;
74 private bool m_terrainModified;
75 98
76 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. 99 // 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. 100 // This is incremented before assigning to new region so it is the last ID allocated.
@@ -89,8 +112,7 @@ public sealed class BSTerrainManager
89 public BSTerrainManager(BSScene physicsScene) 112 public BSTerrainManager(BSScene physicsScene)
90 { 113 {
91 PhysicsScene = physicsScene; 114 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); 115 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
93 m_terrainModified = false;
94 116
95 // Assume one region of default size 117 // Assume one region of default size
96 m_worldOffset = Vector3.Zero; 118 m_worldOffset = Vector3.Zero;
@@ -99,17 +121,15 @@ public sealed class BSTerrainManager
99 } 121 }
100 122
101 // Create the initial instance of terrain and the underlying ground plane. 123 // 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 124 // 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. 125 // safe to call Bullet in real time. We hope no one is moving prims around yet.
107 public void CreateInitialGroundPlaneAndTerrain() 126 public void CreateInitialGroundPlaneAndTerrain()
108 { 127 {
109 // The ground plane is here to catch things that are trying to drop to negative infinity 128 // The ground plane is here to catch things that are trying to drop to negative infinity
110 BulletShape groundPlaneShape = new BulletShape( 129 BulletShape groundPlaneShape = new BulletShape(
111 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 130 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
112 ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE); 131 PhysicsScene.Params.terrainCollisionMargin),
132 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
113 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 133 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 134 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity)); 135 Vector3.Zero, Quaternion.Identity));
@@ -121,15 +141,9 @@ public sealed class BSTerrainManager
121 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 141 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
122 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 142 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
123 143
124 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); 144 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
125 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); 145 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
126 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; 146 m_terrains.Add(Vector3.Zero, initialTerrain);
127 float[] initialMap = new float[totalHeights];
128 for (int ii = 0; ii < totalHeights; ii++)
129 {
130 initialMap[ii] = HEIGHT_INITIALIZATION;
131 }
132 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
133 } 147 }
134 148
135 // Release all the terrain structures we might have allocated 149 // Release all the terrain structures we might have allocated
@@ -150,21 +164,22 @@ public sealed class BSTerrainManager
150 // Release all the terrain we have allocated 164 // Release all the terrain we have allocated
151 public void ReleaseTerrain() 165 public void ReleaseTerrain()
152 { 166 {
153 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) 167 lock (m_terrains)
154 { 168 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr)) 169 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
156 { 170 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr); 171 kvp.Value.Dispose();
158 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
159 } 172 }
173 m_terrains.Clear();
160 } 174 }
161 m_heightMaps.Clear();
162 } 175 }
163 176
164 // The simulator wants to set a new heightmap for the terrain. 177 // The simulator wants to set a new heightmap for the terrain.
165 public void SetTerrain(float[] heightMap) { 178 public void SetTerrain(float[] heightMap) {
166 float[] localHeightMap = heightMap; 179 float[] localHeightMap = heightMap;
167 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 180 // If there are multiple requests for changes to the same terrain between ticks,
181 // only do that last one.
182 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
168 { 183 {
169 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 184 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
170 { 185 {
@@ -176,8 +191,9 @@ public sealed class BSTerrainManager
176 { 191 {
177 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 192 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
178 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 193 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
179 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, 194 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
180 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); 195 BSScene.CHILDTERRAIN_ID, localHeightMap,
196 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
181 } 197 }
182 } 198 }
183 else 199 else
@@ -185,7 +201,7 @@ public sealed class BSTerrainManager
185 // If not doing the mega-prim thing, just change the terrain 201 // If not doing the mega-prim thing, just change the terrain
186 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 202 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
187 203
188 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, 204 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
189 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 205 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
190 } 206 }
191 }); 207 });
@@ -195,56 +211,64 @@ public sealed class BSTerrainManager
195 // based on the passed information. The 'id' should be either the terrain id or 211 // based on the passed information. The 'id' should be either the terrain id or
196 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 212 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
197 // The latter feature is for creating child terrains for mega-regions. 213 // The latter feature is for creating child terrains for mega-regions.
198 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
199 // then a new body and shape is created and the mapInfo is filled.
200 // This call is used for doing the initial terrain creation.
201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 214 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
202 // terrain shape is created and added to the body. 215 // terrain shape is created and added to the body.
203 // This call is most often used to update the heightMap and parameters of the terrain. 216 // This call is most often used to update the heightMap and parameters of the terrain.
204 // (The above does suggest that some simplification/refactoring is in order.) 217 // (The above does suggest that some simplification/refactoring is in order.)
205 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 218 // Called during taint-time.
219 private void UpdateTerrain(uint id, float[] heightMap,
220 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
206 { 221 {
207 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 222 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
208 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 223 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
209 224
225 // Find high and low points of passed heightmap.
226 // The min and max passed in is usually the area objects can be in (maximum
227 // object height, for instance). The terrain wants the bounding box for the
228 // terrain so replace passed min and max Z with the actual terrain min/max Z.
210 float minZ = float.MaxValue; 229 float minZ = float.MaxValue;
211 float maxZ = float.MinValue; 230 float maxZ = float.MinValue;
212 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y); 231 foreach (float height in heightMap)
213
214 int heightMapSize = heightMap.Length;
215 for (int ii = 0; ii < heightMapSize; ii++)
216 { 232 {
217 float height = heightMap[ii];
218 if (height < minZ) minZ = height; 233 if (height < minZ) minZ = height;
219 if (height > maxZ) maxZ = height; 234 if (height > maxZ) maxZ = height;
220 } 235 }
221 236 if (minZ == maxZ)
222 // The shape of the terrain is from its base to its extents. 237 {
238 // If min and max are the same, reduce min a little bit so a good bounding box is created.
239 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
240 }
223 minCoords.Z = minZ; 241 minCoords.Z = minZ;
224 maxCoords.Z = maxZ; 242 maxCoords.Z = maxZ;
225 243
226 BulletHeightMapInfo mapInfo; 244 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
227 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) 245
246 lock (m_terrains)
228 { 247 {
229 // If this is terrain we know about, it's easy to update 248 BSTerrainPhys terrainPhys;
230 249 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
231 mapInfo.heightMap = heightMap;
232 mapInfo.minCoords = minCoords;
233 mapInfo.maxCoords = maxCoords;
234 mapInfo.minZ = minZ;
235 mapInfo.maxZ = maxZ;
236 mapInfo.sizeX = maxCoords.X - minCoords.X;
237 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
238 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
239 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
240
241 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate()
242 { 250 {
243 if (MegaRegionParentPhysicsScene != null) 251 // There is already a terrain in this spot. Free the old and build the new.
252 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
253 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
254
255 // Remove old terrain from the collection
256 m_terrains.Remove(terrainRegionBase);
257 // Release any physical memory it may be using.
258 terrainPhys.Dispose();
259
260 if (MegaRegionParentPhysicsScene == null)
261 {
262 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
263 m_terrains.Add(terrainRegionBase, newTerrainPhys);
264
265 m_terrainModified = true;
266 }
267 else
244 { 268 {
245 // It's possible that Combine() was called after this code was queued. 269 // It's possible that Combine() was called after this code was queued.
246 // If we are a child of combined regions, we don't create any terrain for us. 270 // If we are a child of combined regions, we don't create any terrain for us.
247 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); 271 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
248 272
249 // Get rid of any terrain that may have been allocated for us. 273 // Get rid of any terrain that may have been allocated for us.
250 ReleaseGroundPlaneAndTerrain(); 274 ReleaseGroundPlaneAndTerrain();
@@ -252,135 +276,56 @@ public sealed class BSTerrainManager
252 // I hate doing this, but just bail 276 // I hate doing this, but just bail
253 return; 277 return;
254 } 278 }
279 }
280 else
281 {
282 // We don't know about this terrain so either we are creating a new terrain or
283 // our mega-prim child is giving us a new terrain to add to the phys world
255 284
256 if (mapInfo.terrainBody.ptr != IntPtr.Zero) 285 // if this is a child terrain, calculate a unique terrain id
257 { 286 uint newTerrainID = id;
258 // Updating an existing terrain. 287 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
259 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", 288 newTerrainID = ++m_terrainCount;
260 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
261
262 // Remove from the dynamics world because we're going to mangle this object
263 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
264
265 // Get rid of the old terrain
266 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
267 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
268 mapInfo.Ptr = IntPtr.Zero;
269
270 /*
271 // NOTE: This routine is half here because I can't get the terrain shape replacement
272 // to work. In the short term, the above three lines completely delete the old
273 // terrain and the code below recreates one from scratch.
274 // Hopefully the Bullet community will help me out on this one.
275
276 // First, release the old collision shape (there is only one terrain)
277 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
278
279 // Fill the existing height map info with the new location and size information
280 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
281 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
282
283 // Create a terrain shape based on the new info
284 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
285
286 // Stuff the shape into the existing terrain body
287 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
288 */
289 }
290 // else
291 {
292 // Creating a new terrain.
293 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
294 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
295
296 mapInfo.ID = id;
297 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
298 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
299
300 // Create the terrain shape from the mapInfo
301 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
302 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
303
304 // The terrain object initial position is at the center of the object
305 Vector3 centerPos;
306 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
307 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
308 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
309
310 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
311 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
312 id, centerPos, Quaternion.Identity));
313 }
314
315 // Make sure the entry is in the heightmap table
316 m_heightMaps[terrainRegionBase] = mapInfo;
317
318 // Set current terrain attributes
319 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
320 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
321 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
322 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
323
324 // Return the new terrain to the world of physical objects
325 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
326
327 // redo its bounding box now that it is in the world
328 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
329
330 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
331 (uint)CollisionFilterGroups.TerrainFilter,
332 (uint)CollisionFilterGroups.TerrainMask);
333
334 // Make sure the new shape is processed.
335 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
336 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
338
339 m_terrainModified = true;
340 });
341 }
342 else
343 {
344 // We don't know about this terrain so either we are creating a new terrain or
345 // our mega-prim child is giving us a new terrain to add to the phys world
346
347 // if this is a child terrain, calculate a unique terrain id
348 uint newTerrainID = id;
349 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
350 newTerrainID = ++m_terrainCount;
351
352 float[] heightMapX = heightMap;
353 Vector3 minCoordsX = minCoords;
354 Vector3 maxCoordsX = maxCoords;
355
356 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
357 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
358 289
359 // Code that must happen at taint-time 290 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
360 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate() 291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
361 { 292 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
362 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); 293 m_terrains.Add(terrainRegionBase, newTerrainPhys);
363 // Create a new mapInfo that will be filled with the new info
364 mapInfo = new BulletHeightMapInfo(id, heightMapX,
365 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
366 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
367 // Put the unfilled heightmap info into the collection of same
368 m_heightMaps.Add(terrainRegionBase, mapInfo);
369 // Build the terrain
370 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
371 294
372 m_terrainModified = true; 295 m_terrainModified = true;
373 }); 296 }
374 } 297 }
375 } 298 }
376 299
377 // Someday we will have complex terrain with caves and tunnels 300 // TODO: redo terrain implementation selection to allow other base types than heightMap.
378 public float GetTerrainHeightAtXYZ(Vector3 loc) 301 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
379 { 302 {
380 // For the moment, it's flat and convex 303 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
381 return GetTerrainHeightAtXY(loc.X, loc.Y); 304 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
305 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation);
306 BSTerrainPhys newTerrainPhys = null;
307 switch ((int)PhysicsScene.Params.terrainImplementation)
308 {
309 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
310 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
311 heightMap, minCoords, maxCoords);
312 break;
313 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
314 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
315 heightMap, minCoords, maxCoords);
316 break;
317 default:
318 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
319 LogHeader,
320 (int)PhysicsScene.Params.terrainImplementation,
321 PhysicsScene.Params.terrainImplementation,
322 PhysicsScene.RegionName, terrainRegionBase);
323 break;
324 }
325 return newTerrainPhys;
382 } 326 }
383 327
328
384 // Given an X and Y, find the height of the terrain. 329 // Given an X and Y, find the height of the terrain.
385 // Since we could be handling multiple terrains for a mega-region, 330 // Since we could be handling multiple terrains for a mega-region,
386 // the base of the region is calcuated assuming all regions are 331 // the base of the region is calcuated assuming all regions are
@@ -390,12 +335,15 @@ public sealed class BSTerrainManager
390 private float lastHeightTX = 999999f; 335 private float lastHeightTX = 999999f;
391 private float lastHeightTY = 999999f; 336 private float lastHeightTY = 999999f;
392 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 337 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
393 private float GetTerrainHeightAtXY(float tX, float tY) 338 public float GetTerrainHeightAtXYZ(Vector3 loc)
394 { 339 {
340 float tX = loc.X;
341 float tY = loc.Y;
395 // You'd be surprized at the number of times this routine is called 342 // You'd be surprized at the number of times this routine is called
396 // with the same parameters as last time. 343 // with the same parameters as last time.
397 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 344 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
398 return lastHeight; 345 return lastHeight;
346 m_terrainModified = false;
399 347
400 lastHeightTX = tX; 348 lastHeightTX = tX;
401 lastHeightTY = tY; 349 lastHeightTY = tY;
@@ -403,34 +351,21 @@ public sealed class BSTerrainManager
403 351
404 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 352 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
405 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 353 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
406 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); 354 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
407 355
408 BulletHeightMapInfo mapInfo; 356 lock (m_terrains)
409 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
410 { 357 {
411 float regionX = tX - offsetX; 358 BSTerrainPhys physTerrain;
412 float regionY = tY - offsetY; 359 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
413 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
414 try
415 { 360 {
416 ret = mapInfo.heightMap[mapIndex]; 361 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
417 } 362 }
418 catch 363 else
419 { 364 {
420 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 365 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
421 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}", 366 LogHeader, PhysicsScene.RegionName, tX, tY);
422 LogHeader, terrainBaseXY, regionX, regionY);
423 ret = HEIGHT_GETHEIGHT_RET;
424 } 367 }
425 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
426 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
427 }
428 else
429 {
430 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
431 LogHeader, PhysicsScene.RegionName, tX, tY);
432 } 368 }
433 m_terrainModified = false;
434 lastHeight = ret; 369 lastHeight = ret;
435 return ret; 370 return ret;
436 } 371 }
@@ -466,7 +401,7 @@ public sealed class BSTerrainManager
466 // Unhook all the combining that I know about. 401 // Unhook all the combining that I know about.
467 public void UnCombine(PhysicsScene pScene) 402 public void UnCombine(PhysicsScene pScene)
468 { 403 {
469 // Just like ODE, for the moment a NOP 404 // Just like ODE, we don't do anything yet.
470 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); 405 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
471 } 406 }
472 407
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
new file mode 100755
index 0000000..5f6675d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -0,0 +1,262 @@
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 sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
80 m_sizeX, m_sizeY,
81 (float)m_sizeX, (float)m_sizeY,
82 Vector3.Zero, 1.0f,
83 out indicesCount, out indices, out verticesCount, out vertices))
84 {
85 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future.
89 return;
90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
93
94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
95 indicesCount, indices, verticesCount, vertices),
96 BSPhysicsShapeType.SHAPE_MESH);
97 if (m_terrainShape.ptr == IntPtr.Zero)
98 {
99 // DISASTER!!
100 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
101 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
102 // Something is very messed up and a crash is in our future.
103 return;
104 }
105
106 Vector3 pos = regionBase;
107 Quaternion rot = Quaternion.Identity;
108
109 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
110 if (m_terrainBody.ptr == IntPtr.Zero)
111 {
112 // DISASTER!!
113 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
114 // Something is very messed up and a crash is in our future.
115 return;
116 }
117
118 // Set current terrain attributes
119 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction);
120 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
121 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
122 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
123
124 // Static objects are not very massive.
125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
126
127 // Put the new terrain to the world of physical objects
128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
129
130 // Redo its bounding box now that it is in the world
131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
132
133 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
134 (uint)CollisionFilterGroups.TerrainFilter,
135 (uint)CollisionFilterGroups.TerrainMask);
136
137 // Make it so the terrain will not move or be considered for movement.
138 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
139 }
140
141 public override void Dispose()
142 {
143 if (m_terrainBody.ptr != IntPtr.Zero)
144 {
145 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
146 // Frees both the body and the shape.
147 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr);
148 }
149 }
150
151 public override float GetHeightAtXYZ(Vector3 pos)
152 {
153 // For the moment use the saved heightmap to get the terrain height.
154 // TODO: raycast downward to find the true terrain below the position.
155 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
156
157 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
158 try
159 {
160 ret = m_savedHeightMap[mapIndex];
161 }
162 catch
163 {
164 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
165 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
166 LogHeader, TerrainBase, pos);
167 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
168 }
169 return ret;
170 }
171
172 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
173 // Return 'true' if successfully created.
174 public static bool ConvertHeightmapToMesh(
175 BSScene physicsScene,
176 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
177 float extentX, float extentY, // zero based range for output vertices
178 Vector3 extentBase, // base to be added to all vertices
179 float magnification, // number of vertices to create between heightMap coords
180 out int indicesCountO, out int[] indicesO,
181 out int verticesCountO, out float[] verticesO)
182 {
183 bool ret = false;
184
185 int indicesCount = 0;
186 int verticesCount = 0;
187 int[] indices = new int[0];
188 float[] vertices = new float[0];
189
190 // Simple mesh creation which assumes magnification == 1.
191 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
192
193 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
194 // from zero to <= sizeX). The triangle indices are then generated as two triangles
195 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
196 // column of vertices are used to complete the triangles of the last row and column
197 // of the heightmap.
198 try
199 {
200 // One vertice per heightmap value plus the vertices off the top and bottom edge.
201 int totalVertices = (sizeX + 1) * (sizeY + 1);
202 vertices = new float[totalVertices * 3];
203 int totalIndices = sizeX * sizeY * 6;
204 indices = new int[totalIndices];
205
206 float magX = (float)sizeX / extentX;
207 float magY = (float)sizeY / extentY;
208 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
209 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
210 float minHeight = float.MaxValue;
211 // Note that sizeX+1 vertices are created since there is land between this and the next region.
212 for (int yy = 0; yy <= sizeY; yy++)
213 {
214 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
215 {
216 int offset = yy * sizeX + xx;
217 // Extend the height with the height from the last row or column
218 if (yy == sizeY) offset -= sizeX;
219 if (xx == sizeX) offset -= 1;
220 float height = heightMap[offset];
221 minHeight = Math.Min(minHeight, height);
222 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
223 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
224 vertices[verticesCount + 2] = height + extentBase.Z;
225 verticesCount += 3;
226 }
227 }
228 verticesCount = verticesCount / 3;
229
230 for (int yy = 0; yy < sizeY; yy++)
231 {
232 for (int xx = 0; xx < sizeX; xx++)
233 {
234 int offset = yy * (sizeX + 1) + xx;
235 // Each vertices is presumed to be the upper left corner of a box of two triangles
236 indices[indicesCount + 0] = offset;
237 indices[indicesCount + 1] = offset + 1;
238 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
239 indices[indicesCount + 3] = offset + 1;
240 indices[indicesCount + 4] = offset + sizeX + 2;
241 indices[indicesCount + 5] = offset + sizeX + 1;
242 indicesCount += 6;
243 }
244 }
245
246 ret = true;
247 }
248 catch (Exception e)
249 {
250 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
251 LogHeader, physicsScene.RegionName, extentBase, e);
252 }
253
254 indicesCountO = indicesCount;
255 indicesO = indices;
256 verticesCountO = verticesCount;
257 verticesO = vertices;
258
259 return ret;
260 }
261}
262}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 07149d8..1e003e6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -88,11 +88,11 @@ public struct BulletShape
88 public BulletShape(IntPtr xx) 88 public BulletShape(IntPtr xx)
89 { 89 {
90 ptr = xx; 90 ptr = xx;
91 type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; 91 type=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = 0; 92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false; 93 isNativeShape = false;
94 } 94 }
95 public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ) 95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 { 96 {
97 ptr = xx; 97 ptr = xx;
98 type = typ; 98 type = typ;
@@ -100,7 +100,7 @@ public struct BulletShape
100 isNativeShape = false; 100 isNativeShape = false;
101 } 101 }
102 public IntPtr ptr; 102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type; 103 public BSPhysicsShapeType type;
104 public System.UInt64 shapeKey; 104 public System.UInt64 shapeKey;
105 public bool isNativeShape; 105 public bool isNativeShape;
106 public override string ToString() 106 public override string ToString()
@@ -152,7 +152,7 @@ public class BulletHeightMapInfo
152 ID = id; 152 ID = id;
153 Ptr = xx; 153 Ptr = xx;
154 heightMap = hm; 154 heightMap = hm;
155 terrainRegionBase = new Vector2(0f, 0f); 155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f); 156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f); 157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f; 158 minZ = maxZ = 0f;
@@ -161,7 +161,7 @@ public class BulletHeightMapInfo
161 public uint ID; 161 public uint ID;
162 public IntPtr Ptr; 162 public IntPtr Ptr;
163 public float[] heightMap; 163 public float[] heightMap;
164 public Vector2 terrainRegionBase; 164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords; 165 public Vector3 minCoords;
166 public Vector3 maxCoords; 166 public Vector3 maxCoords;
167 public float sizeX, sizeY; 167 public float sizeX, sizeY;
@@ -178,26 +178,39 @@ public struct ConvexHull
178 int VertexCount; 178 int VertexCount;
179 Vector3[] Vertices; 179 Vector3[] Vertices;
180} 180}
181public enum BSPhysicsShapeType
182{
183 SHAPE_UNKNOWN = 0,
184 SHAPE_CAPSULE = 1,
185 SHAPE_BOX = 2,
186 SHAPE_CONE = 3,
187 SHAPE_CYLINDER = 4,
188 SHAPE_SPHERE = 5,
189 SHAPE_MESH = 6,
190 SHAPE_HULL = 7,
191 // following defined by BulletSim
192 SHAPE_GROUNDPLANE = 20,
193 SHAPE_TERRAIN = 21,
194 SHAPE_COMPOUND = 22,
195 SHAPE_HEIGHTMAP = 23,
196};
197
198// The native shapes have predefined shape hash keys
199public enum FixedShapeKey : ulong
200{
201 KEY_NONE = 0,
202 KEY_BOX = 1,
203 KEY_SPHERE = 2,
204 KEY_CONE = 3,
205 KEY_CYLINDER = 4,
206 KEY_CAPSULE = 5,
207}
208
181[StructLayout(LayoutKind.Sequential)] 209[StructLayout(LayoutKind.Sequential)]
182public struct ShapeData 210public struct ShapeData
183{ 211{
184 public enum PhysicsShapeType
185 {
186 SHAPE_UNKNOWN = 0,
187 SHAPE_AVATAR = 1,
188 SHAPE_BOX = 2,
189 SHAPE_CONE = 3,
190 SHAPE_CYLINDER = 4,
191 SHAPE_SPHERE = 5,
192 SHAPE_MESH = 6,
193 SHAPE_HULL = 7,
194 // following defined by BulletSim
195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21,
197 SHAPE_COMPOUND = 22,
198 };
199 public uint ID; 212 public uint ID;
200 public PhysicsShapeType Type; 213 public BSPhysicsShapeType Type;
201 public Vector3 Position; 214 public Vector3 Position;
202 public Quaternion Rotation; 215 public Quaternion Rotation;
203 public Vector3 Velocity; 216 public Vector3 Velocity;
@@ -216,16 +229,6 @@ public struct ShapeData
216 // note that bools are passed as floats since bool size changes by language and architecture 229 // note that bools are passed as floats since bool size changes by language and architecture
217 public const float numericTrue = 1f; 230 public const float numericTrue = 1f;
218 public const float numericFalse = 0f; 231 public const float numericFalse = 0f;
219
220 // The native shapes have predefined shape hash keys
221 public enum FixedShapeKey : ulong
222 {
223 KEY_BOX = 1,
224 KEY_SPHERE = 2,
225 KEY_CONE = 3,
226 KEY_CYLINDER = 4,
227 KEY_CAPSULE = 5,
228 }
229} 232}
230[StructLayout(LayoutKind.Sequential)] 233[StructLayout(LayoutKind.Sequential)]
231public struct SweepHit 234public struct SweepHit
@@ -280,17 +283,23 @@ public struct ConfigurationParameters
280 public float ccdSweptSphereRadius; 283 public float ccdSweptSphereRadius;
281 public float contactProcessingThreshold; 284 public float contactProcessingThreshold;
282 285
286 public float terrainImplementation;
283 public float terrainFriction; 287 public float terrainFriction;
284 public float terrainHitFraction; 288 public float terrainHitFraction;
285 public float terrainRestitution; 289 public float terrainRestitution;
290 public float terrainCollisionMargin;
291
286 public float avatarFriction; 292 public float avatarFriction;
287 public float avatarStandingFriction; 293 public float avatarStandingFriction;
288 public float avatarDensity; 294 public float avatarDensity;
289 public float avatarRestitution; 295 public float avatarRestitution;
290 public float avatarCapsuleRadius; 296 public float avatarCapsuleWidth;
297 public float avatarCapsuleDepth;
291 public float avatarCapsuleHeight; 298 public float avatarCapsuleHeight;
292 public float avatarContactProcessingThreshold; 299 public float avatarContactProcessingThreshold;
293 300
301 public float vehicleAngularDamping;
302
294 public float maxPersistantManifoldPoolSize; 303 public float maxPersistantManifoldPoolSize;
295 public float maxCollisionAlgorithmPoolSize; 304 public float maxCollisionAlgorithmPoolSize;
296 public float shouldDisableContactPoolDynamicAllocation; 305 public float shouldDisableContactPoolDynamicAllocation;
@@ -348,7 +357,7 @@ public enum CollisionFlags : uint
348 CF_CHARACTER_OBJECT = 1 << 4, 357 CF_CHARACTER_OBJECT = 1 << 4,
349 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 358 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
350 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 359 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
351 // Following used by BulletSim to control collisions 360 // Following used by BulletSim to control collisions and updates
352 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 361 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
353 BS_FLOATS_ON_WATER = 1 << 11, 362 BS_FLOATS_ON_WATER = 1 << 11,
354 BS_NONE = 0, 363 BS_NONE = 0,
@@ -388,13 +397,13 @@ public enum CollisionFilterGroups : uint
388 ObjectFilter = BSolidFilter, 397 ObjectFilter = BSolidFilter,
389 ObjectMask = BAllFilter, 398 ObjectMask = BAllFilter,
390 StaticObjectFilter = BStaticFilter, 399 StaticObjectFilter = BStaticFilter,
391 StaticObjectMask = BAllFilter, 400 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
392 LinksetFilter = BLinksetFilter, 401 LinksetFilter = BLinksetFilter,
393 LinksetMask = BAllFilter & ~BLinksetFilter, 402 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
394 VolumeDetectFilter = BSensorTrigger, 403 VolumeDetectFilter = BSensorTrigger,
395 VolumeDetectMask = ~BSensorTrigger, 404 VolumeDetectMask = ~BSensorTrigger,
396 TerrainFilter = BTerrainFilter, 405 TerrainFilter = BTerrainFilter,
397 TerrainMask = BAllFilter & ~BStaticFilter, 406 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
398 GroundPlaneFilter = BGroundPlaneFilter, 407 GroundPlaneFilter = BGroundPlaneFilter,
399 GroundPlaneMask = BAllFilter 408 GroundPlaneMask = BAllFilter
400 409
@@ -429,140 +438,6 @@ static class BulletSimAPI {
429[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 438[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
430public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 439public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
431 440
432[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
433[return: MarshalAs(UnmanagedType.LPStr)]
434public static extern string GetVersion();
435
436/* Remove the linkage to the old api methods
437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
438public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
439 int maxCollisions, IntPtr collisionArray,
440 int maxUpdates, IntPtr updateArray,
441 DebugLogCallback logRoutine);
442
443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
444public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
445
446[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
447public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
448
449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
450public static extern void Shutdown(uint worldID);
451
452[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
453public static extern bool UpdateParameter(uint worldID, uint localID,
454 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
455
456// ===============================================================================
457[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
458public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
459 out int updatedEntityCount,
460 out IntPtr updatedEntitiesPtr,
461 out int collidersCount,
462 out IntPtr collidersPtr);
463
464[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
465public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
466 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
467 );
468
469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
470public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
471 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
472 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
473 );
474
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
477
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
480
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool CreateObject(uint worldID, ShapeData shapeData);
483
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
486
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
489
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
492
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
495
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
498
499// Set the current force acting on the object
500[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
501public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
502
503[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
504public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
505
506[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
507public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
508
509[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
510public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
511
512[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
513public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
514
515[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
516public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
517
518[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
519public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
520
521[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
522public static extern bool HasObject(uint worldID, uint id);
523
524[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
525public static extern bool DestroyObject(uint worldID, uint id);
526
527// ===============================================================================
528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
529public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
530
531[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
532public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
533
534[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
535public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
536
537// ===============================================================================
538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
539public static extern void DumpBulletStatistics();
540*/
541// Log a debug message
542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
543public static extern void SetDebugLogCallback(DebugLogCallback callback);
544
545// ===============================================================================
546// ===============================================================================
547// ===============================================================================
548// A new version of the API that enables moving all the logic out of the C++ code and into
549// the C# code. This will make modifications easier for the next person.
550// This interface passes the actual pointers to the objects in the unmanaged
551// address space. All the management (calls for creation/destruction/lookup)
552// is done in the C# code.
553// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
554// and the old code is removed.
555
556// Functions use while converting from API1 to API2. Can be removed when totally converted.
557[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
558public static extern IntPtr GetSimHandle2(uint worldID);
559
560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
561public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
562
563[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
564public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
565
566// =============================================================================== 441// ===============================================================================
567// Initialization and simulation 442// Initialization and simulation
568[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -611,6 +486,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
611public static extern bool IsNativeShape2(IntPtr shape); 486public static extern bool IsNativeShape2(IntPtr shape);
612 487
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 488[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
489public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
490
491[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
614public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 492public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
615 493
616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 494[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
index cbc6b95..16404c6 100644
--- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
+++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
@@ -32,13 +32,14 @@ using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.OdePlugin; 34using OpenSim.Region.Physics.OdePlugin;
35using OpenSim.Tests.Common;
35using log4net; 36using log4net;
36using System.Reflection; 37using System.Reflection;
37 38
38namespace OpenSim.Region.Physics.OdePlugin.Tests 39namespace OpenSim.Region.Physics.OdePlugin.Tests
39{ 40{
40 [TestFixture] 41 [TestFixture]
41 public class ODETestClass 42 public class ODETestClass : OpenSimTestCase
42 { 43 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 45