diff options
author | BlueWall | 2012-12-03 20:17:00 -0500 |
---|---|---|
committer | BlueWall | 2012-12-03 20:17:00 -0500 |
commit | 0c7d6adef158d5cb25d8eb60287c5cb0cceaa953 (patch) | |
tree | f766959f3442b78aa9202a4f61cf127508245345 | |
parent | XmlRpcGridRouter (diff) | |
parent | BulletSim: Reduce idle region physics overhead where there are MANY (diff) | |
download | opensim-SC_OLD-0c7d6adef158d5cb25d8eb60287c5cb0cceaa953.zip opensim-SC_OLD-0c7d6adef158d5cb25d8eb60287c5cb0cceaa953.tar.gz opensim-SC_OLD-0c7d6adef158d5cb25d8eb60287c5cb0cceaa953.tar.bz2 opensim-SC_OLD-0c7d6adef158d5cb25d8eb60287c5cb0cceaa953.tar.xz |
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
18 files changed, 578 insertions, 287 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 1dfc420..21aa9be 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -165,8 +165,8 @@ public sealed class BSCharacter : BSPhysObject | |||
165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
166 | 166 | ||
167 | // Do this after the object has been added to the world | 167 | // Do this after the object has been added to the world |
168 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | 168 | BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, |
169 | (uint)CollisionFilterGroups.AvatarFilter, | 169 | (uint)CollisionFilterGroups.AvatarGroup, |
170 | (uint)CollisionFilterGroups.AvatarMask); | 170 | (uint)CollisionFilterGroups.AvatarMask); |
171 | } | 171 | } |
172 | 172 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 3a73fba..be8a502 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -45,9 +45,7 @@ using System; | |||
45 | using System.Collections.Generic; | 45 | using System.Collections.Generic; |
46 | using System.Reflection; | 46 | using System.Reflection; |
47 | using System.Runtime.InteropServices; | 47 | using System.Runtime.InteropServices; |
48 | using log4net; | ||
49 | using OpenMetaverse; | 48 | using OpenMetaverse; |
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | 49 | using OpenSim.Region.Physics.Manager; |
52 | 50 | ||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | 51 | namespace OpenSim.Region.Physics.BulletSPlugin |
@@ -100,7 +98,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
100 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 98 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
101 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 99 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
102 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 100 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
103 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 101 | private Vector3 m_lastAngularCorrection = Vector3.Zero; |
104 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 102 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
105 | 103 | ||
106 | //Deflection properties | 104 | //Deflection properties |
@@ -113,6 +111,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
113 | private float m_bankingEfficiency = 0; | 111 | private float m_bankingEfficiency = 0; |
114 | private float m_bankingMix = 0; | 112 | private float m_bankingMix = 0; |
115 | private float m_bankingTimescale = 0; | 113 | private float m_bankingTimescale = 0; |
114 | private Vector3 m_lastBanking = Vector3.Zero; | ||
116 | 115 | ||
117 | //Hover and Buoyancy properties | 116 | //Hover and Buoyancy properties |
118 | private float m_VhoverHeight = 0f; | 117 | private float m_VhoverHeight = 0f; |
@@ -127,7 +126,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
127 | //Attractor properties | 126 | //Attractor properties |
128 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); | 127 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
129 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 128 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
130 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 129 | private float m_verticalAttractionTimescale = 600f; // Timescale > 500 means no vert attractor. |
131 | 130 | ||
132 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 131 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
133 | { | 132 | { |
@@ -154,7 +153,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
154 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 153 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
155 | break; | 154 | break; |
156 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 155 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
157 | m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); | 156 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
158 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | 157 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; |
159 | break; | 158 | break; |
160 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 159 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
@@ -162,7 +161,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
162 | m_angularMotor.TimeScale = m_angularMotorTimescale; | 161 | m_angularMotor.TimeScale = m_angularMotorTimescale; |
163 | break; | 162 | break; |
164 | case Vehicle.BANKING_EFFICIENCY: | 163 | case Vehicle.BANKING_EFFICIENCY: |
165 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 164 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); |
166 | break; | 165 | break; |
167 | case Vehicle.BANKING_MIX: | 166 | case Vehicle.BANKING_MIX: |
168 | m_bankingMix = Math.Max(pValue, 0.01f); | 167 | m_bankingMix = Math.Max(pValue, 0.01f); |
@@ -171,10 +170,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
171 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 170 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
172 | break; | 171 | break; |
173 | case Vehicle.BUOYANCY: | 172 | case Vehicle.BUOYANCY: |
174 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 173 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
175 | break; | 174 | break; |
176 | case Vehicle.HOVER_EFFICIENCY: | 175 | case Vehicle.HOVER_EFFICIENCY: |
177 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 176 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
178 | break; | 177 | break; |
179 | case Vehicle.HOVER_HEIGHT: | 178 | case Vehicle.HOVER_HEIGHT: |
180 | m_VhoverHeight = pValue; | 179 | m_VhoverHeight = pValue; |
@@ -189,7 +188,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
189 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 188 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
190 | break; | 189 | break; |
191 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 190 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
192 | m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); | 191 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
193 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | 192 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; |
194 | break; | 193 | break; |
195 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 194 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
@@ -197,7 +196,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
197 | m_linearMotor.TimeScale = m_linearMotorTimescale; | 196 | m_linearMotor.TimeScale = m_linearMotorTimescale; |
198 | break; | 197 | break; |
199 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 198 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
200 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 199 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); |
201 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | 200 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; |
202 | break; | 201 | break; |
203 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 202 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
@@ -242,9 +241,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
242 | break; | 241 | break; |
243 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 242 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
244 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 243 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
245 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | 244 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); |
246 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 245 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
247 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 246 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
248 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 247 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
249 | m_angularMotor.SetTarget(m_angularMotorDirection); | 248 | m_angularMotor.SetTarget(m_angularMotorDirection); |
250 | break; | 249 | break; |
@@ -330,6 +329,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
330 | m_bankingEfficiency = 0; | 329 | m_bankingEfficiency = 0; |
331 | m_bankingTimescale = 1000; | 330 | m_bankingTimescale = 1000; |
332 | m_bankingMix = 1; | 331 | m_bankingMix = 1; |
332 | m_lastBanking = Vector3.Zero; | ||
333 | 333 | ||
334 | m_referenceFrame = Quaternion.Identity; | 334 | m_referenceFrame = Quaternion.Identity; |
335 | m_flags = (VehicleFlag)0; | 335 | m_flags = (VehicleFlag)0; |
@@ -364,6 +364,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
364 | m_bankingEfficiency = 0; | 364 | m_bankingEfficiency = 0; |
365 | m_bankingTimescale = 10; | 365 | m_bankingTimescale = 10; |
366 | m_bankingMix = 1; | 366 | m_bankingMix = 1; |
367 | m_lastBanking = Vector3.Zero; | ||
367 | 368 | ||
368 | m_referenceFrame = Quaternion.Identity; | 369 | m_referenceFrame = Quaternion.Identity; |
369 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 370 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
@@ -402,6 +403,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
402 | m_bankingEfficiency = -0.2f; | 403 | m_bankingEfficiency = -0.2f; |
403 | m_bankingMix = 1; | 404 | m_bankingMix = 1; |
404 | m_bankingTimescale = 1; | 405 | m_bankingTimescale = 1; |
406 | m_lastBanking = Vector3.Zero; | ||
405 | 407 | ||
406 | m_referenceFrame = Quaternion.Identity; | 408 | m_referenceFrame = Quaternion.Identity; |
407 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 409 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
@@ -440,14 +442,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
440 | m_bankingEfficiency = -0.3f; | 442 | m_bankingEfficiency = -0.3f; |
441 | m_bankingMix = 0.8f; | 443 | m_bankingMix = 0.8f; |
442 | m_bankingTimescale = 1; | 444 | m_bankingTimescale = 1; |
445 | m_lastBanking = Vector3.Zero; | ||
443 | 446 | ||
444 | m_referenceFrame = Quaternion.Identity; | 447 | m_referenceFrame = Quaternion.Identity; |
445 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 448 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
446 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | 449 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
447 | | VehicleFlag.LIMIT_ROLL_ONLY | 450 | | VehicleFlag.LIMIT_ROLL_ONLY |
448 | | VehicleFlag.LIMIT_MOTOR_UP | ||
449 | | VehicleFlag.HOVER_UP_ONLY); | 451 | | VehicleFlag.HOVER_UP_ONLY); |
450 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 452 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
453 | | VehicleFlag.LIMIT_MOTOR_UP | ||
451 | | VehicleFlag.HOVER_WATER_ONLY); | 454 | | VehicleFlag.HOVER_WATER_ONLY); |
452 | break; | 455 | break; |
453 | case Vehicle.TYPE_AIRPLANE: | 456 | case Vehicle.TYPE_AIRPLANE: |
@@ -478,6 +481,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
478 | m_bankingEfficiency = 1; | 481 | m_bankingEfficiency = 1; |
479 | m_bankingMix = 0.7f; | 482 | m_bankingMix = 0.7f; |
480 | m_bankingTimescale = 2; | 483 | m_bankingTimescale = 2; |
484 | m_lastBanking = Vector3.Zero; | ||
481 | 485 | ||
482 | m_referenceFrame = Quaternion.Identity; | 486 | m_referenceFrame = Quaternion.Identity; |
483 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 487 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
@@ -516,6 +520,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
516 | m_bankingEfficiency = 0; | 520 | m_bankingEfficiency = 0; |
517 | m_bankingMix = 0.7f; | 521 | m_bankingMix = 0.7f; |
518 | m_bankingTimescale = 5; | 522 | m_bankingTimescale = 5; |
523 | m_lastBanking = Vector3.Zero; | ||
524 | |||
519 | m_referenceFrame = Quaternion.Identity; | 525 | m_referenceFrame = Quaternion.Identity; |
520 | 526 | ||
521 | m_referenceFrame = Quaternion.Identity; | 527 | m_referenceFrame = Quaternion.Identity; |
@@ -558,9 +564,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
558 | { | 564 | { |
559 | if (IsActive) | 565 | if (IsActive) |
560 | { | 566 | { |
567 | // Remember the mass so we don't have to fetch it every step | ||
561 | m_vehicleMass = Prim.Linkset.LinksetMass; | 568 | m_vehicleMass = Prim.Linkset.LinksetMass; |
562 | 569 | ||
563 | // Friction effects are handled by this vehicle code | 570 | // Friction affects are handled by this vehicle code |
564 | float friction = 0f; | 571 | float friction = 0f; |
565 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); | 572 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); |
566 | 573 | ||
@@ -574,6 +581,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
574 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); | 581 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); |
575 | Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); | 582 | Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); |
576 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | 583 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); |
584 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); | ||
577 | 585 | ||
578 | VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", | 586 | VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", |
579 | Prim.LocalID, friction, localInertia, angularDamping); | 587 | Prim.LocalID, friction, localInertia, angularDamping); |
@@ -598,31 +606,167 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
598 | Refresh(); | 606 | Refresh(); |
599 | } | 607 | } |
600 | 608 | ||
609 | #region Known vehicle value functions | ||
610 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
611 | // The "m_known*" variables are initialized to 'null', fetched only if referenced | ||
612 | // and stored back into the physics engine only if updated. | ||
613 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
614 | // 2) signals when a physics property update must happen back to the simulator | ||
615 | // to update values modified for the vehicle. | ||
616 | private int m_knownChanged; | ||
617 | private float? m_knownTerrainHeight; | ||
618 | private float? m_knownWaterLevel; | ||
619 | private Vector3? m_knownPosition; | ||
620 | private Vector3? m_knownVelocity; | ||
621 | private Quaternion? m_knownOrientation; | ||
622 | private Vector3? m_knownRotationalVelocity; | ||
623 | |||
624 | private const int m_knownChangedPosition = 1 << 0; | ||
625 | private const int m_knownChangedVelocity = 1 << 1; | ||
626 | private const int m_knownChangedOrientation = 1 << 2; | ||
627 | private const int m_knownChangedRotationalVelocity = 1 << 3; | ||
628 | |||
629 | private void ForgetKnownVehicleProperties() | ||
630 | { | ||
631 | m_knownTerrainHeight = null; | ||
632 | m_knownWaterLevel = null; | ||
633 | m_knownPosition = null; | ||
634 | m_knownVelocity = null; | ||
635 | m_knownOrientation = null; | ||
636 | m_knownRotationalVelocity = null; | ||
637 | m_knownChanged = 0; | ||
638 | } | ||
639 | private void PushKnownChanged() | ||
640 | { | ||
641 | if (m_knownChanged != 0) | ||
642 | { | ||
643 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
644 | Prim.ForcePosition = VehiclePosition; | ||
645 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
646 | Prim.ForceOrientation = VehicleOrientation; | ||
647 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
648 | Prim.ForceVelocity = VehicleVelocity; | ||
649 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
650 | { | ||
651 | Prim.ForceRotationalVelocity = VehicleRotationalVelocity; | ||
652 | BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity); | ||
653 | } | ||
654 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
655 | // an UpdateProperties event to send the changes up to the simulator. | ||
656 | BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | // Since the computation of terrain height can be a little involved, this routine | ||
661 | // is used ot fetch the height only once for each vehicle simulation step. | ||
662 | private float GetTerrainHeight(Vector3 pos) | ||
663 | { | ||
664 | if (m_knownTerrainHeight == null) | ||
665 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
666 | return (float)m_knownTerrainHeight; | ||
667 | } | ||
668 | |||
669 | // Since the computation of water level can be a little involved, this routine | ||
670 | // is used ot fetch the level only once for each vehicle simulation step. | ||
671 | private float GetWaterLevel(Vector3 pos) | ||
672 | { | ||
673 | if (m_knownWaterLevel == null) | ||
674 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
675 | return (float)m_knownWaterLevel; | ||
676 | } | ||
677 | |||
678 | private Vector3 VehiclePosition | ||
679 | { | ||
680 | get | ||
681 | { | ||
682 | if (m_knownPosition == null) | ||
683 | m_knownPosition = Prim.ForcePosition; | ||
684 | return (Vector3)m_knownPosition; | ||
685 | } | ||
686 | set | ||
687 | { | ||
688 | m_knownPosition = value; | ||
689 | m_knownChanged |= m_knownChangedPosition; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | private Quaternion VehicleOrientation | ||
694 | { | ||
695 | get | ||
696 | { | ||
697 | if (m_knownOrientation == null) | ||
698 | m_knownOrientation = Prim.ForceOrientation; | ||
699 | return (Quaternion)m_knownOrientation; | ||
700 | } | ||
701 | set | ||
702 | { | ||
703 | m_knownOrientation = value; | ||
704 | m_knownChanged |= m_knownChangedOrientation; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | private Vector3 VehicleVelocity | ||
709 | { | ||
710 | get | ||
711 | { | ||
712 | if (m_knownVelocity == null) | ||
713 | m_knownVelocity = Prim.ForceVelocity; | ||
714 | return (Vector3)m_knownVelocity; | ||
715 | } | ||
716 | set | ||
717 | { | ||
718 | m_knownVelocity = value; | ||
719 | m_knownChanged |= m_knownChangedVelocity; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | private Vector3 VehicleRotationalVelocity | ||
724 | { | ||
725 | get | ||
726 | { | ||
727 | if (m_knownRotationalVelocity == null) | ||
728 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
729 | return (Vector3)m_knownRotationalVelocity; | ||
730 | } | ||
731 | set | ||
732 | { | ||
733 | m_knownRotationalVelocity = value; | ||
734 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
735 | } | ||
736 | } | ||
737 | #endregion // Known vehicle value functions | ||
738 | |||
601 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 739 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
602 | internal void Step(float pTimestep) | 740 | internal void Step(float pTimestep) |
603 | { | 741 | { |
604 | if (!IsActive) return; | 742 | if (!IsActive) return; |
605 | 743 | ||
744 | ForgetKnownVehicleProperties(); | ||
745 | |||
606 | MoveLinear(pTimestep); | 746 | MoveLinear(pTimestep); |
607 | MoveAngular(pTimestep); | 747 | MoveAngular(pTimestep); |
608 | 748 | ||
609 | LimitRotation(pTimestep); | 749 | LimitRotation(pTimestep); |
610 | 750 | ||
611 | // remember the position so next step we can limit absolute movement effects | 751 | // remember the position so next step we can limit absolute movement effects |
612 | m_lastPositionVector = Prim.ForcePosition; | 752 | m_lastPositionVector = VehiclePosition; |
753 | |||
754 | // If we forced the changing of some vehicle parameters, update the values and | ||
755 | // for the physics engine to note the changes so an UpdateProperties event will happen. | ||
756 | PushKnownChanged(); | ||
613 | 757 | ||
614 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 758 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
615 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 759 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); |
616 | } | 760 | } |
617 | 761 | ||
618 | // Apply the effect of the linear motor. | 762 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
619 | // Also does hover and float. | ||
620 | private void MoveLinear(float pTimestep) | 763 | private void MoveLinear(float pTimestep) |
621 | { | 764 | { |
622 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); | 765 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); |
623 | 766 | ||
624 | // Rotate new object velocity from vehicle relative to world coordinates | 767 | // The movement computed in the linear motor is relative to the vehicle |
625 | linearMotorContribution *= Prim.ForceOrientation; | 768 | // coordinates. Rotate the movement to world coordinates. |
769 | linearMotorContribution *= VehicleOrientation; | ||
626 | 770 | ||
627 | // ================================================================== | 771 | // ================================================================== |
628 | // Gravity and Buoyancy | 772 | // Gravity and Buoyancy |
@@ -630,16 +774,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
630 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 774 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
631 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 775 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); |
632 | 776 | ||
633 | Vector3 pos = Prim.ForcePosition; | 777 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); |
634 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
635 | |||
636 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight); | ||
637 | 778 | ||
638 | Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight); | 779 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); |
639 | 780 | ||
640 | ComputeLinearBlockingEndPoint(pTimestep, ref pos); | 781 | ComputeLinearBlockingEndPoint(pTimestep); |
641 | 782 | ||
642 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight); | 783 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); |
643 | 784 | ||
644 | // ================================================================== | 785 | // ================================================================== |
645 | Vector3 newVelocity = linearMotorContribution | 786 | Vector3 newVelocity = linearMotorContribution |
@@ -667,42 +808,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
667 | newVelocity = Vector3.Zero; | 808 | newVelocity = Vector3.Zero; |
668 | 809 | ||
669 | // ================================================================== | 810 | // ================================================================== |
670 | // Stuff new linear velocity into the vehicle | 811 | // Stuff new linear velocity into the vehicle. |
671 | Prim.ForceVelocity = newVelocity; | 812 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. |
672 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | 813 | VehicleVelocity = newVelocity; |
673 | 814 | ||
674 | // Other linear forces are applied as forces. | 815 | // Other linear forces are applied as forces. |
675 | Vector3 totalDownForce = grav * m_vehicleMass; | 816 | Vector3 totalDownForce = grav * m_vehicleMass * pTimestep; |
676 | if (totalDownForce != Vector3.Zero) | 817 | if (totalDownForce != Vector3.Zero) |
677 | { | 818 | { |
678 | Prim.AddForce(totalDownForce, false); | 819 | Prim.AddForce(totalDownForce, false); |
679 | } | 820 | } |
680 | 821 | ||
681 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | 822 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},linContrib={3},terrContrib={4},hoverContrib={5},limitContrib={6}", |
682 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, | 823 | Prim.LocalID, newVelocity, totalDownForce, |
683 | newVelocity, Prim.Velocity, totalDownForce); | 824 | linearMotorContribution, terrainHeightContribution, hoverContribution, limitMotorUpContribution |
825 | ); | ||
684 | 826 | ||
685 | } // end MoveLinear() | 827 | } // end MoveLinear() |
686 | 828 | ||
687 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight) | 829 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) |
688 | { | 830 | { |
689 | Vector3 ret = Vector3.Zero; | 831 | Vector3 ret = Vector3.Zero; |
690 | // If below the terrain, move us above the ground a little. | 832 | // If below the terrain, move us above the ground a little. |
691 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 833 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
692 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | 834 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
693 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
694 | // if (rotatedSize.Z < terrainHeight) | ||
695 | if (pos.Z < terrainHeight) | ||
696 | { | 835 | { |
697 | // TODO: correct position by applying force rather than forcing position. | 836 | // TODO: correct position by applying force rather than forcing position. |
698 | pos.Z = terrainHeight + 2; | 837 | VehiclePosition += new Vector3(0f, 0f, GetTerrainHeight(VehiclePosition) + 2f); |
699 | Prim.ForcePosition = pos; | 838 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); |
700 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | ||
701 | } | 839 | } |
702 | return ret; | 840 | return ret; |
703 | } | 841 | } |
704 | 842 | ||
705 | public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight) | 843 | public Vector3 ComputeLinearHover(float pTimestep) |
706 | { | 844 | { |
707 | Vector3 ret = Vector3.Zero; | 845 | Vector3 ret = Vector3.Zero; |
708 | 846 | ||
@@ -713,11 +851,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
713 | // We should hover, get the target height | 851 | // We should hover, get the target height |
714 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 852 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
715 | { | 853 | { |
716 | m_VhoverTargetHeight = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 854 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; |
717 | } | 855 | } |
718 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 856 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
719 | { | 857 | { |
720 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 858 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; |
721 | } | 859 | } |
722 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 860 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
723 | { | 861 | { |
@@ -727,46 +865,44 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
727 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 865 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
728 | { | 866 | { |
729 | // If body is already heigher, use its height as target height | 867 | // If body is already heigher, use its height as target height |
730 | if (pos.Z > m_VhoverTargetHeight) | 868 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
731 | m_VhoverTargetHeight = pos.Z; | 869 | m_VhoverTargetHeight = VehiclePosition.Z; |
732 | } | 870 | } |
733 | 871 | ||
734 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 872 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
735 | { | 873 | { |
736 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 874 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
737 | { | 875 | { |
876 | Vector3 pos = VehiclePosition; | ||
738 | pos.Z = m_VhoverTargetHeight; | 877 | pos.Z = m_VhoverTargetHeight; |
739 | Prim.ForcePosition = pos; | 878 | VehiclePosition = pos; |
740 | } | 879 | } |
741 | } | 880 | } |
742 | else | 881 | else |
743 | { | 882 | { |
744 | float verticalError = pos.Z - m_VhoverTargetHeight; | 883 | // Error is positive if below the target and negative if above. |
745 | // RA: where does the 50 come from? | 884 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; |
746 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 885 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
747 | // Replace Vertical speed with correction figure if significant | 886 | |
748 | if (verticalError > 0.01f) | 887 | // TODO: implement m_VhoverEfficiency correctly |
888 | if (Math.Abs(verticalError) > m_VhoverEfficiency) | ||
749 | { | 889 | { |
750 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); | 890 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); |
751 | //KF: m_VhoverEfficiency is not yet implemented | ||
752 | } | ||
753 | else if (verticalError < -0.01) | ||
754 | { | ||
755 | ret = new Vector3(0f, 0f, -verticalCorrectionVelocity); | ||
756 | } | 891 | } |
757 | } | 892 | } |
758 | 893 | ||
759 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", | 894 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", |
760 | Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight); | 895 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); |
761 | } | 896 | } |
762 | 897 | ||
763 | return ret; | 898 | return ret; |
764 | } | 899 | } |
765 | 900 | ||
766 | public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos) | 901 | public bool ComputeLinearBlockingEndPoint(float pTimestep) |
767 | { | 902 | { |
768 | bool changed = false; | 903 | bool changed = false; |
769 | 904 | ||
905 | Vector3 pos = VehiclePosition; | ||
770 | Vector3 posChange = pos - m_lastPositionVector; | 906 | Vector3 posChange = pos - m_lastPositionVector; |
771 | if (m_BlockingEndPoint != Vector3.Zero) | 907 | if (m_BlockingEndPoint != Vector3.Zero) |
772 | { | 908 | { |
@@ -797,8 +933,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
797 | } | 933 | } |
798 | if (changed) | 934 | if (changed) |
799 | { | 935 | { |
800 | Prim.ForcePosition = pos; | 936 | VehiclePosition = pos; |
801 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 937 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
802 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 938 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
803 | } | 939 | } |
804 | } | 940 | } |
@@ -812,13 +948,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
812 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | 948 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering |
813 | // when they are in mid jump. | 949 | // when they are in mid jump. |
814 | // TODO: this code is wrong. Also, what should it do for boats? | 950 | // TODO: this code is wrong. Also, what should it do for boats? |
815 | public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight) | 951 | public Vector3 ComputeLinearMotorUp(float pTimestep) |
816 | { | 952 | { |
817 | Vector3 ret = Vector3.Zero; | 953 | Vector3 ret = Vector3.Zero; |
818 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 954 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
819 | { | 955 | { |
820 | // If the vehicle is motoring into the sky, get it going back down. | 956 | // If the vehicle is motoring into the sky, get it going back down. |
821 | float distanceAboveGround = pos.Z - terrainHeight; | 957 | // float distanceAboveGround = pos.Z - Math.Max(GetTerrainHeight(pos), GetWaterLevel(pos)); |
958 | float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition); | ||
822 | if (distanceAboveGround > 1f) | 959 | if (distanceAboveGround > 1f) |
823 | { | 960 | { |
824 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | 961 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); |
@@ -830,7 +967,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
830 | // has a decay factor. This says this force should | 967 | // has a decay factor. This says this force should |
831 | // be computed with a motor. | 968 | // be computed with a motor. |
832 | // TODO: add interaction with banking. | 969 | // TODO: add interaction with banking. |
833 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 970 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},downForce={2}", |
834 | Prim.LocalID, distanceAboveGround, ret); | 971 | Prim.LocalID, distanceAboveGround, ret); |
835 | } | 972 | } |
836 | return ret; | 973 | return ret; |
@@ -839,36 +976,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
839 | // ======================================================================= | 976 | // ======================================================================= |
840 | // ======================================================================= | 977 | // ======================================================================= |
841 | // Apply the effect of the angular motor. | 978 | // Apply the effect of the angular motor. |
979 | // The 'contribution' is how much angular correction velocity each function wants. | ||
980 | // All the contributions are added together and the orientation of the vehicle | ||
981 | // is changed by all the contributed corrections. | ||
842 | private void MoveAngular(float pTimestep) | 982 | private void MoveAngular(float pTimestep) |
843 | { | 983 | { |
844 | // m_angularMotorDirection // angular velocity requested by LSL motor | 984 | // The user wants how many radians per second angular change? |
845 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | ||
846 | // m_angularMotorTimescale // motor angular velocity ramp up time | ||
847 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | ||
848 | // m_angularFrictionTimescale // body angular velocity decay rate | ||
849 | // m_lastAngularVelocity // what was last applied to body | ||
850 | |||
851 | /* | ||
852 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | ||
853 | { | ||
854 | Vector3 origVel = m_angularMotorVelocity; | ||
855 | Vector3 origDir = m_angularMotorDirection; | ||
856 | |||
857 | // new velocity += error / ( time to get there / step interval) | ||
858 | // requested direction - current vehicle direction | ||
859 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
860 | // decay requested direction | ||
861 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
862 | |||
863 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | ||
864 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | ||
865 | } | ||
866 | else | ||
867 | { | ||
868 | m_angularMotorVelocity = Vector3.Zero; | ||
869 | } | ||
870 | */ | ||
871 | |||
872 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); | 985 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
873 | 986 | ||
874 | // ================================================================== | 987 | // ================================================================== |
@@ -881,25 +994,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
881 | { | 994 | { |
882 | angularMotorContribution.X = 0f; | 995 | angularMotorContribution.X = 0f; |
883 | angularMotorContribution.Y = 0f; | 996 | angularMotorContribution.Y = 0f; |
884 | VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | 997 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); |
885 | } | 998 | } |
886 | 999 | ||
887 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep); | 1000 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); |
888 | 1001 | ||
889 | Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep); | 1002 | Vector3 deflectionContribution = ComputeAngularDeflection(); |
890 | 1003 | ||
891 | Vector3 bankingContribution = ComputeAngularBanking(pTimestep); | 1004 | Vector3 bankingContribution = ComputeAngularBanking(angularMotorContribution.Z); |
892 | 1005 | ||
893 | // ================================================================== | 1006 | // ================================================================== |
894 | m_lastVertAttractor = verticalAttractionContribution; | 1007 | m_lastVertAttractor = verticalAttractionContribution; |
895 | 1008 | ||
896 | // Sum velocities | 1009 | // Sum corrections |
897 | m_lastAngularVelocity = angularMotorContribution | 1010 | m_lastAngularCorrection = angularMotorContribution |
898 | + verticalAttractionContribution | 1011 | + verticalAttractionContribution |
899 | + deflectionContribution | 1012 | + deflectionContribution |
900 | + bankingContribution; | 1013 | + bankingContribution; |
901 | 1014 | ||
902 | // ================================================================== | 1015 | // ================================================================== |
1016 | // The correction is applied to the current orientation. | ||
1017 | if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f)) | ||
1018 | { | ||
1019 | Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep; | ||
1020 | |||
1021 | VehicleRotationalVelocity = scaledCorrection; | ||
1022 | |||
1023 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}", | ||
1024 | Prim.LocalID, | ||
1025 | angularMotorContribution, verticalAttractionContribution, | ||
1026 | bankingContribution, deflectionContribution, | ||
1027 | m_lastAngularCorrection, scaledCorrection | ||
1028 | ); | ||
1029 | } | ||
1030 | else | ||
1031 | { | ||
1032 | // The vehicle is not adding anything velocity wise. | ||
1033 | VehicleRotationalVelocity = Vector3.Zero; | ||
1034 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); | ||
1035 | } | ||
1036 | |||
1037 | // ================================================================== | ||
903 | //Offset section | 1038 | //Offset section |
904 | if (m_linearMotorOffset != Vector3.Zero) | 1039 | if (m_linearMotorOffset != Vector3.Zero) |
905 | { | 1040 | { |
@@ -927,53 +1062,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
927 | torqueFromOffset.Z = 0; | 1062 | torqueFromOffset.Z = 0; |
928 | torqueFromOffset *= m_vehicleMass; | 1063 | torqueFromOffset *= m_vehicleMass; |
929 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | 1064 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); |
930 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1065 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); |
931 | } | 1066 | } |
932 | 1067 | ||
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 | ||
942 | { | ||
943 | // Apply to the body. | ||
944 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | ||
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 | } | 1068 | } |
961 | 1069 | ||
962 | public Vector3 ComputeAngularVerticalAttraction(float pTimestep) | 1070 | public Vector3 ComputeAngularVerticalAttraction() |
963 | { | 1071 | { |
964 | Vector3 ret = Vector3.Zero; | 1072 | Vector3 ret = Vector3.Zero; |
965 | 1073 | ||
966 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | 1074 | // If vertical attaction timescale is reasonable and we applied an angular force last time... |
967 | if (m_verticalAttractionTimescale < 500) | 1075 | if (m_verticalAttractionTimescale < 500) |
968 | { | 1076 | { |
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. | 1077 | // Take a vector pointing up and convert it from world to vehicle relative coords. |
976 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | 1078 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; |
977 | verticalError.Normalize(); | 1079 | verticalError.Normalize(); |
978 | 1080 | ||
979 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | 1081 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) |
@@ -991,63 +1093,70 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
991 | } | 1093 | } |
992 | 1094 | ||
993 | // Y error means needed rotation around X axis and visa versa. | 1095 | // Y error means needed rotation around X axis and visa versa. |
994 | verticalAttractionContribution.X = verticalError.Y; | 1096 | ret.X = verticalError.Y; |
995 | verticalAttractionContribution.Y = - verticalError.X; | 1097 | ret.Y = - verticalError.X; |
996 | verticalAttractionContribution.Z = 0f; | 1098 | ret.Z = 0f; |
997 | 1099 | ||
998 | // scale by the time scale and timestep | 1100 | // scale by the time scale and timestep |
999 | Vector3 unscaledContrib = verticalAttractionContribution; | 1101 | Vector3 unscaledContrib = ret; |
1000 | verticalAttractionContribution /= m_verticalAttractionTimescale; | 1102 | ret /= m_verticalAttractionTimescale; |
1001 | verticalAttractionContribution *= pTimestep; | 1103 | // This returns the angular correction desired. Timestep is added later. |
1104 | // ret *= pTimestep; | ||
1002 | 1105 | ||
1003 | // apply efficiency | 1106 | // apply efficiency |
1004 | Vector3 preEfficiencyContrib = verticalAttractionContribution; | 1107 | Vector3 preEfficiencyContrib = ret; |
1108 | // TODO: implement efficiency. | ||
1109 | // Effenciency squared seems to give a more realistic effect | ||
1005 | float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency; | 1110 | float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency; |
1006 | verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 1111 | // ret *= efficencySquared; |
1007 | 1112 | ||
1008 | VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}", | 1113 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}", |
1009 | Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib, | 1114 | Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib, |
1010 | m_verticalAttractionEfficiency, efficencySquared, | 1115 | m_verticalAttractionEfficiency, efficencySquared, |
1011 | verticalAttractionContribution); | 1116 | ret); |
1012 | */ | ||
1013 | |||
1014 | } | 1117 | } |
1015 | return ret; | 1118 | return ret; |
1016 | } | 1119 | } |
1017 | 1120 | ||
1018 | public Vector3 ComputeAngularDeflection(float pTimestep) | 1121 | // Return the angular correction to correct the direction the vehicle is pointing to be |
1122 | // the direction is should want to be pointing. | ||
1123 | public Vector3 ComputeAngularDeflection() | ||
1019 | { | 1124 | { |
1020 | Vector3 ret = Vector3.Zero; | 1125 | Vector3 ret = Vector3.Zero; |
1021 | 1126 | ||
1022 | if (m_angularDeflectionEfficiency != 0) | 1127 | if (m_angularDeflectionEfficiency != 0) |
1023 | { | 1128 | { |
1024 | // Compute a scaled vector that points in the preferred axis (X direction) | 1129 | // Where the vehicle should want to point relative to the vehicle |
1025 | Vector3 scaledDefaultDirection = | 1130 | Vector3 preferredDirection = Vector3.UnitX * m_referenceFrame; |
1026 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
1027 | // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. | ||
1028 | // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. | ||
1029 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
1030 | 1131 | ||
1031 | // Scale by efficiency and timescale | 1132 | // Where the vehicle is pointing relative to the vehicle. |
1032 | ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | 1133 | Vector3 currentDirection = Vector3.UnitX * Quaternion.Add(VehicleOrientation, m_referenceFrame); |
1033 | 1134 | ||
1034 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret); | 1135 | // Difference between where vehicle is pointing and where it should wish to point |
1136 | Vector3 directionCorrection = preferredDirection - currentDirection; | ||
1035 | 1137 | ||
1036 | // This deflection computation is not correct. | 1138 | // Scale the correction by recovery timescale and efficiency |
1037 | ret = Vector3.Zero; | 1139 | ret = directionCorrection * m_angularDeflectionEfficiency / m_angularDeflectionTimescale; |
1140 | |||
1141 | VDetailLog("{0}, MoveAngular,Deflection,perfDir={1},currentDir={2},dirCorrection={3},ret={4}", | ||
1142 | Prim.LocalID, preferredDirection, currentDirection, directionCorrection, ret); | ||
1038 | } | 1143 | } |
1039 | return ret; | 1144 | return ret; |
1040 | } | 1145 | } |
1041 | 1146 | ||
1042 | public Vector3 ComputeAngularBanking(float pTimestep) | 1147 | // Return an angular change to tip the vehicle (around X axis) when turning (turned around Z). |
1148 | // Remembers the last banking value calculated and returns the difference needed this tick. | ||
1149 | // TurningFactor is rate going left or right (pos=left, neg=right, scale=0..1). | ||
1150 | public Vector3 ComputeAngularBanking(float turningFactor) | ||
1043 | { | 1151 | { |
1044 | Vector3 ret = Vector3.Zero; | 1152 | Vector3 ret = Vector3.Zero; |
1153 | Vector3 computedBanking = Vector3.Zero; | ||
1045 | 1154 | ||
1046 | if (m_bankingEfficiency != 0) | 1155 | if (m_bankingEfficiency != 0) |
1047 | { | 1156 | { |
1048 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1157 | Vector3 currentDirection = Vector3.UnitX * VehicleOrientation; |
1158 | |||
1049 | float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1); | 1159 | float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1); |
1050 | //Changes which way it banks in and out of turns | ||
1051 | 1160 | ||
1052 | //Use the square of the efficiency, as it looks much more how SL banking works | 1161 | //Use the square of the efficiency, as it looks much more how SL banking works |
1053 | float effSquared = (m_bankingEfficiency * m_bankingEfficiency); | 1162 | float effSquared = (m_bankingEfficiency * m_bankingEfficiency); |
@@ -1055,58 +1164,34 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1055 | effSquared *= -1; //Keep the negative! | 1164 | effSquared *= -1; //Keep the negative! |
1056 | 1165 | ||
1057 | float mix = Math.Abs(m_bankingMix); | 1166 | float mix = Math.Abs(m_bankingMix); |
1058 | if (m_angularMotorVelocity.X == 0) | 1167 | // TODO: Must include reference frame. |
1059 | { | 1168 | float forwardSpeed = VehicleVelocity.X; |
1060 | // The vehicle is stopped | ||
1061 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
1062 | { | ||
1063 | Vector3 axisAngle; | ||
1064 | float angle; | ||
1065 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
1066 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
1067 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
1068 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
1069 | else | ||
1070 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
1071 | }*/ | ||
1072 | } | ||
1073 | else | ||
1074 | { | ||
1075 | ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4; | ||
1076 | } | ||
1077 | 1169 | ||
1078 | //If they are colliding, we probably shouldn't shove the prim around... probably | 1170 | if (!Prim.IsColliding && forwardSpeed > mix) |
1079 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
1080 | { | 1171 | { |
1081 | float angVelZ = m_angularMotorVelocity.X * -1; | 1172 | computedBanking.X = ClampInRange(-3f, turningFactor * (effSquared * mult), 3f); |
1082 | /*if(angVelZ > mix) | ||
1083 | angVelZ = mix; | ||
1084 | else if(angVelZ < -mix) | ||
1085 | angVelZ = -mix;*/ | ||
1086 | //This controls how fast and how far the banking occurs | ||
1087 | Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0); | ||
1088 | if (bankingRot.X > 3) | ||
1089 | bankingRot.X = 3; | ||
1090 | else if (bankingRot.X < -3) | ||
1091 | bankingRot.X = -3; | ||
1092 | bankingRot *= Prim.ForceOrientation; | ||
1093 | ret += bankingRot; | ||
1094 | } | 1173 | } |
1095 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | 1174 | |
1096 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}", | 1175 | // 'computedBanking' is now how much banking that should be happening. |
1097 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret); | 1176 | ret = computedBanking - m_lastBanking; |
1177 | |||
1178 | // Scale the correction by timescale and efficiency | ||
1179 | ret /= m_bankingTimescale * m_bankingEfficiency; | ||
1180 | |||
1181 | VDetailLog("{0}, MoveAngular,Banking,computedB={1},lastB={2},bEff={3},effSq={4},mult={5},mix={6},banking={7}", | ||
1182 | Prim.LocalID, computedBanking, m_lastBanking, m_bankingEfficiency, effSquared, mult, mix, ret); | ||
1098 | } | 1183 | } |
1184 | m_lastBanking = computedBanking; | ||
1099 | return ret; | 1185 | return ret; |
1100 | } | 1186 | } |
1101 | 1187 | ||
1102 | |||
1103 | // This is from previous instantiations of XXXDynamics.cs. | 1188 | // This is from previous instantiations of XXXDynamics.cs. |
1104 | // Applies roll reference frame. | 1189 | // Applies roll reference frame. |
1105 | // TODO: is this the right way to separate the code to do this operation? | 1190 | // TODO: is this the right way to separate the code to do this operation? |
1106 | // Should this be in MoveAngular()? | 1191 | // Should this be in MoveAngular()? |
1107 | internal void LimitRotation(float timestep) | 1192 | internal void LimitRotation(float timestep) |
1108 | { | 1193 | { |
1109 | Quaternion rotq = Prim.ForceOrientation; | 1194 | Quaternion rotq = VehicleOrientation; |
1110 | Quaternion m_rot = rotq; | 1195 | Quaternion m_rot = rotq; |
1111 | if (m_RollreferenceFrame != Quaternion.Identity) | 1196 | if (m_RollreferenceFrame != Quaternion.Identity) |
1112 | { | 1197 | { |
@@ -1134,12 +1219,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1134 | } | 1219 | } |
1135 | if (rotq != m_rot) | 1220 | if (rotq != m_rot) |
1136 | { | 1221 | { |
1137 | Prim.ForceOrientation = m_rot; | 1222 | VehicleOrientation = m_rot; |
1138 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1223 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); |
1139 | } | 1224 | } |
1140 | 1225 | ||
1141 | } | 1226 | } |
1142 | 1227 | ||
1228 | private float ClampInRange(float low, float val, float high) | ||
1229 | { | ||
1230 | return Math.Max(low, Math.Min(val, high)); | ||
1231 | } | ||
1232 | |||
1143 | // Invoke the detailed logger and output something if it's enabled. | 1233 | // Invoke the detailed logger and output something if it's enabled. |
1144 | private void VDetailLog(string msg, params Object[] args) | 1234 | private void VDetailLog(string msg, params Object[] args) |
1145 | { | 1235 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index e91bfa8..851d508 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,3 +1,30 @@ | |||
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 copyright | ||
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 | * | ||
27 | */ | ||
1 | using System; | 28 | using System; |
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Text; | 30 | using System.Text; |
@@ -8,7 +35,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
8 | public abstract class BSMotor | 35 | public abstract class BSMotor |
9 | { | 36 | { |
10 | // Timescales and other things can be turned off by setting them to 'infinite'. | 37 | // Timescales and other things can be turned off by setting them to 'infinite'. |
11 | public const float Infinite = 10000f; | 38 | public const float Infinite = 12345f; |
12 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); | 39 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); |
13 | 40 | ||
14 | public BSMotor(string useName) | 41 | public BSMotor(string useName) |
@@ -19,7 +46,9 @@ public abstract class BSMotor | |||
19 | public virtual void Reset() { } | 46 | public virtual void Reset() { } |
20 | public virtual void Zero() { } | 47 | public virtual void Zero() { } |
21 | 48 | ||
49 | // A name passed at motor creation for easily identifyable debugging messages. | ||
22 | public string UseName { get; private set; } | 50 | public string UseName { get; private set; } |
51 | |||
23 | // Used only for outputting debug information. Might not be set so check for null. | 52 | // Used only for outputting debug information. Might not be set so check for null. |
24 | public BSScene PhysicsScene { get; set; } | 53 | public BSScene PhysicsScene { get; set; } |
25 | protected void MDetailLog(string msg, params Object[] parms) | 54 | protected void MDetailLog(string msg, params Object[] parms) |
@@ -34,10 +63,23 @@ public abstract class BSMotor | |||
34 | } | 63 | } |
35 | } | 64 | } |
36 | // Can all the incremental stepping be replaced with motor classes? | 65 | // Can all the incremental stepping be replaced with motor classes? |
66 | |||
67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. | ||
68 | // The TargetValue is decays in TargetValueDecayTimeScale and | ||
69 | // the CurrentValue will be held back by FrictionTimeScale. | ||
70 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay. | ||
71 | |||
72 | // For instance, if something is moving at speed X and the desired speed is Y, | ||
73 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new | ||
74 | // values of CurrentValue are returned that approach the TargetValue. | ||
75 | // The feature of decaying TargetValue is so vehicles will eventually | ||
76 | // come to a stop rather than run forever. This can be disabled by | ||
77 | // setting TargetValueDecayTimescale to 'infinite'. | ||
78 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. | ||
37 | public class BSVMotor : BSMotor | 79 | public class BSVMotor : BSMotor |
38 | { | 80 | { |
39 | public Vector3 FrameOfReference { get; set; } | 81 | // public Vector3 FrameOfReference { get; set; } |
40 | public Vector3 Offset { get; set; } | 82 | // public Vector3 Offset { get; set; } |
41 | 83 | ||
42 | public float TimeScale { get; set; } | 84 | public float TimeScale { get; set; } |
43 | public float TargetValueDecayTimeScale { get; set; } | 85 | public float TargetValueDecayTimeScale { get; set; } |
@@ -72,6 +114,14 @@ public class BSVMotor : BSMotor | |||
72 | { | 114 | { |
73 | TargetValue = target; | 115 | TargetValue = target; |
74 | } | 116 | } |
117 | |||
118 | // A form of stepping that does not take the time quantum into account. | ||
119 | // The caller must do the right thing later. | ||
120 | public Vector3 Step() | ||
121 | { | ||
122 | return Step(1f); | ||
123 | } | ||
124 | |||
75 | public Vector3 Step(float timeStep) | 125 | public Vector3 Step(float timeStep) |
76 | { | 126 | { |
77 | Vector3 returnCurrent = Vector3.Zero; | 127 | Vector3 returnCurrent = Vector3.Zero; |
@@ -99,18 +149,19 @@ public class BSVMotor : BSMotor | |||
99 | if (FrictionTimescale != BSMotor.InfiniteVector) | 149 | if (FrictionTimescale != BSMotor.InfiniteVector) |
100 | { | 150 | { |
101 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | 151 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; |
152 | // Individual friction components can be 'infinite' so compute each separately. | ||
102 | frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep; | 153 | frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep; |
103 | frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep; | 154 | frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep; |
104 | frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep; | 155 | frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep; |
105 | CurrentValue *= (Vector3.One - frictionFactor); | 156 | CurrentValue *= (Vector3.One - frictionFactor); |
106 | } | 157 | } |
107 | 158 | ||
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}", | 159 | 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, | 160 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
110 | timeStep, TimeScale, addAmount, | 161 | timeStep, TimeScale, addAmount, |
111 | TargetValueDecayTimeScale, decayFactor, | 162 | TargetValueDecayTimeScale, decayFactor, |
112 | FrictionTimescale, frictionFactor); | 163 | FrictionTimescale, frictionFactor); |
113 | MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", | 164 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", |
114 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, | 165 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, |
115 | addAmount, decayFactor, frictionFactor, returnCurrent); | 166 | addAmount, decayFactor, frictionFactor, returnCurrent); |
116 | } | 167 | } |
@@ -120,7 +171,7 @@ public class BSVMotor : BSMotor | |||
120 | CurrentValue = Vector3.Zero; | 171 | CurrentValue = Vector3.Zero; |
121 | TargetValue = Vector3.Zero; | 172 | TargetValue = Vector3.Zero; |
122 | 173 | ||
123 | MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", | 174 | MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", |
124 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); | 175 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); |
125 | 176 | ||
126 | } | 177 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 3fb0300..ea1f71a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -348,7 +348,9 @@ public sealed class BSPrim : BSPhysObject | |||
348 | if (ret) | 348 | if (ret) |
349 | { | 349 | { |
350 | // Apply upforce and overcome gravity. | 350 | // Apply upforce and overcome gravity. |
351 | AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime); | 351 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; |
352 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | ||
353 | AddForce(correctionForce, false, inTaintTime); | ||
352 | } | 354 | } |
353 | return ret; | 355 | return ret; |
354 | } | 356 | } |
@@ -644,9 +646,13 @@ public sealed class BSPrim : BSPhysObject | |||
644 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 646 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
645 | 647 | ||
646 | // Collision filter can be set only when the object is in the world | 648 | // Collision filter can be set only when the object is in the world |
647 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | 649 | if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0) |
648 | { | 650 | { |
649 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | 651 | if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask)) |
652 | { | ||
653 | PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}", | ||
654 | LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask); | ||
655 | } | ||
650 | } | 656 | } |
651 | 657 | ||
652 | // Recompute any linkset parameters. | 658 | // Recompute any linkset parameters. |
@@ -685,11 +691,11 @@ public sealed class BSPrim : BSPhysObject | |||
685 | // There can be special things needed for implementing linksets | 691 | // There can be special things needed for implementing linksets |
686 | Linkset.MakeStatic(this); | 692 | Linkset.MakeStatic(this); |
687 | // The activation state is 'disabled' so Bullet will not try to act on it. | 693 | // The activation state is 'disabled' so Bullet will not try to act on it. |
688 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 694 | // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
689 | // Start it out sleeping and physical actions could wake it up. | 695 | // Start it out sleeping and physical actions could wake it up. |
690 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 696 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); |
691 | 697 | ||
692 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 698 | PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup; |
693 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 699 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; |
694 | } | 700 | } |
695 | else | 701 | else |
@@ -735,7 +741,7 @@ public sealed class BSPrim : BSPhysObject | |||
735 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | 741 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); |
736 | // BulletSimAPI.Activate2(BSBody.ptr, true); | 742 | // BulletSimAPI.Activate2(BSBody.ptr, true); |
737 | 743 | ||
738 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 744 | PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup; |
739 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | 745 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; |
740 | } | 746 | } |
741 | } | 747 | } |
@@ -763,7 +769,7 @@ public sealed class BSPrim : BSPhysObject | |||
763 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 769 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
764 | } | 770 | } |
765 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 771 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
766 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 772 | PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup; |
767 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 773 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; |
768 | } | 774 | } |
769 | } | 775 | } |
@@ -839,15 +845,6 @@ public sealed class BSPrim : BSPhysObject | |||
839 | } | 845 | } |
840 | public override OMV.Vector3 RotationalVelocity { | 846 | public override OMV.Vector3 RotationalVelocity { |
841 | get { | 847 | get { |
842 | /* | ||
843 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
844 | // if close to zero, report zero | ||
845 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
846 | // zero the property in the physics engine. | ||
847 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
848 | return pv; | ||
849 | */ | ||
850 | |||
851 | return _rotationalVelocity; | 848 | return _rotationalVelocity; |
852 | } | 849 | } |
853 | set { | 850 | set { |
@@ -1409,7 +1406,7 @@ public sealed class BSPrim : BSPhysObject | |||
1409 | LastEntityProperties = CurrentEntityProperties; | 1406 | LastEntityProperties = CurrentEntityProperties; |
1410 | CurrentEntityProperties = entprop; | 1407 | CurrentEntityProperties = entprop; |
1411 | 1408 | ||
1412 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | 1409 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1413 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1410 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1414 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | 1411 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); |
1415 | 1412 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 0c80611..f72bd74 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -96,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
96 | public long SimulationStep { get { return m_simulationStep; } } | 96 | public long SimulationStep { get { return m_simulationStep; } } |
97 | private int m_taintsToProcessPerStep; | 97 | private int m_taintsToProcessPerStep; |
98 | 98 | ||
99 | public delegate void PreStepAction(float timeStep); | ||
100 | public event PreStepAction BeforeStep; | ||
101 | |||
99 | // A value of the time now so all the collision and update routines do not have to get their own | 102 | // A value of the time now so all the collision and update routines do not have to get their own |
100 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 103 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
101 | public int SimulationNowTime { get; private set; } | 104 | public int SimulationNowTime { get; private set; } |
@@ -487,8 +490,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
487 | ProcessTaints(); | 490 | ProcessTaints(); |
488 | 491 | ||
489 | // Some of the prims operate with special vehicle properties | 492 | // Some of the prims operate with special vehicle properties |
490 | ProcessVehicles(timeStep); | 493 | DoPreStepActions(timeStep); |
491 | ProcessTaints(); // the vehicles might have added taints | 494 | |
495 | // the prestep actions might have added taints | ||
496 | ProcessTaints(); | ||
492 | 497 | ||
493 | // step the physical world one interval | 498 | // step the physical world one interval |
494 | m_simulationStep++; | 499 | m_simulationStep++; |
@@ -496,7 +501,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
496 | 501 | ||
497 | try | 502 | try |
498 | { | 503 | { |
499 | // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 504 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG |
500 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 505 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
501 | 506 | ||
502 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 507 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
@@ -505,7 +510,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
505 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 510 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
506 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 511 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", |
507 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 512 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); |
508 | // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 513 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG |
509 | } | 514 | } |
510 | catch (Exception e) | 515 | catch (Exception e) |
511 | { | 516 | { |
@@ -907,6 +912,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
907 | } | 912 | } |
908 | } | 913 | } |
909 | 914 | ||
915 | private void DoPreStepActions(float timeStep) | ||
916 | { | ||
917 | ProcessVehicles(timeStep); | ||
918 | |||
919 | PreStepAction actions = BeforeStep; | ||
920 | if (actions != null) | ||
921 | actions(timeStep); | ||
922 | |||
923 | } | ||
924 | |||
910 | // Some prims have extra vehicle actions | 925 | // Some prims have extra vehicle actions |
911 | // Called at taint time! | 926 | // Called at taint time! |
912 | private void ProcessVehicles(float timeStep) | 927 | private void ProcessVehicles(float timeStep) |
@@ -971,6 +986,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
971 | // Should handle fetching the right type from the ini file and converting it. | 986 | // Should handle fetching the right type from the ini file and converting it. |
972 | // -- a delegate for getting the value as a float | 987 | // -- a delegate for getting the value as a float |
973 | // -- a delegate for setting the value from a float | 988 | // -- a delegate for setting the value from a float |
989 | // -- an optional delegate to update the value in the world. Most often used to | ||
990 | // push the new value to an in-world object. | ||
974 | // | 991 | // |
975 | // The single letter parameters for the delegates are: | 992 | // The single letter parameters for the delegates are: |
976 | // s = BSScene | 993 | // s = BSScene |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..b94dcf6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -620,8 +620,7 @@ public sealed class BSShapeCollection : IDisposable | |||
620 | } | 620 | } |
621 | else | 621 | else |
622 | { | 622 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 623 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | ||
625 | 624 | ||
626 | if (meshData != null) | 625 | if (meshData != null) |
627 | { | 626 | { |
@@ -694,8 +693,8 @@ public sealed class BSShapeCollection : IDisposable | |||
694 | else | 693 | else |
695 | { | 694 | { |
696 | // Build a new hull in the physical world | 695 | // Build a new hull in the physical world |
697 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 696 | // Pass true for physicalness as this creates some sort of bounding box which we don't need |
698 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 697 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); |
699 | if (meshData != null) | 698 | if (meshData != null) |
700 | { | 699 | { |
701 | 700 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 0cb151e..83b9c37 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -121,8 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
121 | // redo its bounding box now that it is in the world | 121 | // redo its bounding box now that it is in the world |
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); |
123 | 123 | ||
124 | BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, | 124 | BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr, |
125 | (uint)CollisionFilterGroups.TerrainFilter, | 125 | (uint)CollisionFilterGroups.TerrainGroup, |
126 | (uint)CollisionFilterGroups.TerrainMask); | 126 | (uint)CollisionFilterGroups.TerrainMask); |
127 | 127 | ||
128 | // Make it so the terrain will not move or be considered for movement. | 128 | // Make it so the terrain will not move or be considered for movement. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 17d9536..83df360 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -140,8 +140,8 @@ public sealed class BSTerrainManager | |||
140 | // Ground plane does not move | 140 | // Ground plane does not move |
141 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | 141 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); |
142 | // Everything collides with the ground plane. | 142 | // Everything collides with the ground plane. |
143 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 143 | BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr, |
144 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 144 | (uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask); |
145 | 145 | ||
146 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 146 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
147 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 147 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index 7e93ab4..6ce767d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -130,8 +130,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
130 | // Redo its bounding box now that it is in the world | 130 | // Redo its bounding box now that it is in the world |
131 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 131 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
132 | 132 | ||
133 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | 133 | BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr, |
134 | (uint)CollisionFilterGroups.TerrainFilter, | 134 | (uint)CollisionFilterGroups.TerrainGroup, |
135 | (uint)CollisionFilterGroups.TerrainMask); | 135 | (uint)CollisionFilterGroups.TerrainMask); |
136 | 136 | ||
137 | // Make it so the terrain will not move or be considered for movement. | 137 | // Make it so the terrain will not move or be considered for movement. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 1e003e6..a5acfd1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -57,12 +57,12 @@ public struct BulletBody | |||
57 | { | 57 | { |
58 | ID = id; | 58 | ID = id; |
59 | ptr = xx; | 59 | ptr = xx; |
60 | collisionFilter = 0; | 60 | collisionGroup = 0; |
61 | collisionMask = 0; | 61 | collisionMask = 0; |
62 | } | 62 | } |
63 | public IntPtr ptr; | 63 | public IntPtr ptr; |
64 | public uint ID; | 64 | public uint ID; |
65 | public CollisionFilterGroups collisionFilter; | 65 | public CollisionFilterGroups collisionGroup; |
66 | public CollisionFilterGroups collisionMask; | 66 | public CollisionFilterGroups collisionMask; |
67 | public override string ToString() | 67 | public override string ToString() |
68 | { | 68 | { |
@@ -71,10 +71,10 @@ public struct BulletBody | |||
71 | buff.Append(ID.ToString()); | 71 | buff.Append(ID.ToString()); |
72 | buff.Append(",p="); | 72 | buff.Append(",p="); |
73 | buff.Append(ptr.ToString("X")); | 73 | buff.Append(ptr.ToString("X")); |
74 | if (collisionFilter != 0 || collisionMask != 0) | 74 | if (collisionGroup != 0 || collisionMask != 0) |
75 | { | 75 | { |
76 | buff.Append(",f="); | 76 | buff.Append(",g="); |
77 | buff.Append(collisionFilter.ToString("X")); | 77 | buff.Append(collisionGroup.ToString("X")); |
78 | buff.Append(",m="); | 78 | buff.Append(",m="); |
79 | buff.Append(collisionMask.ToString("X")); | 79 | buff.Append(collisionMask.ToString("X")); |
80 | } | 80 | } |
@@ -376,36 +376,36 @@ public enum CollisionFilterGroups : uint | |||
376 | // Don't use the bit definitions!! Define the use in a | 376 | // Don't use the bit definitions!! Define the use in a |
377 | // filter/mask definition below. This way collision interactions | 377 | // filter/mask definition below. This way collision interactions |
378 | // are more easily debugged. | 378 | // are more easily debugged. |
379 | BNoneFilter = 0, | 379 | BNoneGroup = 0, |
380 | BDefaultFilter = 1 << 0, | 380 | BDefaultGroup = 1 << 0, |
381 | BStaticFilter = 1 << 1, | 381 | BStaticGroup = 1 << 1, |
382 | BKinematicFilter = 1 << 2, | 382 | BKinematicGroup = 1 << 2, |
383 | BDebrisFilter = 1 << 3, | 383 | BDebrisGroup = 1 << 3, |
384 | BSensorTrigger = 1 << 4, | 384 | BSensorTrigger = 1 << 4, |
385 | BCharacterFilter = 1 << 5, | 385 | BCharacterGroup = 1 << 5, |
386 | BAllFilter = 0xFFFFFFFF, | 386 | BAllGroup = 0xFFFFFFFF, |
387 | // Filter groups defined by BulletSim | 387 | // Filter groups defined by BulletSim |
388 | BGroundPlaneFilter = 1 << 10, | 388 | BGroundPlaneGroup = 1 << 10, |
389 | BTerrainFilter = 1 << 11, | 389 | BTerrainGroup = 1 << 11, |
390 | BRaycastFilter = 1 << 12, | 390 | BRaycastGroup = 1 << 12, |
391 | BSolidFilter = 1 << 13, | 391 | BSolidGroup = 1 << 13, |
392 | BLinksetFilter = 1 << 14, | 392 | BLinksetGroup = 1 << 14, |
393 | 393 | ||
394 | // The collsion filters and masked are defined in one place -- don't want them scattered | 394 | // The collsion filters and masked are defined in one place -- don't want them scattered |
395 | AvatarFilter = BCharacterFilter, | 395 | AvatarGroup = BCharacterGroup, |
396 | AvatarMask = BAllFilter, | 396 | AvatarMask = BAllGroup, |
397 | ObjectFilter = BSolidFilter, | 397 | ObjectGroup = BSolidGroup, |
398 | ObjectMask = BAllFilter, | 398 | ObjectMask = BAllGroup, |
399 | StaticObjectFilter = BStaticFilter, | 399 | StaticObjectGroup = BStaticGroup, |
400 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other | 400 | StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much |
401 | LinksetFilter = BLinksetFilter, | 401 | LinksetGroup = BLinksetGroup, |
402 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other | 402 | LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other |
403 | VolumeDetectFilter = BSensorTrigger, | 403 | VolumeDetectGroup = BSensorTrigger, |
404 | VolumeDetectMask = ~BSensorTrigger, | 404 | VolumeDetectMask = ~BSensorTrigger, |
405 | TerrainFilter = BTerrainFilter, | 405 | TerrainGroup = BTerrainGroup, |
406 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide | 406 | TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide |
407 | GroundPlaneFilter = BGroundPlaneFilter, | 407 | GroundPlaneGroup = BGroundPlaneGroup, |
408 | GroundPlaneMask = BAllFilter | 408 | GroundPlaneMask = BAllGroup |
409 | 409 | ||
410 | }; | 410 | }; |
411 | 411 | ||
@@ -945,7 +945,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | |||
945 | public static extern int GetNumConstraintRefs2(IntPtr obj); | 945 | public static extern int GetNumConstraintRefs2(IntPtr obj); |
946 | 946 | ||
947 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 947 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
948 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | 948 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); |
949 | 949 | ||
950 | // ===================================================================================== | 950 | // ===================================================================================== |
951 | // btCollisionShape entries | 951 | // btCollisionShape entries |
@@ -1007,13 +1007,16 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | |||
1007 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | 1007 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); |
1008 | 1008 | ||
1009 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1009 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1010 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
1011 | |||
1012 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1010 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | 1013 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); |
1011 | 1014 | ||
1012 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1015 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1013 | public static extern void DumpAllInfo2(IntPtr sim); | 1016 | public static extern void DumpActivationInfo2(IntPtr sim); |
1014 | 1017 | ||
1015 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1018 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1016 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | 1019 | public static extern void DumpAllInfo2(IntPtr sim); |
1017 | 1020 | ||
1018 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1021 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1019 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | 1022 | public static extern void DumpPhysicsStatistics2(IntPtr sim); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt new file mode 100755 index 0000000..68f25fc --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -0,0 +1,117 @@ | |||
1 | CRASHES | ||
2 | ================================================= | ||
3 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
4 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
5 | 20121128.1600: mesh object not rezzing (no physics mesh). | ||
6 | Causes many errors. Doesn't stop after first error with box shape. | ||
7 | Eventually crashes when deleting the object. | ||
8 | |||
9 | BULLETSIM TODO LIST: | ||
10 | ================================================= | ||
11 | Neb car jiggling left and right | ||
12 | Vehicles (Move smoothly) | ||
13 | Light cycle falling over when driving | ||
14 | Light cycle not banking | ||
15 | Do single prim vehicles don't seem to properly vehiclize. | ||
16 | Gun sending shooter flying | ||
17 | Collision margin (gap between physical objects lying on each other) | ||
18 | Boundry checking (crashes related to crossing boundry) | ||
19 | Add check for border edge position for avatars and objects. | ||
20 | Verify the events are created for border crossings. | ||
21 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
22 | Avatar running (what does phys engine need to do?) | ||
23 | Small physical objects do not interact correctly | ||
24 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
25 | The chain will fall apart and pairs will dance around on ground | ||
26 | Chains of 1x1x.2 will stay connected but will dance. | ||
27 | Chains above 2x2x.4 are move stable and get stablier as torui get larger. | ||
28 | Add material type linkage and input all the material property definitions. | ||
29 | Skeleton classes and table are in the sources but are not filled or used. | ||
30 | Add PID motor for avatar movement (slow to stop, ...) | ||
31 | Implement function efficiency for lineaar and angular motion. | ||
32 | |||
33 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
34 | Need to force a position update for the root prim after compound shape destruction | ||
35 | Find/remove avatar collision with ID=0. | ||
36 | Test avatar walking up stairs. How does compare with SL. | ||
37 | Radius of the capsule affects ability to climb edges. | ||
38 | Tune terrain/object friction to be closer to SL. | ||
39 | Debounce avatar contact so legs don't keep folding up when standing. | ||
40 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
41 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
42 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
43 | |||
44 | Speed up creation of large physical linksets | ||
45 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical | ||
46 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
47 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
48 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
49 | Check wheter SimMotionState needs large if statement (see TODO). | ||
50 | |||
51 | Implement 'top colliders' info. | ||
52 | Avatar jump | ||
53 | Implement meshes or just verify that they work. | ||
54 | Do prim hash codes work for sculpties and meshes? | ||
55 | Performance measurement and changes to make quicker. | ||
56 | Implement detailed physics stats (GetStats()). | ||
57 | |||
58 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
59 | Have UserPointer point to struct with localID and linksetID? | ||
60 | Objects in original linkset still collide with each other? | ||
61 | |||
62 | Measure performance improvement from hulls | ||
63 | Test not using ghost objects for volume detect implementation. | ||
64 | Performance of closures and delegates for taint processing | ||
65 | Are there faster ways? | ||
66 | Is any slowdown introduced by the existing implementation significant? | ||
67 | Is there are more efficient method of implementing pre and post step actions? | ||
68 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
69 | |||
70 | Package Bullet source mods for Bullet internal stats output | ||
71 | |||
72 | Physics Arena central pyramid: why is one side permiable? | ||
73 | |||
74 | INTERNAL IMPROVEMENT/CLEANUP | ||
75 | ================================================= | ||
76 | Remove unused fields from ShapeData (not used in API2) | ||
77 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
78 | Standardize access to building and reference code. | ||
79 | The skeleton classes are in the sources but are not complete or linked in. | ||
80 | Generalize Dynamics and PID with standardized motors. | ||
81 | Generalize Linkset and vehicles into PropertyManagers | ||
82 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
83 | Possibly generalized a 'pre step action' registration. | ||
84 | Complete implemention of preStepActions | ||
85 | Replace vehicle step call with prestep event. | ||
86 | Is there a need for postStepActions? postStepTaints? | ||
87 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
88 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
89 | Linkset implementation using manual prim movement. | ||
90 | Linkset implementation using compound shapes. | ||
91 | Compound shapes will need the LocalID in the shapes and collision | ||
92 | processing to get it from there. | ||
93 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
94 | Remove HeightmapInfo from terrain specification. | ||
95 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
96 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
97 | bob at the water level. BSPrim.PositionSanityCheck(). | ||
98 | |||
99 | DONE DONE DONE DONE | ||
100 | ================================================= | ||
101 | Cleanup code in BSDynamics by using motors. | ||
102 | Consider implementing terrain with a mesh rather than heightmap. | ||
103 | Would have better and adjustable resolution. | ||
104 | NOTDONE: Build terrain mesh so heighmap is height of the center of the square meter. | ||
105 | SL and ODE define meter square as being at one corner with one diagional. | ||
106 | Terrain as mesh. | ||
107 | How are static linksets seen by the physics engine? | ||
108 | A: they are not linked in physics. When moved, all the children are repositioned. | ||
109 | Remember to remove BSScene.DetailLog Refresh call. | ||
110 | Convert BSCharacter to use all API2 | ||
111 | Avatar pushing difficult (too heavy?) | ||
112 | Use asset service passed to BulletSim to get sculptie bodies, etc. | ||
113 | Vehicles (fix bouncing on terrain) | ||
114 | Remove old code in DLL (all non-API2 stuff). | ||
115 | Measurements of mega-physical prim performance (with graph) | ||
116 | Debug Bullet internal stats output (why is timing all wrong?) | ||
117 | Bullet stats logging only works with a single instance of Bullet (one region). \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index 3a9ca1b..10c4bd3 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs | |||
@@ -36,6 +36,7 @@ namespace OpenSim.Region.Physics.Manager | |||
36 | { | 36 | { |
37 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); | 37 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); |
38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); | 38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); |
39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache); | ||
39 | } | 40 | } |
40 | 41 | ||
41 | // Values for level of detail to be passed to the mesher. | 42 | // Values for level of detail to be passed to the mesher. |
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs index ba19db6..270d2ec 100644 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs | |||
@@ -64,11 +64,16 @@ namespace OpenSim.Region.Physics.Manager | |||
64 | { | 64 | { |
65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
66 | { | 66 | { |
67 | return CreateMesh(primName, primShape, size, lod, false); | 67 | return CreateMesh(primName, primShape, size, lod, false, false); |
68 | } | 68 | } |
69 | 69 | ||
70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
71 | { | 71 | { |
72 | return CreateMesh(primName, primShape, size, lod, false, false); | ||
73 | } | ||
74 | |||
75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
76 | { | ||
72 | // Remove the reference to the encoded JPEG2000 data so it can be GCed | 77 | // Remove the reference to the encoded JPEG2000 data so it can be GCed |
73 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; | 78 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; |
74 | 79 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 6fa91ab..8145d61 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -702,11 +702,16 @@ namespace OpenSim.Region.Physics.Meshing | |||
702 | 702 | ||
703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
704 | { | 704 | { |
705 | return CreateMesh(primName, primShape, size, lod, false); | 705 | return CreateMesh(primName, primShape, size, lod, false, true); |
706 | } | 706 | } |
707 | 707 | ||
708 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 708 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
709 | { | 709 | { |
710 | return CreateMesh(primName, primShape, size, lod, isPhysical, true); | ||
711 | } | ||
712 | |||
713 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
714 | { | ||
710 | #if SPAM | 715 | #if SPAM |
711 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 716 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
712 | #endif | 717 | #endif |
@@ -716,9 +721,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
716 | 721 | ||
717 | // If this mesh has been created already, return it instead of creating another copy | 722 | // If this mesh has been created already, return it instead of creating another copy |
718 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | 723 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory |
719 | key = primShape.GetMeshKey(size, lod); | 724 | if (shouldCache) |
720 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 725 | { |
721 | return mesh; | 726 | key = primShape.GetMeshKey(size, lod); |
727 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
728 | return mesh; | ||
729 | } | ||
722 | 730 | ||
723 | if (size.X < 0.01f) size.X = 0.01f; | 731 | if (size.X < 0.01f) size.X = 0.01f; |
724 | if (size.Y < 0.01f) size.Y = 0.01f; | 732 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -741,7 +749,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
741 | // trim the vertex and triangle lists to free up memory | 749 | // trim the vertex and triangle lists to free up memory |
742 | mesh.TrimExcess(); | 750 | mesh.TrimExcess(); |
743 | 751 | ||
744 | m_uniqueMeshes.Add(key, mesh); | 752 | if (shouldCache) |
753 | { | ||
754 | m_uniqueMeshes.Add(key, mesh); | ||
755 | } | ||
745 | } | 756 | } |
746 | 757 | ||
747 | return mesh; | 758 | return mesh; |
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 3f5011a..75d5bc3 100755 --- a/bin/lib32/BulletSim.dll +++ b/bin/lib32/BulletSim.dll | |||
Binary files differ | |||
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 46d40fe..b648da1 100755 --- a/bin/lib32/libBulletSim.so +++ b/bin/lib32/libBulletSim.so | |||
Binary files differ | |||
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 27a807c..fc0fdca 100755 --- a/bin/lib64/BulletSim.dll +++ b/bin/lib64/BulletSim.dll | |||
Binary files differ | |||
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 1e82b3d..a1b099c 100755 --- a/bin/lib64/libBulletSim.so +++ b/bin/lib64/libBulletSim.so | |||
Binary files differ | |||