aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs599
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs191
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs273
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs66
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs67
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs10
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs122
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs34
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs9
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs3
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs5
12 files changed, 865 insertions, 516 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..1dfc420 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 307 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 309 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 310 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 311 if (Position.Z < waterHeight)
312 { 312 {
313 _position.Z = waterHeight; 313 _position.Z = waterHeight;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..3a73fba 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;
@@ -427,9 +445,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
427 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY 445 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
428 | VehicleFlag.HOVER_GLOBAL_HEIGHT 446 | VehicleFlag.HOVER_GLOBAL_HEIGHT
429 | VehicleFlag.LIMIT_ROLL_ONLY 447 | VehicleFlag.LIMIT_ROLL_ONLY
448 | VehicleFlag.LIMIT_MOTOR_UP
430 | VehicleFlag.HOVER_UP_ONLY); 449 | VehicleFlag.HOVER_UP_ONLY);
431 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 450 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
432 | VehicleFlag.LIMIT_MOTOR_UP
433 | VehicleFlag.HOVER_WATER_ONLY); 451 | VehicleFlag.HOVER_WATER_ONLY);
434 break; 452 break;
435 case Vehicle.TYPE_AIRPLANE: 453 case Vehicle.TYPE_AIRPLANE:
@@ -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 623
593 if (m_linearMotorDirection.LengthSquared() > 0.001f) 624 // Rotate new object velocity from vehicle relative to world coordinates
594 { 625 linearMotorContribution *= Prim.ForceOrientation;
595 Vector3 origDir = m_linearMotorDirection; // DEBUG 626
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG 627 // ==================================================================
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison 628 // Gravity and Buoyancy
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG 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);
599 632
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 633 Vector3 pos = Prim.ForcePosition;
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; 634 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
602 m_lastLinearVelocityVector += addAmount;
603 635
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 636 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
605 m_linearMotorDirection *= (1f - decayFactor);
606 637
607 // Rotate new object velocity from vehicle relative to world coordinates 638 Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609 639
610 // Apply friction for next time 640 ComputeLinearBlockingEndPoint(pTimestep, ref pos);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 641
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 642 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 643
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 644 // ==================================================================
617 } 645 Vector3 newVelocity = linearMotorContribution
618 else 646 + terrainHeightContribution
619 { 647 + hoverContribution
620 // if what remains of direction is very small, zero it. 648 + limitMotorUpContribution;
621 m_linearMotorDirection = Vector3.Zero;
622 m_lastLinearVelocityVector = Vector3.Zero;
623 m_newVelocity = Vector3.Zero;
624 649
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 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;
657
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)
@@ -663,7 +713,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 713 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 714 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 715 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 716 m_VhoverTargetHeight = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
667 } 717 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 718 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 719 {
@@ -680,6 +730,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
680 if (pos.Z > m_VhoverTargetHeight) 730 if (pos.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 731 m_VhoverTargetHeight = pos.Z;
682 } 732 }
733
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 734 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 735 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 736 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
@@ -694,28 +745,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
694 // RA: where does the 50 come from? 745 // RA: where does the 50 come from?
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 746 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
696 // Replace Vertical speed with correction figure if significant 747 // Replace Vertical speed with correction figure if significant
697 if (Math.Abs(verticalError) > 0.01f) 748 if (verticalError > 0.01f)
698 { 749 {
699 m_newVelocity.Z += verticalCorrectionVelocity; 750 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
700 //KF: m_VhoverEfficiency is not yet implemented 751 //KF: m_VhoverEfficiency is not yet implemented
701 } 752 }
702 else if (verticalError < -0.01) 753 else if (verticalError < -0.01)
703 { 754 {
704 m_newVelocity.Z -= verticalCorrectionVelocity; 755 ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
705 }
706 else
707 {
708 m_newVelocity.Z = 0f;
709 } 756 }
710 } 757 }
711 758
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); 759 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
760 Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
713 } 761 }
714 762
763 return ret;
764 }
765
766 public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
767 {
768 bool changed = false;
769
715 Vector3 posChange = pos - m_lastPositionVector; 770 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 771 if (m_BlockingEndPoint != Vector3.Zero)
717 { 772 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 773 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 774 {
721 pos.X -= posChange.X + 1; 775 pos.X -= posChange.X + 1;
@@ -748,75 +802,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 802 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 803 }
750 } 804 }
805 return changed;
806 }
751 807
752 #region downForce 808 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 809 // Prevent ground vehicles from motoring into the sky.This flag has a subtle effect when
754 810 // used with conjunction with banking: the strength of the banking will decay when the
811 // vehicle no longer experiences collisions. The decay timescale is the same as
812 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
813 // when they are in mid jump.
814 // TODO: this code is wrong. Also, what should it do for boats?
815 public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
816 {
817 Vector3 ret = Vector3.Zero;
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 818 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 819 {
757 // If the vehicle is motoring into the sky, get it going back down. 820 // 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; 821 float distanceAboveGround = pos.Z - terrainHeight;
760 if (distanceAboveGround > 2f) 822 if (distanceAboveGround > 1f)
761 { 823 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); 824 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 825 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 826 ret = new Vector3(0, 0, -distanceAboveGround);
765 } 827 }
766 // TODO: this calculation is all wrong. From the description at 828 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 829 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 830 // has a decay factor. This says this force should
769 // be computed with a motor. 831 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 832 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce); 833 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
772 } 834 Prim.LocalID, distanceAboveGround, ret);
773 #endregion // downForce
774
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 } 835 }
836 return ret;
837 }
802 838
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 839 // =======================================================================
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
805
806 } // end MoveLinear()
807
808 // ======================================================================= 840 // =======================================================================
809 // Apply the effect of the angular motor. 841 // Apply the effect of the angular motor.
810 private void MoveAngular(float pTimestep) 842 private void MoveAngular(float pTimestep)
811 { 843 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 844 // 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) 845 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
815 // m_angularMotorTimescale // motor angular velocity ramp up rate 846 // m_angularMotorTimescale // motor angular velocity ramp up time
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate 847 // m_angularMotorDecayTimescale // motor angular velocity decay rate
817 // m_angularFrictionTimescale // body angular velocity decay rate 848 // m_angularFrictionTimescale // body angular velocity decay rate
818 // m_lastAngularVelocity // what was last applied to body 849 // m_lastAngularVelocity // what was last applied to body
819 850
851 /*
820 if (m_angularMotorDirection.LengthSquared() > 0.0001) 852 if (m_angularMotorDirection.LengthSquared() > 0.0001)
821 { 853 {
822 Vector3 origVel = m_angularMotorVelocity; 854 Vector3 origVel = m_angularMotorVelocity;
@@ -835,59 +867,157 @@ namespace OpenSim.Region.Physics.BulletSPlugin
835 { 867 {
836 m_angularMotorVelocity = Vector3.Zero; 868 m_angularMotorVelocity = Vector3.Zero;
837 } 869 }
870 */
838 871
839 #region Vertical attactor 872 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
840 873
841 Vector3 vertattr = Vector3.Zero; 874 // ==================================================================
842 Vector3 deflection = Vector3.Zero; 875 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
843 Vector3 banking = Vector3.Zero; 876 // This flag prevents linear deflection parallel to world z-axis. This is useful
877 // for preventing ground vehicles with large linear deflection, like bumper cars,
878 // from climbing their linear deflection into the sky.
879 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
880 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
881 {
882 angularMotorContribution.X = 0f;
883 angularMotorContribution.Y = 0f;
884 VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
885 }
844 886
845 // If vertical attaction timescale is reasonable and we applied an angular force last time... 887 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 888
889 Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
890
891 Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
892
893 // ==================================================================
894 m_lastVertAttractor = verticalAttractionContribution;
895
896 // Sum velocities
897 m_lastAngularVelocity = angularMotorContribution
898 + verticalAttractionContribution
899 + deflectionContribution
900 + bankingContribution;
901
902 // ==================================================================
903 //Offset section
904 if (m_linearMotorOffset != Vector3.Zero)
905 {
906 //Offset of linear velocity doesn't change the linear velocity,
907 // but causes a torque to be applied, for example...
908 //
909 // IIIII >>> IIIII
910 // IIIII >>> IIIII
911 // IIIII >>> IIIII
912 // ^
913 // | Applying a force at the arrow will cause the object to move forward, but also rotate
914 //
915 //
916 // The torque created is the linear velocity crossed with the offset
917
918 // TODO: this computation should be in the linear section
919 // because that is where we know the impulse being applied.
920 Vector3 torqueFromOffset = Vector3.Zero;
921 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
922 if (float.IsNaN(torqueFromOffset.X))
923 torqueFromOffset.X = 0;
924 if (float.IsNaN(torqueFromOffset.Y))
925 torqueFromOffset.Y = 0;
926 if (float.IsNaN(torqueFromOffset.Z))
927 torqueFromOffset.Z = 0;
928 torqueFromOffset *= m_vehicleMass;
929 Prim.ApplyTorqueImpulse(torqueFromOffset, true);
930 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
931 }
932
933 // ==================================================================
934 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
935 {
936 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
937 // TODO: zeroing is good but it also sets values in unmanaged code. Remove the stores when idle.
938 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
939 Prim.ZeroAngularMotion(true);
940 }
941 else
847 { 942 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; 943 // Apply to the body.
849 if (Prim.IsColliding) 944 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); 945 // Since we are stuffing the angular velocity directly into the object, the computed
946 // velocity needs to be scaled by the timestep.
947 // Also remove any motion that is on the object so added motion is only from vehicle.
948 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
949 - Prim.ForceRotationalVelocity);
950 // Unscale the force by the angular factor so it overwhelmes the Bullet additions.
951 Prim.ForceRotationalVelocity = applyAngularForce;
952
953 VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
954 Prim.LocalID,
955 angularMotorContribution, verticalAttractionContribution,
956 bankingContribution, deflectionContribution,
957 applyAngularForce, m_lastAngularVelocity
958 );
959 }
960 }
851 961
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 962 public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
963 {
964 Vector3 ret = Vector3.Zero;
853 965
854 // Create a vector of the vehicle "up" in world coordinates 966 // If vertical attaction timescale is reasonable and we applied an angular force last time...
967 if (m_verticalAttractionTimescale < 500)
968 {
969 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
970 verticalError.Normalize();
971 m_verticalAttractionMotor.SetCurrent(verticalError);
972 m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
973 ret = m_verticalAttractionMotor.Step(pTimestep);
974 /*
975 // Take a vector pointing up and convert it from world to vehicle relative coords.
855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; 976 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no 977 verticalError.Normalize();
857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its 978
858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall 979 // 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 980 // is now leaning to one side (rotated around the X axis) and the Y value will
860 // modulated to prevent a stable inverted body. 981 // go from zero (nearly straight up) to one (completely to the side) or leaning
861 982 // 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) 983 // zero and one.
863 if (verticalError.Z < 0.0f) 984 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
985
986 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
987 if (verticalError.Z < 0f)
864 { 988 {
865 verticalError.X = 2.0f - verticalError.X; 989 verticalError.X = 2f - verticalError.X;
866 verticalError.Y = 2.0f - verticalError.Y; 990 verticalError.Y = 2f - verticalError.Y;
867 } 991 }
868 // scale it by VAservo (timestep and timescale)
869 verticalError = verticalError * VAservo;
870 992
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y 993 // 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. 994 verticalAttractionContribution.X = verticalError.Y;
873 // Z is not changed. 995 verticalAttractionContribution.Y = - verticalError.X;
874 vertattr.X = verticalError.Y; 996 verticalAttractionContribution.Z = 0f;
875 vertattr.Y = - verticalError.X;
876 vertattr.Z = 0f;
877 997
878 // scaling appears better usingsquare-law 998 // scale by the time scale and timestep
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity; 999 Vector3 unscaledContrib = verticalAttractionContribution;
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 1000 verticalAttractionContribution /= m_verticalAttractionTimescale;
881 vertattr.X += bounce * angularVelocity.X; 1001 verticalAttractionContribution *= pTimestep;
882 vertattr.Y += bounce * angularVelocity.Y;
883 1002
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 1003 // apply efficiency
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); 1004 Vector3 preEfficiencyContrib = verticalAttractionContribution;
1005 float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
1006 verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
1007
1008 VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
1009 Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
1010 m_verticalAttractionEfficiency, efficencySquared,
1011 verticalAttractionContribution);
1012 */
886 1013
887 } 1014 }
888 #endregion // Vertical attactor 1015 return ret;
1016 }
889 1017
890 #region Deflection 1018 public Vector3 ComputeAngularDeflection(float pTimestep)
1019 {
1020 Vector3 ret = Vector3.Zero;
891 1021
892 if (m_angularDeflectionEfficiency != 0) 1022 if (m_angularDeflectionEfficiency != 0)
893 { 1023 {
@@ -899,32 +1029,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); 1029 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900 1030
901 // Scale by efficiency and timescale 1031 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; 1032 ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
1033
1034 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
903 1035
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct. 1036 // This deflection computation is not correct.
907 deflection = Vector3.Zero; 1037 ret = Vector3.Zero;
908 } 1038 }
1039 return ret;
1040 }
909 1041
910 #endregion 1042 public Vector3 ComputeAngularBanking(float pTimestep)
911 1043 {
912 #region Banking 1044 Vector3 ret = Vector3.Zero;
913 1045
914 if (m_bankingEfficiency != 0) 1046 if (m_bankingEfficiency != 0)
915 { 1047 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1048 Vector3 dir = Vector3.One * Prim.ForceOrientation;
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); 1049 float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns 1050 //Changes which way it banks in and out of turns
919 1051
920 //Use the square of the efficiency, as it looks much more how SL banking works 1052 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency); 1053 float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
922 if (m_bankingEfficiency < 0) 1054 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative! 1055 effSquared *= -1; //Keep the negative!
924 1056
925 float mix = Math.Abs(m_bankingMix); 1057 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0) 1058 if (m_angularMotorVelocity.X == 0)
927 { 1059 {
1060 // The vehicle is stopped
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) 1061 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 { 1062 {
930 Vector3 axisAngle; 1063 Vector3 axisAngle;
@@ -938,101 +1071,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
938 }*/ 1071 }*/
939 } 1072 }
940 else 1073 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; 1074 {
1075 ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
1076 }
1077
1078 //If they are colliding, we probably shouldn't shove the prim around... probably
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) 1079 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 { 1080 {
945 float angVelZ = m_angularMotorVelocity.X*-1; 1081 float angVelZ = m_angularMotorVelocity.X * -1;
946 /*if(angVelZ > mix) 1082 /*if(angVelZ > mix)
947 angVelZ = mix; 1083 angVelZ = mix;
948 else if(angVelZ < -mix) 1084 else if(angVelZ < -mix)
949 angVelZ = -mix;*/ 1085 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs 1086 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); 1087 Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
952 if (bankingRot.X > 3) 1088 if (bankingRot.X > 3)
953 bankingRot.X = 3; 1089 bankingRot.X = 3;
954 else if (bankingRot.X < -3) 1090 else if (bankingRot.X < -3)
955 bankingRot.X = -3; 1091 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation; 1092 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot; 1093 ret += bankingRot;
958 } 1094 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; 1095 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", 1096 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); 1097 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
962 }
963
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 } 1098 }
1099 return ret;
1100 }
1011 1101
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 1102
1103 // This is from previous instantiations of XXXDynamics.cs.
1104 // Applies roll reference frame.
1105 // TODO: is this the right way to separate the code to do this operation?
1106 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1107 internal void LimitRotation(float timestep)
1037 { 1108 {
1038 Quaternion rotq = Prim.ForceOrientation; 1109 Quaternion rotq = Prim.ForceOrientation;
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/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..3fb0300 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 253 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 255 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 256 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 257 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
258 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
258 }); 259 });
259 } 260 }
260 261
@@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject
329 330
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 331 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 332 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 333 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 334 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 335 if (Math.Abs(Position.Z - waterHeight) > 0.1f)
335 { 336 {
@@ -342,13 +343,12 @@ public sealed class BSPrim : BSPhysObject
342 // TODO: check for out of bounds 343 // TODO: check for out of bounds
343 344
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 345 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
346 // TODO: This should be intergrated with a geneal physics action mechanism.
347 // TODO: This should be moderated with PID'ness.
345 if (ret) 348 if (ret)
346 { 349 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() 350 // Apply upforce and overcome gravity.
348 { 351 AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
349 // Apply upforce and overcome gravity.
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
351 });
352 } 352 }
353 return ret; 353 return ret;
354 } 354 }
@@ -1381,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
1381 1381
1382 public override void UpdateProperties(EntityProperties entprop) 1382 public override void UpdateProperties(EntityProperties entprop)
1383 { 1383 {
1384 /* 1384 // Updates only for individual prims and for the root object of a linkset.
1385 UpdatedProperties changed = 0; 1385 if (Linkset.IsRoot(this))
1386 // assign to the local variables so the normal set action does not happen
1387 // if (_position != entprop.Position)
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1389 {
1390 _position = entprop.Position;
1391 changed |= UpdatedProperties.Position;
1392 }
1393 // if (_orientation != entprop.Rotation)
1394 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1395 {
1396 _orientation = entprop.Rotation;
1397 changed |= UpdatedProperties.Rotation;
1398 }
1399 // if (_velocity != entprop.Velocity)
1400 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1401 {
1402 _velocity = entprop.Velocity;
1403 changed |= UpdatedProperties.Velocity;
1404 }
1405 // if (_acceleration != entprop.Acceleration)
1406 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1407 {
1408 _acceleration = entprop.Acceleration;
1409 changed |= UpdatedProperties.Acceleration;
1410 }
1411 // if (_rotationalVelocity != entprop.RotationalVelocity)
1412 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1413 {
1414 _rotationalVelocity = entprop.RotationalVelocity;
1415 changed |= UpdatedProperties.RotationalVel;
1416 }
1417 if (changed != 0)
1418 { 1386 {
1419 // Only update the position of single objects and linkset roots 1387 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1420 if (Linkset.IsRoot(this)) 1388 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1389 if (_vehicle.IsActive)
1421 { 1390 {
1422 base.RequestPhysicsterseUpdate(); 1391 entprop.RotationalVelocity = OMV.Vector3.Zero;
1423 } 1392 }
1424 }
1425 */
1426
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1428 1393
1429 // Updates only for individual prims and for the root object of a linkset.
1430 if (Linkset.IsRoot(this))
1431 {
1432 // Assign directly to the local variables so the normal set action does not happen 1394 // Assign directly to the local variables so the normal set action does not happen
1433 _position = entprop.Position; 1395 _position = entprop.Position;
1434 _orientation = entprop.Rotation; 1396 _orientation = entprop.Rotation;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..0c80611 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
@@ -140,7 +127,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
140 public const uint GROUNDPLANE_ID = 1; 127 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 128 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142 129
143 private float m_waterLevel; 130 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; } 131 public BSTerrainManager TerrainManager { get; private set; }
145 132
146 public ConfigurationParameters Params 133 public ConfigurationParameters Params
@@ -195,6 +182,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
195 private string m_physicsLoggingDir; 182 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix; 183 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes; 184 private int m_physicsLoggingFileMinutes;
185 private bool m_physicsLoggingDoFlush;
198 // 'true' of the vehicle code is to log lots of details 186 // 'true' of the vehicle code is to log lots of details
199 public bool VehicleLoggingEnabled { get; private set; } 187 public bool VehicleLoggingEnabled { get; private set; }
200 188
@@ -234,6 +222,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 222 if (m_physicsLoggingEnabled)
235 { 223 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 224 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
225 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 226 }
238 else 227 else
239 { 228 {
@@ -302,12 +291,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 291 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 292 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 293 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
294 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
305 // Very detailed logging for vehicle debugging 295 // Very detailed logging for vehicle debugging
306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 296 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
307 297
308 // Do any replacements in the parameters 298 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 299 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 300 }
301
302 // The material characteristics.
303 BSMaterials.InitializeFromDefaults(Params);
304 if (pConfig != null)
305 {
306 BSMaterials.InitializefromParameters(pConfig);
307 }
311 } 308 }
312 } 309 }
313 310
@@ -499,7 +496,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
499 496
500 try 497 try
501 { 498 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 499 // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 500 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
504 501
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 502 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@@ -508,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 505 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 506 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 507 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 508 // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
512 } 509 }
513 catch (Exception e) 510 catch (Exception e)
514 { 511 {
@@ -520,9 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 517 collidersCount = 0;
521 } 518 }
522 519
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 520 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
524 521
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 522 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 523 SimulationNowTime = Util.EnvironmentTickCount();
527 524
528 // If there were collisions, process them by sending the event to the prim. 525 // If there were collisions, process them by sending the event to the prim.
@@ -568,6 +565,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
568 ObjectsWithCollisions.Remove(po); 565 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 566 ObjectsWithNoMoreCollisions.Clear();
570 } 567 }
568 // Done with collisions.
571 569
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 570 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 571 if (updatedEntityCount > 0)
@@ -591,9 +589,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
591 589
592 // The physics engine returns the number of milliseconds it simulated this call. 590 // 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. 591 // 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). 592 // Multiply by 55 to give a nominal frame rate of 55.
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 593 return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
596 // return timeStep * 1000 * 55;
597 } 594 }
598 595
599 // Something has collided 596 // Something has collided
@@ -639,12 +636,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 636
640 public override void SetWaterLevel(float baseheight) 637 public override void SetWaterLevel(float baseheight)
641 { 638 {
642 m_waterLevel = baseheight; 639 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 640 }
649 641
650 public override void DeleteTerrain() 642 public override void DeleteTerrain()
@@ -1069,7 +1061,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1069 (s,p,l,v) => { s.PID_P = v; } ), 1061 (s,p,l,v) => { s.PID_P = v; } ),
1070 1062
1071 new ParameterDefn("DefaultFriction", "Friction factor used on new objects", 1063 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
1072 0.5f, 1064 0.2f,
1073 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, 1065 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
1074 (s) => { return s.m_params[0].defaultFriction; }, 1066 (s) => { return s.m_params[0].defaultFriction; },
1075 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), 1067 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
@@ -1084,7 +1076,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1084 (s) => { return s.m_params[0].defaultRestitution; }, 1076 (s) => { return s.m_params[0].defaultRestitution; },
1085 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), 1077 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
1086 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", 1078 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
1087 0f, 1079 0.04f,
1088 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, 1080 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
1089 (s) => { return s.m_params[0].collisionMargin; }, 1081 (s) => { return s.m_params[0].collisionMargin; },
1090 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), 1082 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
@@ -1151,7 +1143,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1151 (s) => { return s.m_params[0].terrainImplementation; }, 1143 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), 1144 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1145 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1154 0.5f, 1146 0.3f,
1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1147 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1156 (s) => { return s.m_params[0].terrainFriction; }, 1148 (s) => { return s.m_params[0].terrainFriction; },
1157 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), 1149 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
@@ -1165,13 +1157,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1165 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1157 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainRestitution; }, 1158 (s) => { return s.m_params[0].terrainRestitution; },
1167 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), 1159 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1160 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
1161 0.04f,
1162 (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
1163 (s) => { return s.m_params[0].terrainCollisionMargin; },
1164 (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
1165
1168 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1166 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1169 0.2f, 1167 0.2f,
1170 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1168 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1171 (s) => { return s.m_params[0].avatarFriction; }, 1169 (s) => { return s.m_params[0].avatarFriction; },
1172 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1170 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1173 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 1171 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1174 10f, 1172 10.0f,
1175 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, 1173 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1176 (s) => { return s.m_params[0].avatarStandingFriction; }, 1174 (s) => { return s.m_params[0].avatarStandingFriction; },
1177 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), 1175 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@@ -1206,6 +1204,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1206 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1204 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1207 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1205 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1208 1206
1207 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
1208 0.95f,
1209 (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
1210 (s) => { return s.m_params[0].vehicleAngularDamping; },
1211 (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
1209 1212
1210 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1213 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1211 0f, 1214 0f,
@@ -1487,7 +1490,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1487 { 1490 {
1488 PhysicsLogging.Write(msg, args); 1491 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 1492 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 1493 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 1494 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1495 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 1496 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 3ca756c..0cb151e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
93 { 93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, 94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords, 95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); 96 m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
97 97
98 // Create the terrain shape from the mapInfo 98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), 99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
@@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
148 } 148 }
149 149
150 // The passed position is relative to the base of the region. 150 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos) 151 public override float GetTerrainHeightAtXYZ(Vector3 pos)
152 { 152 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154 154
@@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
166 } 166 }
167 return ret; 167 return ret;
168 } 168 }
169
170 // The passed position is relative to the base of the region.
171 public override float GetWaterLevelAtXYZ(Vector3 pos)
172 {
173 return PhysicsScene.SimpleWaterLevel;
174 }
169} 175}
170} 176}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 23fcfd3..17d9536 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
62 ID = id; 62 ID = id;
63 } 63 }
64 public abstract void Dispose(); 64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos); 65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66} 67}
67 68
68// ========================================================================================== 69// ==========================================================================================
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager
75 public const float HEIGHT_INITIALIZATION = 24.987f; 76 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; 77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f; 78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
78 80
79 // If the min and max height are equal, we reduce the min by this 81 // If the min and max height are equal, we reduce the min by this
80 // amount to make sure that a bounding box is built for the terrain. 82 // amount to make sure that a bounding box is built for the terrain.
81 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
82 84
83 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants. 85 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
@@ -129,7 +129,8 @@ public sealed class BSTerrainManager
129 { 129 {
130 // The ground plane is here to catch things that are trying to drop to negative infinity 130 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 131 BulletShape groundPlaneShape = new BulletShape(
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
133 PhysicsScene.Params.terrainCollisionMargin),
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 134 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 135 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 136 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@@ -165,17 +166,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 166 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 167 public void ReleaseTerrain()
167 { 168 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 169 lock (m_terrains)
169 { 170 {
170 kvp.Value.Dispose(); 171 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
172 {
173 kvp.Value.Dispose();
174 }
175 m_terrains.Clear();
171 } 176 }
172 m_terrains.Clear();
173 } 177 }
174 178
175 // The simulator wants to set a new heightmap for the terrain. 179 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 180 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 181 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 182 // If there are multiple requests for changes to the same terrain between ticks,
183 // only do that last one.
184 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 185 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 186 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 187 {
@@ -211,6 +217,7 @@ public sealed class BSTerrainManager
211 // terrain shape is created and added to the body. 217 // terrain shape is created and added to the body.
212 // This call is most often used to update the heightMap and parameters of the terrain. 218 // This call is most often used to update the heightMap and parameters of the terrain.
213 // (The above does suggest that some simplification/refactoring is in order.) 219 // (The above does suggest that some simplification/refactoring is in order.)
220 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 221 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 222 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 223 {
@@ -220,7 +227,7 @@ public sealed class BSTerrainManager
220 // Find high and low points of passed heightmap. 227 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 228 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the 229 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z. 230 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 231 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 232 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 233 foreach (float height in heightMap)
@@ -238,15 +245,15 @@ public sealed class BSTerrainManager
238 245
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 246 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 247
241 BSTerrainPhys terrainPhys; 248 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 249 {
244 // There is already a terrain in this spot. Free the old and build the new. 250 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 251 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 252 {
253 // There is already a terrain in this spot. Free the old and build the new.
254 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
255 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
256
250 // Remove old terrain from the collection 257 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 258 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 259 // Release any physical memory it may be using.
@@ -271,35 +278,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 278 // I hate doing this, but just bail
272 return; 279 return;
273 } 280 }
274 }); 281 }
275 } 282 else
276 else 283 {
277 { 284 // We don't know about this terrain so either we are creating a new terrain or
278 // We don't know about this terrain so either we are creating a new terrain or 285 // our mega-prim child is giving us a new terrain to add to the phys world
279 // our mega-prim child is giving us a new terrain to add to the phys world
280
281 // if this is a child terrain, calculate a unique terrain id
282 uint newTerrainID = id;
283 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
284 newTerrainID = ++m_terrainCount;
285
286 float[] heightMapX = heightMap;
287 Vector3 minCoordsX = minCoords;
288 Vector3 maxCoordsX = maxCoords;
289 286
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 287 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 288 uint newTerrainID = id;
289 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
290 newTerrainID = ++m_terrainCount;
292 291
293 // Code that must happen at taint-time 292 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 293 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
295 {
296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 294 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 295 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 296
301 m_terrainModified = true; 297 m_terrainModified = true;
302 }); 298 }
303 } 299 }
304 } 300 }
305 301
@@ -349,6 +345,7 @@ public sealed class BSTerrainManager
349 // with the same parameters as last time. 345 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 346 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
351 return lastHeight; 347 return lastHeight;
348 m_terrainModified = false;
352 349
353 lastHeightTX = tX; 350 lastHeightTX = tX;
354 lastHeightTY = tY; 351 lastHeightTY = tY;
@@ -358,20 +355,47 @@ public sealed class BSTerrainManager
358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 355 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); 356 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
360 357
361 BSTerrainPhys physTerrain; 358 lock (m_terrains)
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
363 { 359 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 360 BSTerrainPhys physTerrain;
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", 361 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); 362 {
363 ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ);
364 }
365 else
366 {
367 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
368 LogHeader, PhysicsScene.RegionName, tX, tY);
369 }
367 } 370 }
368 else 371 lastHeight = ret;
372 return ret;
373 }
374
375 public float GetWaterLevelAtXYZ(Vector3 pos)
376 {
377 float ret = WATER_HEIGHT_GETHEIGHT_RET;
378
379 float tX = pos.X;
380 float tY = pos.Y;
381
382 Vector3 terrainBaseXYZ = Vector3.Zero;
383 terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
384 terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
385
386 lock (m_terrains)
369 { 387 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 388 BSTerrainPhys physTerrain;
371 LogHeader, PhysicsScene.RegionName, tX, tY); 389 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
390 {
391 ret = physTerrain.GetWaterLevelAtXYZ(pos);
392 }
393 else
394 {
395 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
396 LogHeader, PhysicsScene.RegionName, tX, tY);
397 }
372 } 398 }
373 m_terrainModified = false;
374 lastHeight = ret;
375 return ret; 399 return ret;
376 } 400 }
377 401
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..7e93ab4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 88 // Something is very messed up and a crash is in our future.
89 return; 89 return;
90 } 90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
91 93
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
93 indicesCount, indices, verticesCount, vertices), 95 indicesCount, indices, verticesCount, vertices),
94 BSPhysicsShapeType.SHAPE_MESH); 96 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero) 97 if (m_terrainShape.ptr == IntPtr.Zero)
96 { 98 {
@@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys
122 // Static objects are not very massive. 124 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
124 126
125 // Return the new terrain to the world of physical objects 127 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
127 129
128 // redo its bounding box now that it is in the world 130 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
130 132
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 133 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
@@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
146 } 148 }
147 } 149 }
148 150
149 public override float GetHeightAtXYZ(Vector3 pos) 151 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 152 {
151 // For the moment use the saved heightmap to get the terrain height. 153 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 154 // TODO: raycast downward to find the true terrain below the position.
@@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 169 return ret;
168 } 170 }
169 171
172 // The passed position is relative to the base of the region.
173 public override float GetWaterLevelAtXYZ(Vector3 pos)
174 {
175 return PhysicsScene.SimpleWaterLevel;
176 }
177
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 178 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 179 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 180 public static bool ConvertHeightmapToMesh(
@@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 196 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 197 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 198
199 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
200 // from zero to <= sizeX). The triangle indices are then generated as two triangles
201 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
202 // column of vertices are used to complete the triangles of the last row and column
203 // of the heightmap.
191 try 204 try
192 { 205 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 206 // One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
200 float magY = (float)sizeY / extentY; 213 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 214 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 215 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
216 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 217 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++) 218 for (int yy = 0; yy <= sizeY; yy++)
205 { 219 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 220 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 221 {
208 int offset = yy * sizeX + xx; 222 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 223 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 224 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 225 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 226 float height = heightMap[offset];
227 minHeight = Math.Min(minHeight, height);
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 228 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 229 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 230 vertices[verticesCount + 2] = height + extentBase.Z;
@@ -217,14 +232,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
217 } 232 }
218 } 233 }
219 verticesCount = verticesCount / 3; 234 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 235
223 for (int yy = 0; yy < sizeY; yy++) 236 for (int yy = 0; yy < sizeY; yy++)
224 { 237 {
225 for (int xx = 0; xx < sizeX; xx++) 238 for (int xx = 0; xx < sizeX; xx++)
226 { 239 {
227 int offset = yy * sizeX + xx; 240 int offset = yy * (sizeX + 1) + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles 241 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset; 242 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1; 243 indices[indicesCount + 1] = offset + 1;
@@ -235,8 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 248 indicesCount += 6;
236 } 249 }
237 } 250 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG 251
239 LogHeader, indicesCount); // DEBUG
240 ret = true; 252 ret = true;
241 } 253 }
242 catch (Exception e) 254 catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index e60a760..1e003e6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -287,6 +287,8 @@ public struct ConfigurationParameters
287 public float terrainFriction; 287 public float terrainFriction;
288 public float terrainHitFraction; 288 public float terrainHitFraction;
289 public float terrainRestitution; 289 public float terrainRestitution;
290 public float terrainCollisionMargin;
291
290 public float avatarFriction; 292 public float avatarFriction;
291 public float avatarStandingFriction; 293 public float avatarStandingFriction;
292 public float avatarDensity; 294 public float avatarDensity;
@@ -296,6 +298,8 @@ public struct ConfigurationParameters
296 public float avatarCapsuleHeight; 298 public float avatarCapsuleHeight;
297 public float avatarContactProcessingThreshold; 299 public float avatarContactProcessingThreshold;
298 300
301 public float vehicleAngularDamping;
302
299 public float maxPersistantManifoldPoolSize; 303 public float maxPersistantManifoldPoolSize;
300 public float maxCollisionAlgorithmPoolSize; 304 public float maxCollisionAlgorithmPoolSize;
301 public float shouldDisableContactPoolDynamicAllocation; 305 public float shouldDisableContactPoolDynamicAllocation;
@@ -353,7 +357,7 @@ public enum CollisionFlags : uint
353 CF_CHARACTER_OBJECT = 1 << 4, 357 CF_CHARACTER_OBJECT = 1 << 4,
354 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 358 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
355 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 359 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
356 // Following used by BulletSim to control collisions 360 // Following used by BulletSim to control collisions and updates
357 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 361 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
358 BS_FLOATS_ON_WATER = 1 << 11, 362 BS_FLOATS_ON_WATER = 1 << 11,
359 BS_NONE = 0, 363 BS_NONE = 0,
@@ -482,6 +486,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
482public static extern bool IsNativeShape2(IntPtr shape); 486public static extern bool IsNativeShape2(IntPtr shape);
483 487
484[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]
485public 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);
486 493
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 494[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index f629c4d..9262a9e 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
321 321
322 if (primShape.SculptData.Length <= 0) 322 if (primShape.SculptData.Length <= 0)
323 { 323 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
325 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
326 // The first time will always call with unloaded SculptData if this needs to be uploaded.
324// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); 327// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
325 return false; 328 return false;
326 } 329 }
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index a59f63f..d09aa62 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
3367 _pbs.SculptData = new byte[asset.Data.Length]; 3367 _pbs.SculptData = new byte[asset.Data.Length];
3368 asset.Data.CopyTo(_pbs.SculptData, 0); 3368 asset.Data.CopyTo(_pbs.SculptData, 0);
3369// m_assetFailed = false; 3369// m_assetFailed = false;
3370
3371// m_log.DebugFormat(
3372// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3373// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3374
3370 m_taintshape = true; 3375 m_taintshape = true;
3371 _parent_scene.AddPhysicsActorTaint(this); 3376 _parent_scene.AddPhysicsActorTaint(this);
3372 } 3377 }