diff options
author | teravus | 2012-11-15 10:05:16 -0500 |
---|---|---|
committer | teravus | 2012-11-15 10:05:16 -0500 |
commit | e9153e1d1aae50024d8cd05fe14a9bce34343a0e (patch) | |
tree | bc111d34f95a26b99c7e34d9e495dc14d1802cc3 /OpenSim/Region/Physics | |
parent | Merge master into teravuswork (diff) | |
download | opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.zip opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.tar.gz opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.tar.bz2 opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.tar.xz |
Revert "Merge master into teravuswork", it should have been avination, not master.
This reverts commit dfac269032300872c4d0dc507f4f9062d102b0f4, reversing
changes made to 619c39e5144f15aca129d6d999bcc5c34133ee64.
Diffstat (limited to '')
20 files changed, 2360 insertions, 5509 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs index 23ef052..683bc51 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs | |||
@@ -32,14 +32,10 @@ using OpenMetaverse; | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | 32 | namespace OpenSim.Region.Physics.BulletSPlugin |
33 | { | 33 | { |
34 | 34 | ||
35 | public sealed class BSConstraint6Dof : BSConstraint | 35 | public class BS6DofConstraint : BSConstraint |
36 | { | 36 | { |
37 | private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; | ||
38 | |||
39 | public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } | ||
40 | |||
41 | // Create a btGeneric6DofConstraint | 37 | // Create a btGeneric6DofConstraint |
42 | public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, | 38 | public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, |
43 | Vector3 frame1, Quaternion frame1rot, | 39 | Vector3 frame1, Quaternion frame1rot, |
44 | Vector3 frame2, Quaternion frame2rot, | 40 | Vector3 frame2, Quaternion frame2rot, |
45 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 41 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
@@ -48,52 +44,25 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
48 | m_body1 = obj1; | 44 | m_body1 = obj1; |
49 | m_body2 = obj2; | 45 | m_body2 = obj2; |
50 | m_constraint = new BulletConstraint( | 46 | m_constraint = new BulletConstraint( |
51 | BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | 47 | BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, |
52 | frame1, frame1rot, | 48 | frame1, frame1rot, |
53 | frame2, frame2rot, | 49 | frame2, frame2rot, |
54 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 50 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); |
55 | m_enabled = true; | 51 | m_enabled = true; |
56 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
57 | BSScene.DetailLogZero, world.worldID, | ||
58 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | ||
59 | } | 52 | } |
60 | 53 | ||
61 | public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, | 54 | public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, |
62 | Vector3 joinPoint, | 55 | Vector3 joinPoint, |
63 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 56 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
64 | { | 57 | { |
65 | m_world = world; | 58 | m_world = world; |
66 | m_body1 = obj1; | 59 | m_body1 = obj1; |
67 | m_body2 = obj2; | 60 | m_body2 = obj2; |
68 | if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) | 61 | m_constraint = new BulletConstraint( |
69 | { | 62 | BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, |
70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 63 | joinPoint, |
71 | BSScene.DetailLogZero, world.worldID, | 64 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); |
72 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 65 | m_enabled = true; |
73 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
74 | LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | ||
75 | m_enabled = false; | ||
76 | } | ||
77 | else | ||
78 | { | ||
79 | m_constraint = new BulletConstraint( | ||
80 | BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
81 | joinPoint, | ||
82 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | ||
84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), | ||
85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | ||
86 | if (m_constraint.ptr == IntPtr.Zero) | ||
87 | { | ||
88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | ||
89 | LogHeader, obj1.ID, obj2.ID); | ||
90 | m_enabled = false; | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | m_enabled = true; | ||
95 | } | ||
96 | } | ||
97 | } | 66 | } |
98 | 67 | ||
99 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | 68 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) |
@@ -101,7 +70,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
101 | bool ret = false; | 70 | bool ret = false; |
102 | if (m_enabled) | 71 | if (m_enabled) |
103 | { | 72 | { |
104 | BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | 73 | BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot); |
105 | ret = true; | 74 | ret = true; |
106 | } | 75 | } |
107 | return ret; | 76 | return ret; |
@@ -112,9 +81,9 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
112 | bool ret = false; | 81 | bool ret = false; |
113 | if (m_enabled) | 82 | if (m_enabled) |
114 | { | 83 | { |
115 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | 84 | BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); |
116 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); | 85 | BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); |
117 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | 86 | BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); |
118 | ret = true; | 87 | ret = true; |
119 | } | 88 | } |
120 | return ret; | 89 | return ret; |
@@ -125,7 +94,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
125 | bool ret = false; | 94 | bool ret = false; |
126 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | 95 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; |
127 | if (m_enabled) | 96 | if (m_enabled) |
128 | ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); | 97 | ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff); |
129 | return ret; | 98 | return ret; |
130 | } | 99 | } |
131 | 100 | ||
@@ -134,11 +103,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
134 | bool ret = false; | 103 | bool ret = false; |
135 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | 104 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; |
136 | if (m_enabled) | 105 | if (m_enabled) |
137 | { | 106 | ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce); |
138 | ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); | ||
139 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", | ||
140 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); | ||
141 | } | ||
142 | return ret; | 107 | return ret; |
143 | } | 108 | } |
144 | 109 | ||
@@ -146,7 +111,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
146 | { | 111 | { |
147 | bool ret = false; | 112 | bool ret = false; |
148 | if (m_enabled) | 113 | if (m_enabled) |
149 | ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); | 114 | ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold); |
150 | return ret; | 115 | return ret; |
151 | } | 116 | } |
152 | } | 117 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 2a5397e..e2f7af9 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -28,48 +28,62 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Reflection; | 29 | using System.Reflection; |
30 | using log4net; | 30 | using log4net; |
31 | using OMV = OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.Physics.Manager; |
34 | 34 | ||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | public sealed class BSCharacter : BSPhysObject | 37 | public class BSCharacter : PhysicsActor |
38 | { | 38 | { |
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
40 | private static readonly string LogHeader = "[BULLETS CHAR]"; | 40 | private static readonly string LogHeader = "[BULLETS CHAR]"; |
41 | 41 | ||
42 | private BSScene _scene; | ||
43 | public BSScene Scene { get { return _scene; } } | ||
44 | private String _avName; | ||
42 | // private bool _stopped; | 45 | // private bool _stopped; |
43 | private OMV.Vector3 _size; | 46 | private Vector3 _size; |
47 | private Vector3 _scale; | ||
48 | private PrimitiveBaseShape _pbs; | ||
49 | private uint _localID = 0; | ||
44 | private bool _grabbed; | 50 | private bool _grabbed; |
45 | private bool _selected; | 51 | private bool _selected; |
46 | private OMV.Vector3 _position; | 52 | private Vector3 _position; |
47 | private float _mass; | 53 | private float _mass; |
48 | private float _avatarDensity; | 54 | public float _density; |
49 | private float _avatarVolume; | 55 | public float _avatarVolume; |
50 | private OMV.Vector3 _force; | 56 | private Vector3 _force; |
51 | private OMV.Vector3 _velocity; | 57 | private Vector3 _velocity; |
52 | private OMV.Vector3 _torque; | 58 | private Vector3 _torque; |
53 | private float _collisionScore; | 59 | private float _collisionScore; |
54 | private OMV.Vector3 _acceleration; | 60 | private Vector3 _acceleration; |
55 | private OMV.Quaternion _orientation; | 61 | private Quaternion _orientation; |
56 | private int _physicsActorType; | 62 | private int _physicsActorType; |
57 | private bool _isPhysical; | 63 | private bool _isPhysical; |
58 | private bool _flying; | 64 | private bool _flying; |
59 | private bool _setAlwaysRun; | 65 | private bool _setAlwaysRun; |
60 | private bool _throttleUpdates; | 66 | private bool _throttleUpdates; |
61 | private bool _isColliding; | 67 | private bool _isColliding; |
68 | private long _collidingStep; | ||
69 | private bool _collidingGround; | ||
70 | private long _collidingGroundStep; | ||
62 | private bool _collidingObj; | 71 | private bool _collidingObj; |
63 | private bool _floatOnWater; | 72 | private bool _floatOnWater; |
64 | private OMV.Vector3 _rotationalVelocity; | 73 | private Vector3 _rotationalVelocity; |
65 | private bool _kinematic; | 74 | private bool _kinematic; |
66 | private float _buoyancy; | 75 | private float _buoyancy; |
67 | 76 | ||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | 77 | private BulletBody m_body; |
69 | private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar | 78 | public BulletBody Body { |
70 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | 79 | get { return m_body; } |
80 | set { m_body = value; } | ||
81 | } | ||
82 | |||
83 | private int _subscribedEventsMs = 0; | ||
84 | private int _nextCollisionOkTime = 0; | ||
71 | 85 | ||
72 | private OMV.Vector3 _PIDTarget; | 86 | private Vector3 _PIDTarget; |
73 | private bool _usePID; | 87 | private bool _usePID; |
74 | private float _PIDTau; | 88 | private float _PIDTau; |
75 | private bool _useHoverPID; | 89 | private bool _useHoverPID; |
@@ -77,507 +91,332 @@ public sealed class BSCharacter : BSPhysObject | |||
77 | private PIDHoverType _PIDHoverType; | 91 | private PIDHoverType _PIDHoverType; |
78 | private float _PIDHoverTao; | 92 | private float _PIDHoverTao; |
79 | 93 | ||
80 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | 94 | public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) |
81 | { | 95 | { |
82 | base.BaseInitialize(parent_scene, localID, avName, "BSCharacter"); | 96 | _localID = localID; |
83 | _physicsActorType = (int)ActorTypes.Agent; | 97 | _avName = avName; |
98 | _scene = parent_scene; | ||
84 | _position = pos; | 99 | _position = pos; |
85 | _size = size; | 100 | _size = size; |
86 | _flying = isFlying; | 101 | _flying = isFlying; |
87 | _orientation = OMV.Quaternion.Identity; | 102 | _orientation = Quaternion.Identity; |
88 | _velocity = OMV.Vector3.Zero; | 103 | _velocity = Vector3.Zero; |
89 | _appliedVelocity = OMV.Vector3.Zero; | ||
90 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 104 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
91 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | ||
92 | _avatarDensity = PhysicsScene.Params.avatarDensity; | ||
93 | |||
94 | // The dimensions of the avatar capsule are kept in the scale. | 105 | // The dimensions of the avatar capsule are kept in the scale. |
95 | // Physics creates a unit capsule which is scaled by the physics engine. | 106 | // Physics creates a unit capsule which is scaled by the physics engine. |
96 | ComputeAvatarScale(_size); | 107 | _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); |
97 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 108 | _density = _scene.Params.avatarDensity; |
98 | ComputeAvatarVolumeAndMass(); | 109 | ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale |
99 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 110 | |
100 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 111 | ShapeData shapeData = new ShapeData(); |
112 | shapeData.ID = _localID; | ||
113 | shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; | ||
114 | shapeData.Position = _position; | ||
115 | shapeData.Rotation = _orientation; | ||
116 | shapeData.Velocity = _velocity; | ||
117 | shapeData.Scale = _scale; | ||
118 | shapeData.Mass = _mass; | ||
119 | shapeData.Buoyancy = _buoyancy; | ||
120 | shapeData.Static = ShapeData.numericFalse; | ||
121 | shapeData.Friction = _scene.Params.avatarFriction; | ||
122 | shapeData.Restitution = _scene.Params.avatarRestitution; | ||
101 | 123 | ||
102 | // do actual create at taint time | 124 | // do actual create at taint time |
103 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 125 | _scene.TaintedObject("BSCharacter.create", delegate() |
104 | { | 126 | { |
105 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 127 | BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); |
106 | // New body and shape into BSBody and BSShape | ||
107 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); | ||
108 | 128 | ||
109 | SetPhysicalProperties(); | 129 | m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); |
130 | // avatars get all collisions no matter what | ||
131 | BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
110 | }); | 132 | }); |
133 | |||
111 | return; | 134 | return; |
112 | } | 135 | } |
113 | 136 | ||
114 | // called when this character is being destroyed and the resources should be released | 137 | // called when this character is being destroyed and the resources should be released |
115 | public override void Destroy() | 138 | public void Destroy() |
116 | { | 139 | { |
117 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 140 | // DetailLog("{0},BSCharacter.Destroy", LocalID); |
118 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 141 | _scene.TaintedObject("BSCharacter.destroy", delegate() |
119 | { | 142 | { |
120 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 143 | BulletSimAPI.DestroyObject(_scene.WorldID, _localID); |
121 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
122 | }); | 144 | }); |
123 | } | 145 | } |
124 | 146 | ||
125 | private void SetPhysicalProperties() | ||
126 | { | ||
127 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
128 | |||
129 | ZeroMotion(); | ||
130 | ForcePosition = _position; | ||
131 | // Set the velocity and compute the proper friction | ||
132 | ForceVelocity = _velocity; | ||
133 | |||
134 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); | ||
135 | BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); | ||
136 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
137 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | ||
138 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
139 | { | ||
140 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
141 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
142 | } | ||
143 | |||
144 | UpdatePhysicalMassProperties(RawMass); | ||
145 | |||
146 | // Make so capsule does not fall over | ||
147 | BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); | ||
148 | |||
149 | BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | ||
150 | |||
151 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
152 | |||
153 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | ||
154 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); | ||
155 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
156 | |||
157 | // Do this after the object has been added to the world | ||
158 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | ||
159 | (uint)CollisionFilterGroups.AvatarFilter, | ||
160 | (uint)CollisionFilterGroups.AvatarMask); | ||
161 | } | ||
162 | |||
163 | public override void RequestPhysicsterseUpdate() | 147 | public override void RequestPhysicsterseUpdate() |
164 | { | 148 | { |
165 | base.RequestPhysicsterseUpdate(); | 149 | base.RequestPhysicsterseUpdate(); |
166 | } | 150 | } |
167 | // No one calls this method so I don't know what it could possibly mean | 151 | // No one calls this method so I don't know what it could possibly mean |
168 | public override bool Stopped { get { return false; } } | 152 | public override bool Stopped { |
169 | 153 | get { return false; } | |
170 | public override OMV.Vector3 Size { | 154 | } |
155 | public override Vector3 Size { | ||
171 | get | 156 | get |
172 | { | 157 | { |
173 | // Avatar capsule size is kept in the scale parameter. | 158 | // Avatar capsule size is kept in the scale parameter. |
174 | // return _size; | 159 | return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); |
175 | return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z); | ||
176 | } | 160 | } |
177 | 161 | ||
178 | set { | 162 | set { |
179 | // When an avatar's size is set, only the height is changed. | 163 | // When an avatar's size is set, only the height is changed |
164 | // and that really only depends on the radius. | ||
180 | _size = value; | 165 | _size = value; |
181 | ComputeAvatarScale(_size); | 166 | _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); |
167 | |||
168 | // TODO: something has to be done with the avatar's vertical position | ||
169 | |||
182 | ComputeAvatarVolumeAndMass(); | 170 | ComputeAvatarVolumeAndMass(); |
183 | DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", | ||
184 | LocalID, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
185 | 171 | ||
186 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 172 | _scene.TaintedObject("BSCharacter.setSize", delegate() |
187 | { | 173 | { |
188 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 174 | BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); |
189 | UpdatePhysicalMassProperties(RawMass); | ||
190 | }); | 175 | }); |
191 | 176 | ||
192 | } | 177 | } |
193 | } | 178 | } |
194 | 179 | public override PrimitiveBaseShape Shape { | |
195 | public override OMV.Vector3 Scale { get; set; } | 180 | set { _pbs = value; |
196 | 181 | } | |
197 | public override PrimitiveBaseShape Shape | ||
198 | { | ||
199 | set { BaseShape = value; } | ||
200 | } | 182 | } |
201 | // I want the physics engine to make an avatar capsule | 183 | public override uint LocalID { |
202 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape | 184 | set { _localID = value; |
203 | { | 185 | } |
204 | get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; } | 186 | get { return _localID; } |
205 | } | 187 | } |
206 | 188 | public override bool Grabbed { | |
207 | public override bool Grabbed { | 189 | set { _grabbed = value; |
208 | set { _grabbed = value; } | 190 | } |
209 | } | 191 | } |
210 | public override bool Selected { | 192 | public override bool Selected { |
211 | set { _selected = value; } | 193 | set { _selected = value; |
194 | } | ||
212 | } | 195 | } |
213 | public override void CrossingFailure() { return; } | 196 | public override void CrossingFailure() { return; } |
214 | public override void link(PhysicsActor obj) { return; } | 197 | public override void link(PhysicsActor obj) { return; } |
215 | public override void delink() { return; } | 198 | public override void delink() { return; } |
199 | public override void LockAngularMotion(Vector3 axis) { return; } | ||
216 | 200 | ||
217 | // Set motion values to zero. | 201 | public override Vector3 Position { |
218 | // Do it to the properties so the values get set in the physics engine. | ||
219 | // Push the setting of the values to the viewer. | ||
220 | // Called at taint time! | ||
221 | public override void ZeroMotion() | ||
222 | { | ||
223 | _velocity = OMV.Vector3.Zero; | ||
224 | _acceleration = OMV.Vector3.Zero; | ||
225 | _rotationalVelocity = OMV.Vector3.Zero; | ||
226 | |||
227 | // Zero some other properties directly into the physics engine | ||
228 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
229 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
230 | BulletSimAPI.SetInterpolationVelocity2(PhysBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
231 | BulletSimAPI.ClearForces2(PhysBody.ptr); | ||
232 | } | ||
233 | |||
234 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | ||
235 | |||
236 | public override OMV.Vector3 RawPosition | ||
237 | { | ||
238 | get { return _position; } | ||
239 | set { _position = value; } | ||
240 | } | ||
241 | public override OMV.Vector3 Position { | ||
242 | get { | 202 | get { |
243 | // Don't refetch the position because this function is called a zillion times | 203 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
244 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); | 204 | return _position; |
245 | return _position; | 205 | } |
246 | } | ||
247 | set { | 206 | set { |
248 | _position = value; | 207 | _position = value; |
249 | PositionSanityCheck(); | 208 | PositionSanityCheck(); |
250 | 209 | ||
251 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 210 | _scene.TaintedObject("BSCharacter.setPosition", delegate() |
252 | { | 211 | { |
253 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 212 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
254 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 213 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
255 | }); | 214 | }); |
256 | } | 215 | } |
257 | } | ||
258 | public override OMV.Vector3 ForcePosition { | ||
259 | get { | ||
260 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | ||
261 | return _position; | ||
262 | } | ||
263 | set { | ||
264 | _position = value; | ||
265 | PositionSanityCheck(); | ||
266 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
267 | } | ||
268 | } | 216 | } |
269 | 217 | ||
270 | |||
271 | // Check that the current position is sane and, if not, modify the position to make it so. | 218 | // Check that the current position is sane and, if not, modify the position to make it so. |
272 | // Check for being below terrain or on water. | 219 | // Check for being below terrain and being out of bounds. |
273 | // Returns 'true' of the position was made sane by some action. | 220 | // Returns 'true' of the position was made sane by some action. |
274 | private bool PositionSanityCheck() | 221 | private bool PositionSanityCheck() |
275 | { | 222 | { |
276 | bool ret = false; | 223 | bool ret = false; |
277 | 224 | ||
278 | // If below the ground, move the avatar up | 225 | // If below the ground, move the avatar up |
279 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 226 | float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); |
280 | if (Position.Z < terrainHeight) | 227 | if (_position.Z < terrainHeight) |
281 | { | 228 | { |
282 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 229 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); |
283 | _position.Z = terrainHeight + 2.0f; | 230 | _position.Z = terrainHeight + 2.0f; |
284 | ret = true; | 231 | ret = true; |
285 | } | 232 | } |
286 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
287 | { | ||
288 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | ||
289 | if (Position.Z < waterHeight) | ||
290 | { | ||
291 | _position.Z = waterHeight; | ||
292 | ret = true; | ||
293 | } | ||
294 | } | ||
295 | 233 | ||
296 | // TODO: check for out of bounds | 234 | // TODO: check for out of bounds |
297 | return ret; | ||
298 | } | ||
299 | 235 | ||
300 | // A version of the sanity check that also makes sure a new position value is | ||
301 | // pushed back to the physics engine. This routine would be used by anyone | ||
302 | // who is not already pushing the value. | ||
303 | private bool PositionSanityCheck(bool inTaintTime) | ||
304 | { | ||
305 | bool ret = false; | ||
306 | if (PositionSanityCheck()) | ||
307 | { | ||
308 | // The new position value must be pushed into the physics engine but we can't | ||
309 | // just assign to "Position" because of potential call loops. | ||
310 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | ||
311 | { | ||
312 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
313 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
314 | }); | ||
315 | ret = true; | ||
316 | } | ||
317 | return ret; | 236 | return ret; |
318 | } | 237 | } |
319 | 238 | ||
320 | public override float Mass { get { return _mass; } } | 239 | public override float Mass { |
321 | 240 | get { | |
322 | // used when we only want this prim's mass and not the linkset thing | 241 | return _mass; |
323 | public override float RawMass { | 242 | } |
324 | get {return _mass; } | ||
325 | } | ||
326 | public override void UpdatePhysicalMassProperties(float physMass) | ||
327 | { | ||
328 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
329 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | ||
330 | } | 243 | } |
331 | 244 | public override Vector3 Force { | |
332 | public override OMV.Vector3 Force { | 245 | get { return _force; } |
333 | get { return _force; } | ||
334 | set { | 246 | set { |
335 | _force = value; | 247 | _force = value; |
336 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 248 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
337 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 249 | Scene.TaintedObject("BSCharacter.SetForce", delegate() |
338 | { | 250 | { |
339 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 251 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
340 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 252 | BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); |
341 | }); | 253 | }); |
342 | } | 254 | } |
343 | } | 255 | } |
344 | 256 | ||
345 | // Avatars don't do vehicles | 257 | public override int VehicleType { |
346 | public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } | 258 | get { return 0; } |
259 | set { return; } | ||
260 | } | ||
347 | public override void VehicleFloatParam(int param, float value) { } | 261 | public override void VehicleFloatParam(int param, float value) { } |
348 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} | 262 | public override void VehicleVectorParam(int param, Vector3 value) {} |
349 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } | 263 | public override void VehicleRotationParam(int param, Quaternion rotation) { } |
350 | public override void VehicleFlags(int param, bool remove) { } | 264 | public override void VehicleFlags(int param, bool remove) { } |
351 | 265 | ||
352 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 266 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
353 | public override void SetVolumeDetect(int param) { return; } | 267 | public override void SetVolumeDetect(int param) { return; } |
354 | 268 | ||
355 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | 269 | public override Vector3 GeometricCenter { get { return Vector3.Zero; } } |
356 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | 270 | public override Vector3 CenterOfMass { get { return Vector3.Zero; } } |
357 | public override OMV.Vector3 Velocity { | 271 | public override Vector3 Velocity { |
358 | get { return _velocity; } | 272 | get { return _velocity; } |
359 | set { | 273 | set { |
360 | _velocity = value; | 274 | _velocity = value; |
361 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 275 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); |
362 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 276 | _scene.TaintedObject("BSCharacter.setVelocity", delegate() |
363 | { | 277 | { |
364 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 278 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); |
365 | ForceVelocity = _velocity; | 279 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); |
366 | }); | 280 | }); |
367 | } | 281 | } |
368 | } | ||
369 | public override OMV.Vector3 ForceVelocity { | ||
370 | get { return _velocity; } | ||
371 | set { | ||
372 | // Depending on whether the avatar is moving or not, change the friction | ||
373 | // to keep the avatar from slipping around | ||
374 | if (_velocity.Length() == 0) | ||
375 | { | ||
376 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | ||
377 | { | ||
378 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | ||
379 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
380 | } | ||
381 | } | ||
382 | else | ||
383 | { | ||
384 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | ||
385 | { | ||
386 | _currentFriction = PhysicsScene.Params.avatarFriction; | ||
387 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
388 | } | ||
389 | } | ||
390 | _velocity = value; | ||
391 | // Remember the set velocity so we can suppress the reduction by friction, ... | ||
392 | _appliedVelocity = value; | ||
393 | |||
394 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
395 | BulletSimAPI.Activate2(PhysBody.ptr, true); | ||
396 | } | ||
397 | } | 282 | } |
398 | public override OMV.Vector3 Torque { | 283 | public override Vector3 Torque { |
399 | get { return _torque; } | 284 | get { return _torque; } |
400 | set { _torque = value; | 285 | set { _torque = value; |
401 | } | 286 | } |
402 | } | 287 | } |
403 | public override float CollisionScore { | 288 | public override float CollisionScore { |
404 | get { return _collisionScore; } | 289 | get { return _collisionScore; } |
405 | set { _collisionScore = value; | 290 | set { _collisionScore = value; |
406 | } | 291 | } |
407 | } | 292 | } |
408 | public override OMV.Vector3 Acceleration { | 293 | public override Vector3 Acceleration { |
409 | get { return _acceleration; } | 294 | get { return _acceleration; } |
410 | set { _acceleration = value; } | 295 | set { _acceleration = value; } |
411 | } | 296 | } |
412 | public override OMV.Quaternion RawOrientation | 297 | public override Quaternion Orientation { |
413 | { | 298 | get { return _orientation; } |
414 | get { return _orientation; } | ||
415 | set { _orientation = value; } | ||
416 | } | ||
417 | public override OMV.Quaternion Orientation { | ||
418 | get { return _orientation; } | ||
419 | set { | 299 | set { |
420 | _orientation = value; | 300 | _orientation = value; |
421 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | 301 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); |
422 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 302 | _scene.TaintedObject("BSCharacter.setOrientation", delegate() |
423 | { | 303 | { |
424 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 304 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
425 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 305 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
426 | }); | 306 | }); |
427 | } | 307 | } |
428 | } | 308 | } |
429 | // Go directly to Bullet to get/set the value. | 309 | public override int PhysicsActorType { |
430 | public override OMV.Quaternion ForceOrientation | 310 | get { return _physicsActorType; } |
431 | { | 311 | set { _physicsActorType = value; |
432 | get | 312 | } |
433 | { | ||
434 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | ||
435 | return _orientation; | ||
436 | } | ||
437 | set | ||
438 | { | ||
439 | _orientation = value; | ||
440 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
441 | } | ||
442 | } | ||
443 | public override int PhysicsActorType { | ||
444 | get { return _physicsActorType; } | ||
445 | set { _physicsActorType = value; | ||
446 | } | ||
447 | } | 313 | } |
448 | public override bool IsPhysical { | 314 | public override bool IsPhysical { |
449 | get { return _isPhysical; } | 315 | get { return _isPhysical; } |
450 | set { _isPhysical = value; | 316 | set { _isPhysical = value; |
451 | } | 317 | } |
452 | } | ||
453 | public override bool IsSolid { | ||
454 | get { return true; } | ||
455 | } | 318 | } |
456 | public override bool IsStatic { | 319 | public override bool Flying { |
457 | get { return false; } | 320 | get { return _flying; } |
458 | } | ||
459 | public override bool Flying { | ||
460 | get { return _flying; } | ||
461 | set { | 321 | set { |
462 | _flying = value; | 322 | if (_flying != value) |
463 | // simulate flying by changing the effect of gravity | 323 | { |
464 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | 324 | _flying = value; |
465 | } | 325 | // simulate flying by changing the effect of gravity |
326 | this.Buoyancy = ComputeBuoyancyFromFlying(_flying); | ||
327 | } | ||
328 | } | ||
466 | } | 329 | } |
467 | // Flying is implimented by changing the avatar's buoyancy. | ||
468 | // Would this be done better with a vehicle type? | ||
469 | private float ComputeBuoyancyFromFlying(bool ifFlying) { | 330 | private float ComputeBuoyancyFromFlying(bool ifFlying) { |
470 | return ifFlying ? 1f : 0f; | 331 | return ifFlying ? 1f : 0f; |
471 | } | 332 | } |
472 | public override bool | 333 | public override bool |
473 | SetAlwaysRun { | 334 | SetAlwaysRun { |
474 | get { return _setAlwaysRun; } | 335 | get { return _setAlwaysRun; } |
475 | set { _setAlwaysRun = value; } | 336 | set { _setAlwaysRun = value; } |
476 | } | 337 | } |
477 | public override bool ThrottleUpdates { | 338 | public override bool ThrottleUpdates { |
478 | get { return _throttleUpdates; } | 339 | get { return _throttleUpdates; } |
479 | set { _throttleUpdates = value; } | 340 | set { _throttleUpdates = value; } |
480 | } | 341 | } |
481 | public override bool IsColliding { | 342 | public override bool IsColliding { |
482 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | 343 | get { return (_collidingStep == _scene.SimulationStep); } |
483 | set { _isColliding = value; } | 344 | set { _isColliding = value; } |
484 | } | 345 | } |
485 | public override bool CollidingGround { | 346 | public override bool CollidingGround { |
486 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | 347 | get { return (_collidingGroundStep == _scene.SimulationStep); } |
487 | set { CollidingGround = value; } | 348 | set { _collidingGround = value; } |
488 | } | ||
489 | public override bool CollidingObj { | ||
490 | get { return _collidingObj; } | ||
491 | set { _collidingObj = value; } | ||
492 | } | 349 | } |
493 | public override bool FloatOnWater { | 350 | public override bool CollidingObj { |
494 | set { | 351 | get { return _collidingObj; } |
495 | _floatOnWater = value; | 352 | set { _collidingObj = value; } |
496 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | ||
497 | { | ||
498 | if (_floatOnWater) | ||
499 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
500 | else | ||
501 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
502 | }); | ||
503 | } | ||
504 | } | 353 | } |
505 | public override OMV.Vector3 RotationalVelocity { | 354 | public override bool FloatOnWater { |
506 | get { return _rotationalVelocity; } | 355 | set { _floatOnWater = value; } |
507 | set { _rotationalVelocity = value; } | ||
508 | } | 356 | } |
509 | public override OMV.Vector3 ForceRotationalVelocity { | 357 | public override Vector3 RotationalVelocity { |
510 | get { return _rotationalVelocity; } | 358 | get { return _rotationalVelocity; } |
511 | set { _rotationalVelocity = value; } | 359 | set { _rotationalVelocity = value; } |
512 | } | 360 | } |
513 | public override bool Kinematic { | 361 | public override bool Kinematic { |
514 | get { return _kinematic; } | 362 | get { return _kinematic; } |
515 | set { _kinematic = value; } | 363 | set { _kinematic = value; } |
516 | } | 364 | } |
517 | // neg=fall quickly, 0=1g, 1=0g, pos=float up | 365 | // neg=fall quickly, 0=1g, 1=0g, pos=float up |
518 | public override float Buoyancy { | 366 | public override float Buoyancy { |
519 | get { return _buoyancy; } | 367 | get { return _buoyancy; } |
520 | set { _buoyancy = value; | 368 | set { _buoyancy = value; |
521 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 369 | _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() |
522 | { | 370 | { |
523 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 371 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
524 | ForceBuoyancy = _buoyancy; | 372 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); |
525 | }); | 373 | }); |
526 | } | 374 | } |
527 | } | ||
528 | public override float ForceBuoyancy { | ||
529 | get { return _buoyancy; } | ||
530 | set { _buoyancy = value; | ||
531 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
532 | // Buoyancy is faked by changing the gravity applied to the object | ||
533 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
534 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
535 | } | ||
536 | } | 375 | } |
537 | 376 | ||
538 | // Used for MoveTo | 377 | // Used for MoveTo |
539 | public override OMV.Vector3 PIDTarget { | 378 | public override Vector3 PIDTarget { |
540 | set { _PIDTarget = value; } | 379 | set { _PIDTarget = value; } |
541 | } | 380 | } |
542 | public override bool PIDActive { | 381 | public override bool PIDActive { |
543 | set { _usePID = value; } | 382 | set { _usePID = value; } |
544 | } | 383 | } |
545 | public override float PIDTau { | 384 | public override float PIDTau { |
546 | set { _PIDTau = value; } | 385 | set { _PIDTau = value; } |
547 | } | 386 | } |
548 | 387 | ||
549 | // Used for llSetHoverHeight and maybe vehicle height | 388 | // Used for llSetHoverHeight and maybe vehicle height |
550 | // Hover Height will override MoveTo target's Z | 389 | // Hover Height will override MoveTo target's Z |
551 | public override bool PIDHoverActive { | 390 | public override bool PIDHoverActive { |
552 | set { _useHoverPID = value; } | 391 | set { _useHoverPID = value; } |
553 | } | 392 | } |
554 | public override float PIDHoverHeight { | 393 | public override float PIDHoverHeight { |
555 | set { _PIDHoverHeight = value; } | 394 | set { _PIDHoverHeight = value; } |
556 | } | 395 | } |
557 | public override PIDHoverType PIDHoverType { | 396 | public override PIDHoverType PIDHoverType { |
558 | set { _PIDHoverType = value; } | 397 | set { _PIDHoverType = value; } |
559 | } | 398 | } |
560 | public override float PIDHoverTau { | 399 | public override float PIDHoverTau { |
561 | set { _PIDHoverTao = value; } | 400 | set { _PIDHoverTao = value; } |
562 | } | 401 | } |
563 | 402 | ||
564 | // For RotLookAt | 403 | // For RotLookAt |
565 | public override OMV.Quaternion APIDTarget { set { return; } } | 404 | public override Quaternion APIDTarget { set { return; } } |
566 | public override bool APIDActive { set { return; } } | 405 | public override bool APIDActive { set { return; } } |
567 | public override float APIDStrength { set { return; } } | 406 | public override float APIDStrength { set { return; } } |
568 | public override float APIDDamping { set { return; } } | 407 | public override float APIDDamping { set { return; } } |
569 | 408 | ||
570 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 409 | public override void AddForce(Vector3 force, bool pushforce) { |
571 | if (force.IsFinite()) | 410 | if (force.IsFinite()) |
572 | { | 411 | { |
573 | _force.X += force.X; | 412 | _force.X += force.X; |
574 | _force.Y += force.Y; | 413 | _force.Y += force.Y; |
575 | _force.Z += force.Z; | 414 | _force.Z += force.Z; |
576 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); | 415 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); |
577 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | 416 | _scene.TaintedObject("BSCharacter.AddForce", delegate() |
578 | { | 417 | { |
579 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | 418 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); |
580 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 419 | BulletSimAPI.AddObjectForce2(Body.Ptr, _force); |
581 | }); | 420 | }); |
582 | } | 421 | } |
583 | else | 422 | else |
@@ -587,75 +426,129 @@ public sealed class BSCharacter : BSPhysObject | |||
587 | //m_lastUpdateSent = false; | 426 | //m_lastUpdateSent = false; |
588 | } | 427 | } |
589 | 428 | ||
590 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 429 | public override void AddAngularForce(Vector3 force, bool pushforce) { |
591 | } | 430 | } |
592 | public override void SetMomentum(OMV.Vector3 momentum) { | 431 | public override void SetMomentum(Vector3 momentum) { |
593 | } | 432 | } |
594 | 433 | ||
595 | private void ComputeAvatarScale(OMV.Vector3 size) | 434 | // Turn on collision events at a rate no faster than one every the given milliseconds |
596 | { | 435 | public override void SubscribeEvents(int ms) { |
597 | // The 'size' given by the simulator is the mid-point of the avatar | 436 | _subscribedEventsMs = ms; |
598 | // and X and Y are unspecified. | 437 | if (ms > 0) |
599 | 438 | { | |
600 | OMV.Vector3 newScale = OMV.Vector3.Zero; | 439 | // make sure first collision happens |
601 | newScale.X = PhysicsScene.Params.avatarCapsuleRadius; | 440 | _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; |
602 | newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; | ||
603 | 441 | ||
604 | // From the total height, remove the capsule half spheres that are at each end | 442 | Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() |
605 | newScale.Z = size.Z- (newScale.X + newScale.Y); | 443 | { |
606 | Scale = newScale; | 444 | BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
445 | }); | ||
446 | } | ||
447 | } | ||
448 | // Stop collision events | ||
449 | public override void UnSubscribeEvents() { | ||
450 | _subscribedEventsMs = 0; | ||
451 | // Avatars get all their collision events | ||
452 | // Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate() | ||
453 | // { | ||
454 | // BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
455 | // }); | ||
456 | } | ||
457 | // Return 'true' if someone has subscribed to events | ||
458 | public override bool SubscribedEvents() { | ||
459 | return (_subscribedEventsMs > 0); | ||
607 | } | 460 | } |
608 | 461 | ||
609 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 462 | // set _avatarVolume and _mass based on capsule size, _density and _scale |
610 | private void ComputeAvatarVolumeAndMass() | 463 | private void ComputeAvatarVolumeAndMass() |
611 | { | 464 | { |
612 | _avatarVolume = (float)( | 465 | _avatarVolume = (float)( |
613 | Math.PI | 466 | Math.PI |
614 | * Scale.X | 467 | * _scale.X |
615 | * Scale.Y // the area of capsule cylinder | 468 | * _scale.Y // the area of capsule cylinder |
616 | * Scale.Z // times height of capsule cylinder | 469 | * _scale.Z // times height of capsule cylinder |
617 | + 1.33333333f | 470 | + 1.33333333f |
618 | * Math.PI | 471 | * Math.PI |
619 | * Scale.X | 472 | * _scale.X |
620 | * Math.Min(Scale.X, Scale.Y) | 473 | * Math.Min(_scale.X, _scale.Y) |
621 | * Scale.Y // plus the volume of the capsule end caps | 474 | * _scale.Y // plus the volume of the capsule end caps |
622 | ); | 475 | ); |
623 | _mass = _avatarDensity * _avatarVolume; | 476 | _mass = _density * _avatarVolume; |
624 | } | 477 | } |
625 | 478 | ||
626 | // The physics engine says that properties have updated. Update same and inform | 479 | // The physics engine says that properties have updated. Update same and inform |
627 | // the world that things have changed. | 480 | // the world that things have changed. |
628 | public override void UpdateProperties(EntityProperties entprop) | 481 | public void UpdateProperties(EntityProperties entprop) |
629 | { | 482 | { |
630 | _position = entprop.Position; | 483 | _position = entprop.Position; |
631 | _orientation = entprop.Rotation; | 484 | _orientation = entprop.Rotation; |
632 | _velocity = entprop.Velocity; | 485 | _velocity = entprop.Velocity; |
633 | _acceleration = entprop.Acceleration; | 486 | _acceleration = entprop.Acceleration; |
634 | _rotationalVelocity = entprop.RotationalVelocity; | 487 | _rotationalVelocity = entprop.RotationalVelocity; |
635 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 488 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
636 | PositionSanityCheck(true); | 489 | // base.RequestPhysicsterseUpdate(); |
490 | |||
491 | /* | ||
492 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
493 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
494 | entprop.Acceleration, entprop.RotationalVelocity); | ||
495 | */ | ||
496 | } | ||
637 | 497 | ||
638 | // remember the current and last set values | 498 | // Called by the scene when a collision with this object is reported |
639 | LastEntityProperties = CurrentEntityProperties; | 499 | // The collision, if it should be reported to the character, is placed in a collection |
640 | CurrentEntityProperties = entprop; | 500 | // that will later be sent to the simulator when SendCollisions() is called. |
501 | CollisionEventUpdate collisionCollection = null; | ||
502 | public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth) | ||
503 | { | ||
504 | // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); | ||
641 | 505 | ||
642 | if (entprop.Velocity != LastEntityProperties.Velocity) | 506 | // The following makes IsColliding() and IsCollidingGround() work |
507 | _collidingStep = _scene.SimulationStep; | ||
508 | if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) | ||
643 | { | 509 | { |
644 | // Changes in the velocity are suppressed in avatars. | 510 | _collidingGroundStep = _scene.SimulationStep; |
645 | // That's just the way they are defined. | ||
646 | OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); | ||
647 | _velocity = avVel; | ||
648 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel); | ||
649 | } | 511 | } |
512 | // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith); | ||
650 | 513 | ||
651 | // Tell the linkset about value changes | 514 | // throttle collisions to the rate specified in the subscription |
652 | Linkset.UpdateProperties(this); | 515 | if (_subscribedEventsMs != 0) { |
516 | int nowTime = _scene.SimulationNowTime; | ||
517 | if (nowTime >= _nextCollisionOkTime) { | ||
518 | _nextCollisionOkTime = nowTime + _subscribedEventsMs; | ||
653 | 519 | ||
654 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 520 | if (collisionCollection == null) |
655 | // base.RequestPhysicsterseUpdate(); | 521 | collisionCollection = new CollisionEventUpdate(); |
522 | collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
523 | } | ||
524 | } | ||
525 | } | ||
656 | 526 | ||
657 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 527 | public void SendCollisions() |
658 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 528 | { |
529 | /* | ||
530 | if (collisionCollection != null && collisionCollection.Count > 0) | ||
531 | { | ||
532 | base.SendCollisionUpdate(collisionCollection); | ||
533 | collisionCollection = null; | ||
534 | } | ||
535 | */ | ||
536 | // Kludge to make a collision call even if there are no collisions. | ||
537 | // This causes the avatar animation to get updated. | ||
538 | if (collisionCollection == null) | ||
539 | collisionCollection = new CollisionEventUpdate(); | ||
540 | base.SendCollisionUpdate(collisionCollection); | ||
541 | // If there were any collisions in the collection, make sure we don't use the | ||
542 | // same instance next time. | ||
543 | if (collisionCollection.Count > 0) | ||
544 | collisionCollection = null; | ||
545 | // End kludge | ||
546 | } | ||
547 | |||
548 | // Invoke the detailed logger and output something if it's enabled. | ||
549 | private void DetailLog(string msg, params Object[] args) | ||
550 | { | ||
551 | Scene.PhysicsLogging.Write(msg, args); | ||
659 | } | 552 | } |
660 | } | 553 | } |
661 | } | 554 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 65fac00..25084d8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -34,20 +34,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
34 | 34 | ||
35 | public abstract class BSConstraint : IDisposable | 35 | public abstract class BSConstraint : IDisposable |
36 | { | 36 | { |
37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; | ||
38 | |||
39 | protected BulletSim m_world; | 37 | protected BulletSim m_world; |
40 | protected BulletBody m_body1; | 38 | protected BulletBody m_body1; |
41 | protected BulletBody m_body2; | 39 | protected BulletBody m_body2; |
42 | protected BulletConstraint m_constraint; | 40 | protected BulletConstraint m_constraint; |
43 | protected bool m_enabled = false; | 41 | protected bool m_enabled = false; |
44 | 42 | ||
45 | public BulletBody Body1 { get { return m_body1; } } | ||
46 | public BulletBody Body2 { get { return m_body2; } } | ||
47 | public BulletConstraint Constraint { get { return m_constraint; } } | ||
48 | public abstract ConstraintType Type { get; } | ||
49 | public bool IsEnabled { get { return m_enabled; } } | ||
50 | |||
51 | public BSConstraint() | 43 | public BSConstraint() |
52 | { | 44 | { |
53 | } | 45 | } |
@@ -56,25 +48,22 @@ public abstract class BSConstraint : IDisposable | |||
56 | { | 48 | { |
57 | if (m_enabled) | 49 | if (m_enabled) |
58 | { | 50 | { |
51 | // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID); | ||
52 | bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr); | ||
53 | m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); | ||
54 | m_constraint.Ptr = System.IntPtr.Zero; | ||
59 | m_enabled = false; | 55 | m_enabled = false; |
60 | if (m_constraint.ptr != IntPtr.Zero) | ||
61 | { | ||
62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | ||
63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | ||
64 | BSScene.DetailLogZero, | ||
65 | m_body1.ID, m_body1.ptr.ToString("X"), | ||
66 | m_body2.ID, m_body2.ptr.ToString("X"), | ||
67 | success); | ||
68 | m_constraint.ptr = System.IntPtr.Zero; | ||
69 | } | ||
70 | } | 56 | } |
71 | } | 57 | } |
72 | 58 | ||
59 | public BulletBody Body1 { get { return m_body1; } } | ||
60 | public BulletBody Body2 { get { return m_body2; } } | ||
61 | |||
73 | public virtual bool SetLinearLimits(Vector3 low, Vector3 high) | 62 | public virtual bool SetLinearLimits(Vector3 low, Vector3 high) |
74 | { | 63 | { |
75 | bool ret = false; | 64 | bool ret = false; |
76 | if (m_enabled) | 65 | if (m_enabled) |
77 | ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); | 66 | ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); |
78 | return ret; | 67 | return ret; |
79 | } | 68 | } |
80 | 69 | ||
@@ -82,18 +71,7 @@ public abstract class BSConstraint : IDisposable | |||
82 | { | 71 | { |
83 | bool ret = false; | 72 | bool ret = false; |
84 | if (m_enabled) | 73 | if (m_enabled) |
85 | ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); | 74 | ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); |
86 | return ret; | ||
87 | } | ||
88 | |||
89 | public virtual bool SetSolverIterations(float cnt) | ||
90 | { | ||
91 | bool ret = false; | ||
92 | if (m_enabled) | ||
93 | { | ||
94 | BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); | ||
95 | ret = true; | ||
96 | } | ||
97 | return ret; | 75 | return ret; |
98 | } | 76 | } |
99 | 77 | ||
@@ -103,7 +81,7 @@ public abstract class BSConstraint : IDisposable | |||
103 | if (m_enabled) | 81 | if (m_enabled) |
104 | { | 82 | { |
105 | // Recompute the internal transforms | 83 | // Recompute the internal transforms |
106 | BulletSimAPI.CalculateTransforms2(m_constraint.ptr); | 84 | BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); |
107 | ret = true; | 85 | ret = true; |
108 | } | 86 | } |
109 | return ret; | 87 | return ret; |
@@ -119,14 +97,13 @@ public abstract class BSConstraint : IDisposable | |||
119 | ret = CalculateTransforms(); | 97 | ret = CalculateTransforms(); |
120 | if (ret) | 98 | if (ret) |
121 | { | 99 | { |
122 | // Setting an object's mass to zero (making it static like when it's selected) | 100 | // m_world.scene.PhysicsLogging.Write("{0},BSConstraint.RecomputeConstraintVariables,taint,enabling,A={1},B={2}", |
123 | // automatically disables the constraints. | 101 | // BSScene.DetailLogZero, Body1.ID, Body2.ID); |
124 | // If the link is enabled, be sure to set the constraint itself to enabled. | 102 | BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); |
125 | BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); | ||
126 | } | 103 | } |
127 | else | 104 | else |
128 | { | 105 | { |
129 | m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); | 106 | m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); |
130 | } | 107 | } |
131 | } | 108 | } |
132 | return ret; | 109 | return ret; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs index a9fd826..22ea367 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs | |||
@@ -33,7 +33,7 @@ using OpenMetaverse; | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | 35 | ||
36 | public sealed class BSConstraintCollection : IDisposable | 36 | public class BSConstraintCollection : IDisposable |
37 | { | 37 | { |
38 | // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 38 | // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
39 | // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; | 39 | // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; |
@@ -143,6 +143,8 @@ public sealed class BSConstraintCollection : IDisposable | |||
143 | // Return 'true' if any constraints were destroyed. | 143 | // Return 'true' if any constraints were destroyed. |
144 | public bool RemoveAndDestroyConstraint(BulletBody body1) | 144 | public bool RemoveAndDestroyConstraint(BulletBody body1) |
145 | { | 145 | { |
146 | // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID); | ||
147 | |||
146 | List<BSConstraint> toRemove = new List<BSConstraint>(); | 148 | List<BSConstraint> toRemove = new List<BSConstraint>(); |
147 | uint lookingID = body1.ID; | 149 | uint lookingID = body1.ID; |
148 | lock (m_constraints) | 150 | lock (m_constraints) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 819635a..5a9f135 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -23,7 +23,7 @@ | |||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | */ |
27 | 27 | ||
28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to | 28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to |
29 | * call the BulletSim system. | 29 | * call the BulletSim system. |
@@ -52,15 +52,19 @@ using OpenSim.Region.Physics.Manager; | |||
52 | 52 | ||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | 53 | namespace OpenSim.Region.Physics.BulletSPlugin |
54 | { | 54 | { |
55 | public sealed class BSDynamics | 55 | public class BSDynamics |
56 | { | 56 | { |
57 | private BSScene PhysicsScene { get; set; } | 57 | private int frcount = 0; // Used to limit dynamics debug output to |
58 | // the prim this dynamic controller belongs to | 58 | // every 100th frame |
59 | private BSPrim Prim { get; set; } | ||
60 | 59 | ||
61 | // Vehicle properties | 60 | private BSPrim m_prim; // the prim this dynamic controller belongs to |
62 | public Vehicle Type { get; set; } | ||
63 | 61 | ||
62 | // Vehicle properties | ||
63 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | ||
64 | public Vehicle Type | ||
65 | { | ||
66 | get { return m_type; } | ||
67 | } | ||
64 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | 68 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier |
65 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | 69 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: |
66 | // HOVER_TERRAIN_ONLY | 70 | // HOVER_TERRAIN_ONLY |
@@ -70,15 +74,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
70 | // HOVER_UP_ONLY | 74 | // HOVER_UP_ONLY |
71 | // LIMIT_MOTOR_UP | 75 | // LIMIT_MOTOR_UP |
72 | // LIMIT_ROLL_ONLY | 76 | // LIMIT_ROLL_ONLY |
77 | private VehicleFlag m_Hoverflags = (VehicleFlag)0; | ||
73 | private Vector3 m_BlockingEndPoint = Vector3.Zero; | 78 | private Vector3 m_BlockingEndPoint = Vector3.Zero; |
74 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; | 79 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; |
75 | private Quaternion m_referenceFrame = Quaternion.Identity; | ||
76 | |||
77 | // Linear properties | 80 | // Linear properties |
78 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 81 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
79 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | ||
80 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 82 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
81 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | 83 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body |
82 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 84 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
83 | private float m_linearMotorDecayTimescale = 0; | 85 | private float m_linearMotorDecayTimescale = 0; |
84 | private float m_linearMotorTimescale = 0; | 86 | private float m_linearMotorTimescale = 0; |
@@ -89,28 +91,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
89 | 91 | ||
90 | //Angular properties | 92 | //Angular properties |
91 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 93 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
92 | // private int m_angularMotorApply = 0; // application frame counter | 94 | private int m_angularMotorApply = 0; // application frame counter |
93 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 95 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
94 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 96 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
95 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 97 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
96 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 98 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
97 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 99 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body |
98 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 100 | // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
99 | 101 | ||
100 | //Deflection properties | 102 | //Deflection properties |
101 | private float m_angularDeflectionEfficiency = 0; | 103 | // private float m_angularDeflectionEfficiency = 0; |
102 | private float m_angularDeflectionTimescale = 0; | 104 | // private float m_angularDeflectionTimescale = 0; |
103 | private float m_linearDeflectionEfficiency = 0; | 105 | // private float m_linearDeflectionEfficiency = 0; |
104 | private float m_linearDeflectionTimescale = 0; | 106 | // private float m_linearDeflectionTimescale = 0; |
105 | 107 | ||
106 | //Banking properties | 108 | //Banking properties |
107 | private float m_bankingEfficiency = 0; | 109 | // private float m_bankingEfficiency = 0; |
108 | private float m_bankingMix = 0; | 110 | // private float m_bankingMix = 0; |
109 | private float m_bankingTimescale = 0; | 111 | // private float m_bankingTimescale = 0; |
110 | 112 | ||
111 | //Hover and Buoyancy properties | 113 | //Hover and Buoyancy properties |
112 | private float m_VhoverHeight = 0f; | 114 | private float m_VhoverHeight = 0f; |
113 | private float m_VhoverEfficiency = 0f; | 115 | // private float m_VhoverEfficiency = 0f; |
114 | private float m_VhoverTimescale = 0f; | 116 | private float m_VhoverTimescale = 0f; |
115 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | 117 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height |
116 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | 118 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. |
@@ -122,74 +124,86 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
122 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 124 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
123 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 125 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. |
124 | 126 | ||
125 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 127 | public BSDynamics(BSPrim myPrim) |
126 | { | ||
127 | PhysicsScene = myScene; | ||
128 | Prim = myPrim; | ||
129 | Type = Vehicle.TYPE_NONE; | ||
130 | } | ||
131 | |||
132 | // Return 'true' if this vehicle is doing vehicle things | ||
133 | public bool IsActive | ||
134 | { | 128 | { |
135 | get { return Type != Vehicle.TYPE_NONE; } | 129 | m_prim = myPrim; |
130 | m_type = Vehicle.TYPE_NONE; | ||
136 | } | 131 | } |
137 | 132 | ||
138 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 133 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep) |
139 | { | 134 | { |
140 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 135 | DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); |
141 | switch (pParam) | 136 | switch (pParam) |
142 | { | 137 | { |
143 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 138 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
144 | m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); | 139 | if (pValue < 0.01f) pValue = 0.01f; |
140 | // m_angularDeflectionEfficiency = pValue; | ||
145 | break; | 141 | break; |
146 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | 142 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: |
147 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 143 | if (pValue < 0.01f) pValue = 0.01f; |
144 | // m_angularDeflectionTimescale = pValue; | ||
148 | break; | 145 | break; |
149 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 146 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
150 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 147 | if (pValue < 0.01f) pValue = 0.01f; |
148 | m_angularMotorDecayTimescale = pValue; | ||
151 | break; | 149 | break; |
152 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 150 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
153 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 151 | if (pValue < 0.01f) pValue = 0.01f; |
152 | m_angularMotorTimescale = pValue; | ||
154 | break; | 153 | break; |
155 | case Vehicle.BANKING_EFFICIENCY: | 154 | case Vehicle.BANKING_EFFICIENCY: |
156 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 155 | if (pValue < 0.01f) pValue = 0.01f; |
156 | // m_bankingEfficiency = pValue; | ||
157 | break; | 157 | break; |
158 | case Vehicle.BANKING_MIX: | 158 | case Vehicle.BANKING_MIX: |
159 | m_bankingMix = Math.Max(pValue, 0.01f); | 159 | if (pValue < 0.01f) pValue = 0.01f; |
160 | // m_bankingMix = pValue; | ||
160 | break; | 161 | break; |
161 | case Vehicle.BANKING_TIMESCALE: | 162 | case Vehicle.BANKING_TIMESCALE: |
162 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 163 | if (pValue < 0.01f) pValue = 0.01f; |
164 | // m_bankingTimescale = pValue; | ||
163 | break; | 165 | break; |
164 | case Vehicle.BUOYANCY: | 166 | case Vehicle.BUOYANCY: |
165 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 167 | if (pValue < -1f) pValue = -1f; |
166 | break; | 168 | if (pValue > 1f) pValue = 1f; |
167 | case Vehicle.HOVER_EFFICIENCY: | 169 | m_VehicleBuoyancy = pValue; |
168 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 170 | break; |
169 | break; | 171 | // case Vehicle.HOVER_EFFICIENCY: |
172 | // if (pValue < 0f) pValue = 0f; | ||
173 | // if (pValue > 1f) pValue = 1f; | ||
174 | // m_VhoverEfficiency = pValue; | ||
175 | // break; | ||
170 | case Vehicle.HOVER_HEIGHT: | 176 | case Vehicle.HOVER_HEIGHT: |
171 | m_VhoverHeight = pValue; | 177 | m_VhoverHeight = pValue; |
172 | break; | 178 | break; |
173 | case Vehicle.HOVER_TIMESCALE: | 179 | case Vehicle.HOVER_TIMESCALE: |
174 | m_VhoverTimescale = Math.Max(pValue, 0.01f); | 180 | if (pValue < 0.01f) pValue = 0.01f; |
181 | m_VhoverTimescale = pValue; | ||
175 | break; | 182 | break; |
176 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | 183 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: |
177 | m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); | 184 | if (pValue < 0.01f) pValue = 0.01f; |
185 | // m_linearDeflectionEfficiency = pValue; | ||
178 | break; | 186 | break; |
179 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | 187 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: |
180 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 188 | if (pValue < 0.01f) pValue = 0.01f; |
189 | // m_linearDeflectionTimescale = pValue; | ||
181 | break; | 190 | break; |
182 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 191 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
183 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 192 | if (pValue < 0.01f) pValue = 0.01f; |
193 | m_linearMotorDecayTimescale = pValue; | ||
184 | break; | 194 | break; |
185 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 195 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
186 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | 196 | if (pValue < 0.01f) pValue = 0.01f; |
197 | m_linearMotorTimescale = pValue; | ||
187 | break; | 198 | break; |
188 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 199 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
189 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 200 | if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable |
201 | if (pValue > 1.0f) pValue = 1.0f; | ||
202 | m_verticalAttractionEfficiency = pValue; | ||
190 | break; | 203 | break; |
191 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 204 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
192 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 205 | if (pValue < 0.01f) pValue = 0.01f; |
206 | m_verticalAttractionTimescale = pValue; | ||
193 | break; | 207 | break; |
194 | 208 | ||
195 | // These are vector properties but the engine lets you use a single float value to | 209 | // These are vector properties but the engine lets you use a single float value to |
@@ -199,7 +213,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
199 | break; | 213 | break; |
200 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 214 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
201 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 215 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
202 | // m_angularMotorApply = 100; | 216 | m_angularMotorApply = 10; |
203 | break; | 217 | break; |
204 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 218 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
205 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 219 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
@@ -209,27 +223,30 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
209 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 223 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
210 | break; | 224 | break; |
211 | case Vehicle.LINEAR_MOTOR_OFFSET: | 225 | case Vehicle.LINEAR_MOTOR_OFFSET: |
212 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 226 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
213 | break; | 227 | break; |
214 | 228 | ||
215 | } | 229 | } |
216 | }//end ProcessFloatVehicleParam | 230 | }//end ProcessFloatVehicleParam |
217 | 231 | ||
218 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | 232 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep) |
219 | { | 233 | { |
220 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 234 | DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); |
221 | switch (pParam) | 235 | switch (pParam) |
222 | { | 236 | { |
223 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 237 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
224 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 238 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
225 | break; | 239 | break; |
226 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 240 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
227 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | ||
228 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | ||
229 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | ||
230 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | ||
231 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 241 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
232 | // m_angularMotorApply = 100; | 242 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
243 | if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; | ||
244 | if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; | ||
245 | if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; | ||
246 | if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; | ||
247 | if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; | ||
248 | if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; | ||
249 | m_angularMotorApply = 10; | ||
233 | break; | 250 | break; |
234 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 251 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
235 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 252 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -239,7 +256,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
239 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 256 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
240 | break; | 257 | break; |
241 | case Vehicle.LINEAR_MOTOR_OFFSET: | 258 | case Vehicle.LINEAR_MOTOR_OFFSET: |
242 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 259 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
243 | break; | 260 | break; |
244 | case Vehicle.BLOCK_EXIT: | 261 | case Vehicle.BLOCK_EXIT: |
245 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); | 262 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -249,11 +266,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
249 | 266 | ||
250 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | 267 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) |
251 | { | 268 | { |
252 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 269 | DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); |
253 | switch (pParam) | 270 | switch (pParam) |
254 | { | 271 | { |
255 | case Vehicle.REFERENCE_FRAME: | 272 | case Vehicle.REFERENCE_FRAME: |
256 | m_referenceFrame = pValue; | 273 | // m_referenceFrame = pValue; |
257 | break; | 274 | break; |
258 | case Vehicle.ROLL_FRAME: | 275 | case Vehicle.ROLL_FRAME: |
259 | m_RollreferenceFrame = pValue; | 276 | m_RollreferenceFrame = pValue; |
@@ -263,492 +280,575 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
263 | 280 | ||
264 | internal void ProcessVehicleFlags(int pParam, bool remove) | 281 | internal void ProcessVehicleFlags(int pParam, bool remove) |
265 | { | 282 | { |
266 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | 283 | DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); |
267 | VehicleFlag parm = (VehicleFlag)pParam; | 284 | if (remove) |
268 | if (pParam == -1) | 285 | { |
269 | m_flags = (VehicleFlag)0; | 286 | if (pParam == -1) |
287 | { | ||
288 | m_flags = (VehicleFlag)0; | ||
289 | m_Hoverflags = (VehicleFlag)0; | ||
290 | return; | ||
291 | } | ||
292 | if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
293 | { | ||
294 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0) | ||
295 | m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
296 | } | ||
297 | if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) | ||
298 | { | ||
299 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0) | ||
300 | m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY); | ||
301 | } | ||
302 | if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) | ||
303 | { | ||
304 | if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0) | ||
305 | m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY); | ||
306 | } | ||
307 | if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) | ||
308 | { | ||
309 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0) | ||
310 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY); | ||
311 | } | ||
312 | if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) | ||
313 | { | ||
314 | if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0) | ||
315 | m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP); | ||
316 | } | ||
317 | if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY) | ||
318 | { | ||
319 | if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0) | ||
320 | m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); | ||
321 | } | ||
322 | if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) | ||
323 | { | ||
324 | if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0) | ||
325 | m_flags &= ~(VehicleFlag.MOUSELOOK_BANK); | ||
326 | } | ||
327 | if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) | ||
328 | { | ||
329 | if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0) | ||
330 | m_flags &= ~(VehicleFlag.MOUSELOOK_STEER); | ||
331 | } | ||
332 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) | ||
333 | { | ||
334 | if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0) | ||
335 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP); | ||
336 | } | ||
337 | if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) | ||
338 | { | ||
339 | if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0) | ||
340 | m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED); | ||
341 | } | ||
342 | if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) | ||
343 | { | ||
344 | if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0) | ||
345 | m_flags &= ~(VehicleFlag.NO_X); | ||
346 | } | ||
347 | if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) | ||
348 | { | ||
349 | if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0) | ||
350 | m_flags &= ~(VehicleFlag.NO_Y); | ||
351 | } | ||
352 | if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) | ||
353 | { | ||
354 | if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0) | ||
355 | m_flags &= ~(VehicleFlag.NO_Z); | ||
356 | } | ||
357 | if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) | ||
358 | { | ||
359 | if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0) | ||
360 | m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT); | ||
361 | } | ||
362 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) | ||
363 | { | ||
364 | if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0) | ||
365 | m_flags &= ~(VehicleFlag.NO_DEFLECTION); | ||
366 | } | ||
367 | if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) | ||
368 | { | ||
369 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) | ||
370 | m_flags &= ~(VehicleFlag.LOCK_ROTATION); | ||
371 | } | ||
372 | } | ||
270 | else | 373 | else |
271 | { | 374 | { |
272 | if (remove) | 375 | if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) |
273 | m_flags &= ~parm; | 376 | { |
274 | else | 377 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags); |
275 | m_flags |= parm; | 378 | } |
379 | if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) | ||
380 | { | ||
381 | m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags); | ||
382 | } | ||
383 | if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) | ||
384 | { | ||
385 | m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags); | ||
386 | } | ||
387 | if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) | ||
388 | { | ||
389 | m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags); | ||
390 | } | ||
391 | if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) | ||
392 | { | ||
393 | m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags); | ||
394 | } | ||
395 | if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) | ||
396 | { | ||
397 | m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags); | ||
398 | } | ||
399 | if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) | ||
400 | { | ||
401 | m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags); | ||
402 | } | ||
403 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) | ||
404 | { | ||
405 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags); | ||
406 | } | ||
407 | if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) | ||
408 | { | ||
409 | m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags); | ||
410 | } | ||
411 | if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) | ||
412 | { | ||
413 | m_flags |= (VehicleFlag.NO_X); | ||
414 | } | ||
415 | if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) | ||
416 | { | ||
417 | m_flags |= (VehicleFlag.NO_Y); | ||
418 | } | ||
419 | if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) | ||
420 | { | ||
421 | m_flags |= (VehicleFlag.NO_Z); | ||
422 | } | ||
423 | if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) | ||
424 | { | ||
425 | m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT); | ||
426 | } | ||
427 | if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) | ||
428 | { | ||
429 | m_flags |= (VehicleFlag.NO_DEFLECTION); | ||
430 | } | ||
431 | if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) | ||
432 | { | ||
433 | m_flags |= (VehicleFlag.LOCK_ROTATION); | ||
434 | } | ||
276 | } | 435 | } |
277 | } | 436 | }//end ProcessVehicleFlags |
278 | 437 | ||
279 | internal void ProcessTypeChange(Vehicle pType) | 438 | internal void ProcessTypeChange(Vehicle pType) |
280 | { | 439 | { |
281 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | 440 | DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); |
282 | // Set Defaults For Type | 441 | // Set Defaults For Type |
283 | Type = pType; | 442 | m_type = pType; |
284 | switch (pType) | 443 | switch (pType) |
285 | { | 444 | { |
286 | case Vehicle.TYPE_NONE: | 445 | case Vehicle.TYPE_NONE: |
446 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
447 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | ||
287 | m_linearMotorDirection = Vector3.Zero; | 448 | m_linearMotorDirection = Vector3.Zero; |
288 | m_linearMotorTimescale = 0; | 449 | m_linearMotorTimescale = 0; |
289 | m_linearMotorDecayTimescale = 0; | 450 | m_linearMotorDecayTimescale = 0; |
290 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
291 | |||
292 | m_angularMotorDirection = Vector3.Zero; | 451 | m_angularMotorDirection = Vector3.Zero; |
293 | m_angularMotorDecayTimescale = 0; | ||
294 | m_angularMotorTimescale = 0; | 452 | m_angularMotorTimescale = 0; |
295 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | 453 | m_angularMotorDecayTimescale = 0; |
296 | |||
297 | m_VhoverHeight = 0; | 454 | m_VhoverHeight = 0; |
298 | m_VhoverEfficiency = 0; | ||
299 | m_VhoverTimescale = 0; | 455 | m_VhoverTimescale = 0; |
300 | m_VehicleBuoyancy = 0; | 456 | m_VehicleBuoyancy = 0; |
301 | |||
302 | m_linearDeflectionEfficiency = 1; | ||
303 | m_linearDeflectionTimescale = 1; | ||
304 | |||
305 | m_angularDeflectionEfficiency = 0; | ||
306 | m_angularDeflectionTimescale = 1000; | ||
307 | |||
308 | m_verticalAttractionEfficiency = 0; | ||
309 | m_verticalAttractionTimescale = 0; | ||
310 | |||
311 | m_bankingEfficiency = 0; | ||
312 | m_bankingTimescale = 1000; | ||
313 | m_bankingMix = 1; | ||
314 | |||
315 | m_referenceFrame = Quaternion.Identity; | ||
316 | m_flags = (VehicleFlag)0; | 457 | m_flags = (VehicleFlag)0; |
317 | break; | 458 | break; |
318 | 459 | ||
319 | case Vehicle.TYPE_SLED: | 460 | case Vehicle.TYPE_SLED: |
461 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
462 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
320 | m_linearMotorDirection = Vector3.Zero; | 463 | m_linearMotorDirection = Vector3.Zero; |
321 | m_linearMotorTimescale = 1000; | 464 | m_linearMotorTimescale = 1000; |
322 | m_linearMotorDecayTimescale = 120; | 465 | m_linearMotorDecayTimescale = 120; |
323 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
324 | |||
325 | m_angularMotorDirection = Vector3.Zero; | 466 | m_angularMotorDirection = Vector3.Zero; |
326 | m_angularMotorTimescale = 1000; | 467 | m_angularMotorTimescale = 1000; |
327 | m_angularMotorDecayTimescale = 120; | 468 | m_angularMotorDecayTimescale = 120; |
328 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
329 | |||
330 | m_VhoverHeight = 0; | 469 | m_VhoverHeight = 0; |
331 | m_VhoverEfficiency = 10; // TODO: this looks wrong!! | 470 | // m_VhoverEfficiency = 1; |
332 | m_VhoverTimescale = 10; | 471 | m_VhoverTimescale = 10; |
333 | m_VehicleBuoyancy = 0; | 472 | m_VehicleBuoyancy = 0; |
334 | 473 | // m_linearDeflectionEfficiency = 1; | |
335 | m_linearDeflectionEfficiency = 1; | 474 | // m_linearDeflectionTimescale = 1; |
336 | m_linearDeflectionTimescale = 1; | 475 | // m_angularDeflectionEfficiency = 1; |
337 | 476 | // m_angularDeflectionTimescale = 1000; | |
338 | m_angularDeflectionEfficiency = 1; | 477 | // m_bankingEfficiency = 0; |
339 | m_angularDeflectionTimescale = 1000; | 478 | // m_bankingMix = 1; |
340 | 479 | // m_bankingTimescale = 10; | |
341 | m_verticalAttractionEfficiency = 0; | 480 | // m_referenceFrame = Quaternion.Identity; |
342 | m_verticalAttractionTimescale = 0; | 481 | m_Hoverflags &= |
343 | |||
344 | m_bankingEfficiency = 0; | ||
345 | m_bankingTimescale = 10; | ||
346 | m_bankingMix = 1; | ||
347 | |||
348 | m_referenceFrame = Quaternion.Identity; | ||
349 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
350 | m_flags &= | ||
351 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 482 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | |
352 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 483 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); |
484 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
353 | break; | 485 | break; |
354 | case Vehicle.TYPE_CAR: | 486 | case Vehicle.TYPE_CAR: |
487 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
488 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
355 | m_linearMotorDirection = Vector3.Zero; | 489 | m_linearMotorDirection = Vector3.Zero; |
356 | m_linearMotorTimescale = 1; | 490 | m_linearMotorTimescale = 1; |
357 | m_linearMotorDecayTimescale = 60; | 491 | m_linearMotorDecayTimescale = 60; |
358 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
359 | |||
360 | m_angularMotorDirection = Vector3.Zero; | 492 | m_angularMotorDirection = Vector3.Zero; |
361 | m_angularMotorTimescale = 1; | 493 | m_angularMotorTimescale = 1; |
362 | m_angularMotorDecayTimescale = 0.8f; | 494 | m_angularMotorDecayTimescale = 0.8f; |
363 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
364 | |||
365 | m_VhoverHeight = 0; | 495 | m_VhoverHeight = 0; |
366 | m_VhoverEfficiency = 0; | 496 | // m_VhoverEfficiency = 0; |
367 | m_VhoverTimescale = 1000; | 497 | m_VhoverTimescale = 1000; |
368 | m_VehicleBuoyancy = 0; | 498 | m_VehicleBuoyancy = 0; |
369 | 499 | // // m_linearDeflectionEfficiency = 1; | |
370 | m_linearDeflectionEfficiency = 1; | 500 | // // m_linearDeflectionTimescale = 2; |
371 | m_linearDeflectionTimescale = 2; | 501 | // // m_angularDeflectionEfficiency = 0; |
372 | 502 | // m_angularDeflectionTimescale = 10; | |
373 | m_angularDeflectionEfficiency = 0; | ||
374 | m_angularDeflectionTimescale = 10; | ||
375 | |||
376 | m_verticalAttractionEfficiency = 1f; | 503 | m_verticalAttractionEfficiency = 1f; |
377 | m_verticalAttractionTimescale = 10f; | 504 | m_verticalAttractionTimescale = 10f; |
378 | 505 | // m_bankingEfficiency = -0.2f; | |
379 | m_bankingEfficiency = -0.2f; | 506 | // m_bankingMix = 1; |
380 | m_bankingMix = 1; | 507 | // m_bankingTimescale = 1; |
381 | m_bankingTimescale = 1; | 508 | // m_referenceFrame = Quaternion.Identity; |
382 | 509 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | |
383 | m_referenceFrame = Quaternion.Identity; | 510 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | |
384 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 511 | VehicleFlag.LIMIT_MOTOR_UP); |
385 | | VehicleFlag.HOVER_TERRAIN_ONLY | 512 | m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); |
386 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
387 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
388 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
389 | | VehicleFlag.LIMIT_MOTOR_UP | ||
390 | | VehicleFlag.HOVER_UP_ONLY); | ||
391 | break; | 513 | break; |
392 | case Vehicle.TYPE_BOAT: | 514 | case Vehicle.TYPE_BOAT: |
515 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
516 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
393 | m_linearMotorDirection = Vector3.Zero; | 517 | m_linearMotorDirection = Vector3.Zero; |
394 | m_linearMotorTimescale = 5; | 518 | m_linearMotorTimescale = 5; |
395 | m_linearMotorDecayTimescale = 60; | 519 | m_linearMotorDecayTimescale = 60; |
396 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
397 | |||
398 | m_angularMotorDirection = Vector3.Zero; | 520 | m_angularMotorDirection = Vector3.Zero; |
399 | m_angularMotorTimescale = 4; | 521 | m_angularMotorTimescale = 4; |
400 | m_angularMotorDecayTimescale = 4; | 522 | m_angularMotorDecayTimescale = 4; |
401 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
402 | |||
403 | m_VhoverHeight = 0; | 523 | m_VhoverHeight = 0; |
404 | m_VhoverEfficiency = 0.5f; | 524 | // m_VhoverEfficiency = 0.5f; |
405 | m_VhoverTimescale = 2; | 525 | m_VhoverTimescale = 2; |
406 | m_VehicleBuoyancy = 1; | 526 | m_VehicleBuoyancy = 1; |
407 | 527 | // m_linearDeflectionEfficiency = 0.5f; | |
408 | m_linearDeflectionEfficiency = 0.5f; | 528 | // m_linearDeflectionTimescale = 3; |
409 | m_linearDeflectionTimescale = 3; | 529 | // m_angularDeflectionEfficiency = 0.5f; |
410 | 530 | // m_angularDeflectionTimescale = 5; | |
411 | m_angularDeflectionEfficiency = 0.5f; | ||
412 | m_angularDeflectionTimescale = 5; | ||
413 | |||
414 | m_verticalAttractionEfficiency = 0.5f; | 531 | m_verticalAttractionEfficiency = 0.5f; |
415 | m_verticalAttractionTimescale = 5f; | 532 | m_verticalAttractionTimescale = 5f; |
416 | 533 | // m_bankingEfficiency = -0.3f; | |
417 | m_bankingEfficiency = -0.3f; | 534 | // m_bankingMix = 0.8f; |
418 | m_bankingMix = 0.8f; | 535 | // m_bankingTimescale = 1; |
419 | m_bankingTimescale = 1; | 536 | // m_referenceFrame = Quaternion.Identity; |
420 | 537 | m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | | |
421 | m_referenceFrame = Quaternion.Identity; | 538 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); |
422 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 539 | m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); |
423 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | 540 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | |
424 | | VehicleFlag.LIMIT_ROLL_ONLY | 541 | VehicleFlag.LIMIT_MOTOR_UP); |
425 | | VehicleFlag.HOVER_UP_ONLY); | 542 | m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); |
426 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
427 | | VehicleFlag.LIMIT_MOTOR_UP | ||
428 | | VehicleFlag.HOVER_WATER_ONLY); | ||
429 | break; | 543 | break; |
430 | case Vehicle.TYPE_AIRPLANE: | 544 | case Vehicle.TYPE_AIRPLANE: |
545 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
546 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
431 | m_linearMotorDirection = Vector3.Zero; | 547 | m_linearMotorDirection = Vector3.Zero; |
432 | m_linearMotorTimescale = 2; | 548 | m_linearMotorTimescale = 2; |
433 | m_linearMotorDecayTimescale = 60; | 549 | m_linearMotorDecayTimescale = 60; |
434 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
435 | |||
436 | m_angularMotorDirection = Vector3.Zero; | 550 | m_angularMotorDirection = Vector3.Zero; |
437 | m_angularMotorTimescale = 4; | 551 | m_angularMotorTimescale = 4; |
438 | m_angularMotorDecayTimescale = 4; | 552 | m_angularMotorDecayTimescale = 4; |
439 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
440 | |||
441 | m_VhoverHeight = 0; | 553 | m_VhoverHeight = 0; |
442 | m_VhoverEfficiency = 0.5f; | 554 | // m_VhoverEfficiency = 0.5f; |
443 | m_VhoverTimescale = 1000; | 555 | m_VhoverTimescale = 1000; |
444 | m_VehicleBuoyancy = 0; | 556 | m_VehicleBuoyancy = 0; |
445 | 557 | // m_linearDeflectionEfficiency = 0.5f; | |
446 | m_linearDeflectionEfficiency = 0.5f; | 558 | // m_linearDeflectionTimescale = 3; |
447 | m_linearDeflectionTimescale = 3; | 559 | // m_angularDeflectionEfficiency = 1; |
448 | 560 | // m_angularDeflectionTimescale = 2; | |
449 | m_angularDeflectionEfficiency = 1; | ||
450 | m_angularDeflectionTimescale = 2; | ||
451 | |||
452 | m_verticalAttractionEfficiency = 0.9f; | 561 | m_verticalAttractionEfficiency = 0.9f; |
453 | m_verticalAttractionTimescale = 2f; | 562 | m_verticalAttractionTimescale = 2f; |
454 | 563 | // m_bankingEfficiency = 1; | |
455 | m_bankingEfficiency = 1; | 564 | // m_bankingMix = 0.7f; |
456 | m_bankingMix = 0.7f; | 565 | // m_bankingTimescale = 2; |
457 | m_bankingTimescale = 2; | 566 | // m_referenceFrame = Quaternion.Identity; |
458 | 567 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | |
459 | m_referenceFrame = Quaternion.Identity; | 568 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); |
460 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 569 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); |
461 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
462 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
463 | | VehicleFlag.HOVER_UP_ONLY | ||
464 | | VehicleFlag.NO_DEFLECTION_UP | ||
465 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
466 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | 570 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); |
467 | break; | 571 | break; |
468 | case Vehicle.TYPE_BALLOON: | 572 | case Vehicle.TYPE_BALLOON: |
573 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
574 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
469 | m_linearMotorDirection = Vector3.Zero; | 575 | m_linearMotorDirection = Vector3.Zero; |
470 | m_linearMotorTimescale = 5; | 576 | m_linearMotorTimescale = 5; |
471 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
472 | m_linearMotorDecayTimescale = 60; | 577 | m_linearMotorDecayTimescale = 60; |
473 | |||
474 | m_angularMotorDirection = Vector3.Zero; | 578 | m_angularMotorDirection = Vector3.Zero; |
475 | m_angularMotorTimescale = 6; | 579 | m_angularMotorTimescale = 6; |
476 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
477 | m_angularMotorDecayTimescale = 10; | 580 | m_angularMotorDecayTimescale = 10; |
478 | |||
479 | m_VhoverHeight = 5; | 581 | m_VhoverHeight = 5; |
480 | m_VhoverEfficiency = 0.8f; | 582 | // m_VhoverEfficiency = 0.8f; |
481 | m_VhoverTimescale = 10; | 583 | m_VhoverTimescale = 10; |
482 | m_VehicleBuoyancy = 1; | 584 | m_VehicleBuoyancy = 1; |
483 | 585 | // m_linearDeflectionEfficiency = 0; | |
484 | m_linearDeflectionEfficiency = 0; | 586 | // m_linearDeflectionTimescale = 5; |
485 | m_linearDeflectionTimescale = 5; | 587 | // m_angularDeflectionEfficiency = 0; |
486 | 588 | // m_angularDeflectionTimescale = 5; | |
487 | m_angularDeflectionEfficiency = 0; | ||
488 | m_angularDeflectionTimescale = 5; | ||
489 | |||
490 | m_verticalAttractionEfficiency = 1f; | 589 | m_verticalAttractionEfficiency = 1f; |
491 | m_verticalAttractionTimescale = 100f; | 590 | m_verticalAttractionTimescale = 100f; |
492 | 591 | // m_bankingEfficiency = 0; | |
493 | m_bankingEfficiency = 0; | 592 | // m_bankingMix = 0.7f; |
494 | m_bankingMix = 0.7f; | 593 | // m_bankingTimescale = 5; |
495 | m_bankingTimescale = 5; | 594 | // m_referenceFrame = Quaternion.Identity; |
496 | m_referenceFrame = Quaternion.Identity; | 595 | m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | |
497 | 596 | VehicleFlag.HOVER_UP_ONLY); | |
498 | m_referenceFrame = Quaternion.Identity; | 597 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); |
499 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 598 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); |
500 | | VehicleFlag.HOVER_TERRAIN_ONLY | 599 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); |
501 | | VehicleFlag.HOVER_UP_ONLY | ||
502 | | VehicleFlag.NO_DEFLECTION_UP | ||
503 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
504 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | ||
505 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
506 | break; | 600 | break; |
507 | } | 601 | } |
508 | } | 602 | }//end SetDefaultsForType |
509 | 603 | ||
510 | // Some of the properties of this prim may have changed. | ||
511 | // Do any updating needed for a vehicle | ||
512 | public void Refresh() | ||
513 | { | ||
514 | if (IsActive) | ||
515 | { | ||
516 | // Friction effects are handled by this vehicle code | ||
517 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); | ||
518 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | // One step of the vehicle properties for the next 'pTimestep' seconds. | ||
523 | internal void Step(float pTimestep) | 604 | internal void Step(float pTimestep) |
524 | { | 605 | { |
525 | if (!IsActive) return; | 606 | if (m_type == Vehicle.TYPE_NONE) return; |
526 | 607 | ||
527 | // DEBUG | 608 | frcount++; // used to limit debug comment output |
528 | // Because Bullet does apply forces to the vehicle, our last computed | 609 | if (frcount > 100) |
529 | // linear and angular velocities are not what is happening now. | 610 | frcount = 0; |
530 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
531 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
532 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
533 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
534 | // END DEBUG | ||
535 | 611 | ||
536 | MoveLinear(pTimestep); | 612 | MoveLinear(pTimestep); |
537 | MoveAngular(pTimestep); | 613 | MoveAngular(pTimestep); |
538 | LimitRotation(pTimestep); | 614 | LimitRotation(pTimestep); |
539 | 615 | ||
540 | // DEBUG: Trying to figure out why Bullet goes crazy when the root prim is moved. | 616 | DetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
541 | // BulletSimAPI.SetInterpolationVelocity2(Prim.BSBody.ptr, m_newVelocity, m_lastAngularVelocity); // DEBUG DEBUG DEBUG | 617 | m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); |
542 | |||
543 | // remember the position so next step we can limit absolute movement effects | ||
544 | m_lastPositionVector = Prim.ForcePosition; | ||
545 | |||
546 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | ||
547 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | ||
548 | }// end Step | 618 | }// end Step |
549 | 619 | ||
550 | // Apply the effect of the linear motor. | ||
551 | // Also does hover and float. | ||
552 | private void MoveLinear(float pTimestep) | 620 | private void MoveLinear(float pTimestep) |
553 | { | 621 | { |
554 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates | 622 | // requested m_linearMotorDirection is significant |
555 | // m_lastLinearVelocityVector is the current speed we are moving in that direction | 623 | // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) |
556 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | 624 | if (m_linearMotorDirection.LengthSquared() > 0.0001f) |
557 | { | 625 | { |
558 | Vector3 origDir = m_linearMotorDirection; | 626 | Vector3 origDir = m_linearMotorDirection; |
559 | Vector3 origVel = m_lastLinearVelocityVector; | 627 | Vector3 origVel = m_lastLinearVelocityVector; |
560 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | ||
561 | 628 | ||
562 | // add drive to body | 629 | // add drive to body |
563 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; | 630 | // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); |
564 | // lastLinearVelocityVector is the current body velocity vector | 631 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale); |
632 | // lastLinearVelocityVector is the current body velocity vector? | ||
633 | // RA: Not sure what the *10 is for. A correction for pTimestep? | ||
634 | // m_lastLinearVelocityVector += (addAmount*10); | ||
635 | m_lastLinearVelocityVector += addAmount; | ||
636 | |||
637 | // This will work temporarily, but we really need to compare speed on an axis | ||
638 | // KF: Limit body velocity to applied velocity? | ||
639 | // Limit the velocity vector to less than the last set linear motor direction | ||
640 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
641 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
642 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
643 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
644 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
645 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
646 | |||
647 | // decay applied velocity | ||
648 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
649 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; | ||
650 | |||
651 | /* | ||
652 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale; | ||
565 | m_lastLinearVelocityVector += addAmount; | 653 | m_lastLinearVelocityVector += addAmount; |
566 | 654 | ||
567 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; | 655 | float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale); |
568 | m_linearMotorDirection *= (1f - decayFactor); | 656 | m_linearMotorDirection *= decayfraction; |
569 | 657 | ||
570 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; | 658 | */ |
571 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); | ||
572 | 659 | ||
573 | // Rotate new object velocity from vehicle relative to world coordinates | 660 | DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}", |
574 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | 661 | m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector); |
575 | |||
576 | VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lmVel={8},newVel={9}", | ||
577 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, | ||
578 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); | ||
579 | } | 662 | } |
580 | else | 663 | else |
581 | { | 664 | { |
582 | // if what remains of direction is very small, zero it. | 665 | // if what remains of applied is small, zero it. |
666 | // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
667 | // m_lastLinearVelocityVector = Vector3.Zero; | ||
583 | m_linearMotorDirection = Vector3.Zero; | 668 | m_linearMotorDirection = Vector3.Zero; |
584 | m_lastLinearVelocityVector = Vector3.Zero; | 669 | m_lastLinearVelocityVector = Vector3.Zero; |
585 | m_newVelocity = Vector3.Zero; | ||
586 | |||
587 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | ||
588 | } | 670 | } |
589 | 671 | ||
590 | // m_newVelocity is velocity computed from linear motor in world coordinates | 672 | // convert requested object velocity to world-referenced vector |
673 | Quaternion rotq = m_prim.Orientation; | ||
674 | m_dir = m_lastLinearVelocityVector * rotq; | ||
591 | 675 | ||
592 | // Gravity and Buoyancy | 676 | // Add the various forces into m_dir which will be our new direction vector (velocity) |
677 | |||
678 | // add Gravity and Buoyancy | ||
679 | // KF: So far I have found no good method to combine a script-requested | ||
680 | // .Z velocity and gravity. Therefore only 0g will used script-requested | ||
681 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | ||
682 | Vector3 grav = Vector3.Zero; | ||
593 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 683 | // There is some gravity, make a gravity force vector that is applied after object velocity. |
594 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 684 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
595 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 685 | grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy); |
596 | |||
597 | /* | ||
598 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... | ||
599 | // Preserve the current Z velocity | 686 | // Preserve the current Z velocity |
600 | Vector3 vel_now = m_prim.Velocity; | 687 | Vector3 vel_now = m_prim.Velocity; |
601 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 688 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity |
602 | */ | ||
603 | 689 | ||
604 | Vector3 pos = Prim.ForcePosition; | 690 | Vector3 pos = m_prim.Position; |
691 | Vector3 posChange = pos; | ||
605 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | 692 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); |
693 | double Zchange = Math.Abs(posChange.Z); | ||
694 | if (m_BlockingEndPoint != Vector3.Zero) | ||
695 | { | ||
696 | bool changed = false; | ||
697 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | ||
698 | { | ||
699 | pos.X -= posChange.X + 1; | ||
700 | changed = true; | ||
701 | } | ||
702 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | ||
703 | { | ||
704 | pos.Y -= posChange.Y + 1; | ||
705 | changed = true; | ||
706 | } | ||
707 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | ||
708 | { | ||
709 | pos.Z -= posChange.Z + 1; | ||
710 | changed = true; | ||
711 | } | ||
712 | if (pos.X <= 0) | ||
713 | { | ||
714 | pos.X += posChange.X + 1; | ||
715 | changed = true; | ||
716 | } | ||
717 | if (pos.Y <= 0) | ||
718 | { | ||
719 | pos.Y += posChange.Y + 1; | ||
720 | changed = true; | ||
721 | } | ||
722 | if (changed) | ||
723 | { | ||
724 | m_prim.Position = pos; | ||
725 | DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | ||
726 | m_prim.LocalID, m_BlockingEndPoint, posChange, pos); | ||
727 | } | ||
728 | } | ||
606 | 729 | ||
607 | // If below the terrain, move us above the ground a little. | 730 | // If below the terrain, move us above the ground a little. |
608 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 731 | if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) |
609 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | ||
610 | // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | ||
611 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
612 | // if (rotatedSize.Z < terrainHeight) | ||
613 | if (pos.Z < terrainHeight) | ||
614 | { | 732 | { |
615 | pos.Z = terrainHeight + 2; | 733 | pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; |
616 | Prim.ForcePosition = pos; | 734 | m_prim.Position = pos; |
617 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | 735 | DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); |
618 | } | 736 | } |
619 | 737 | ||
620 | // Check if hovering | 738 | // Check if hovering |
621 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 739 | if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
622 | // m_VhoverTimescale: time to achieve height | ||
623 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
624 | { | 740 | { |
625 | // We should hover, get the target height | 741 | // We should hover, get the target height |
626 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 742 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
627 | { | 743 | { |
628 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 744 | m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight; |
629 | } | 745 | } |
630 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 746 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
631 | { | 747 | { |
632 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 748 | m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; |
633 | } | 749 | } |
634 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 750 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
635 | { | 751 | { |
636 | m_VhoverTargetHeight = m_VhoverHeight; | 752 | m_VhoverTargetHeight = m_VhoverHeight; |
637 | } | 753 | } |
638 | 754 | ||
639 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 755 | if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) |
640 | { | 756 | { |
641 | // If body is aready heigher, use its height as target height | 757 | // If body is aready heigher, use its height as target height |
642 | if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; | 758 | if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; |
643 | } | 759 | } |
644 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 760 | if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
645 | { | 761 | { |
646 | if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) | 762 | if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) |
647 | { | 763 | { |
648 | Prim.ForcePosition = pos; | 764 | m_prim.Position = pos; |
649 | } | 765 | } |
650 | } | 766 | } |
651 | else | 767 | else |
652 | { | 768 | { |
653 | float verticalError = pos.Z - m_VhoverTargetHeight; | 769 | float herr0 = pos.Z - m_VhoverTargetHeight; |
654 | // RA: where does the 50 come from? | ||
655 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | ||
656 | // Replace Vertical speed with correction figure if significant | 770 | // Replace Vertical speed with correction figure if significant |
657 | if (Math.Abs(verticalError) > 0.01f) | 771 | if (Math.Abs(herr0) > 0.01f) |
658 | { | 772 | { |
659 | m_newVelocity.Z += verticalCorrectionVelocity; | 773 | m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); |
660 | //KF: m_VhoverEfficiency is not yet implemented | 774 | //KF: m_VhoverEfficiency is not yet implemented |
661 | } | 775 | } |
662 | else if (verticalError < -0.01) | ||
663 | { | ||
664 | m_newVelocity.Z -= verticalCorrectionVelocity; | ||
665 | } | ||
666 | else | 776 | else |
667 | { | 777 | { |
668 | m_newVelocity.Z = 0f; | 778 | m_dir.Z = 0f; |
669 | } | 779 | } |
670 | } | 780 | } |
671 | 781 | ||
672 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); | 782 | DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight); |
673 | } | ||
674 | 783 | ||
675 | Vector3 posChange = pos - m_lastPositionVector; | 784 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped |
676 | if (m_BlockingEndPoint != Vector3.Zero) | 785 | // m_VhoverTimescale = 0f; // time to acheive height |
677 | { | 786 | // pTimestep is time since last frame,in secs |
678 | bool changed = false; | ||
679 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | ||
680 | { | ||
681 | pos.X -= posChange.X + 1; | ||
682 | changed = true; | ||
683 | } | ||
684 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | ||
685 | { | ||
686 | pos.Y -= posChange.Y + 1; | ||
687 | changed = true; | ||
688 | } | ||
689 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | ||
690 | { | ||
691 | pos.Z -= posChange.Z + 1; | ||
692 | changed = true; | ||
693 | } | ||
694 | if (pos.X <= 0) | ||
695 | { | ||
696 | pos.X += posChange.X + 1; | ||
697 | changed = true; | ||
698 | } | ||
699 | if (pos.Y <= 0) | ||
700 | { | ||
701 | pos.Y += posChange.Y + 1; | ||
702 | changed = true; | ||
703 | } | ||
704 | if (changed) | ||
705 | { | ||
706 | Prim.ForcePosition = pos; | ||
707 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | ||
708 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | ||
709 | } | ||
710 | } | 787 | } |
711 | 788 | ||
712 | // Limit absolute vertical change | ||
713 | float Zchange = Math.Abs(posChange.Z); | ||
714 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 789 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
715 | { | 790 | { |
791 | //Start Experimental Values | ||
716 | if (Zchange > .3) | 792 | if (Zchange > .3) |
793 | { | ||
717 | grav.Z = (float)(grav.Z * 3); | 794 | grav.Z = (float)(grav.Z * 3); |
795 | } | ||
718 | if (Zchange > .15) | 796 | if (Zchange > .15) |
797 | { | ||
719 | grav.Z = (float)(grav.Z * 2); | 798 | grav.Z = (float)(grav.Z * 2); |
799 | } | ||
720 | if (Zchange > .75) | 800 | if (Zchange > .75) |
801 | { | ||
721 | grav.Z = (float)(grav.Z * 1.5); | 802 | grav.Z = (float)(grav.Z * 1.5); |
803 | } | ||
722 | if (Zchange > .05) | 804 | if (Zchange > .05) |
805 | { | ||
723 | grav.Z = (float)(grav.Z * 1.25); | 806 | grav.Z = (float)(grav.Z * 1.25); |
807 | } | ||
724 | if (Zchange > .025) | 808 | if (Zchange > .025) |
809 | { | ||
725 | grav.Z = (float)(grav.Z * 1.125); | 810 | grav.Z = (float)(grav.Z * 1.125); |
726 | float postemp = (pos.Z - terrainHeight); | 811 | } |
812 | float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos); | ||
813 | float postemp = (pos.Z - terraintemp); | ||
727 | if (postemp > 2.5f) | 814 | if (postemp > 2.5f) |
815 | { | ||
728 | grav.Z = (float)(grav.Z * 1.037125); | 816 | grav.Z = (float)(grav.Z * 1.037125); |
729 | VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav); | 817 | } |
818 | DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav); | ||
819 | //End Experimental Values | ||
730 | } | 820 | } |
731 | |||
732 | // If not changing some axis, reduce out velocity | ||
733 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | 821 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
734 | m_newVelocity.X = 0; | 822 | { |
823 | m_dir.X = 0; | ||
824 | } | ||
735 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | 825 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) |
736 | m_newVelocity.Y = 0; | 826 | { |
827 | m_dir.Y = 0; | ||
828 | } | ||
737 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | 829 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) |
738 | m_newVelocity.Z = 0; | 830 | { |
831 | m_dir.Z = 0; | ||
832 | } | ||
833 | |||
834 | m_lastPositionVector = m_prim.Position; | ||
739 | 835 | ||
740 | // Apply velocity | 836 | // Apply velocity |
741 | Prim.ForceVelocity = m_newVelocity; | 837 | m_prim.Velocity = m_dir; |
742 | // Prim.AddForce(m_newVelocity * Prim.Linkset.LinksetMass, false); | 838 | // apply gravity force |
743 | Prim.AddForce(grav * Prim.Linkset.LinksetMass, false); | 839 | // Why is this set here? The physics engine already does gravity. |
840 | // m_prim.AddForce(grav, false); | ||
841 | // m_prim.Force = grav; | ||
744 | 842 | ||
745 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4}", | 843 | // Apply friction |
746 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav); | 844 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); |
845 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | ||
846 | |||
847 | DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}", | ||
848 | m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount); | ||
747 | 849 | ||
748 | } // end MoveLinear() | 850 | } // end MoveLinear() |
749 | 851 | ||
750 | // ======================================================================= | ||
751 | // Apply the effect of the angular motor. | ||
752 | private void MoveAngular(float pTimestep) | 852 | private void MoveAngular(float pTimestep) |
753 | { | 853 | { |
754 | // m_angularMotorDirection // angular velocity requested by LSL motor | 854 | // m_angularMotorDirection // angular velocity requested by LSL motor |
@@ -759,223 +859,160 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
759 | // m_angularFrictionTimescale // body angular velocity decay rate | 859 | // m_angularFrictionTimescale // body angular velocity decay rate |
760 | // m_lastAngularVelocity // what was last applied to body | 860 | // m_lastAngularVelocity // what was last applied to body |
761 | 861 | ||
762 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | 862 | // Get what the body is doing, this includes 'external' influences |
763 | { | 863 | Vector3 angularVelocity = m_prim.RotationalVelocity; |
764 | Vector3 origVel = m_angularMotorVelocity; | ||
765 | Vector3 origDir = m_angularMotorDirection; | ||
766 | |||
767 | // new velocity += error / ( time to get there / step interval) | ||
768 | // requested speed - last motor speed | ||
769 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
770 | // decay requested direction | ||
771 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
772 | 864 | ||
773 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | 865 | if (m_angularMotorApply > 0) |
774 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | 866 | { |
867 | // Rather than snapping the angular motor velocity from the old value to | ||
868 | // a newly set velocity, this routine steps the value from the previous | ||
869 | // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). | ||
870 | // There are m_angularMotorApply steps. | ||
871 | Vector3 origAngularVelocity = m_angularMotorVelocity; | ||
872 | // ramp up to new value | ||
873 | // current velocity += error / (time to get there / step interval) | ||
874 | // requested speed - last motor speed | ||
875 | m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); | ||
876 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); | ||
877 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); | ||
878 | |||
879 | DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}", | ||
880 | m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); | ||
881 | |||
882 | m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected | ||
883 | // velocity may still be acheived. | ||
775 | } | 884 | } |
776 | else | 885 | else |
777 | { | 886 | { |
778 | m_angularMotorVelocity = Vector3.Zero; | 887 | // No motor recently applied, keep the body velocity |
779 | } | 888 | // and decay the velocity |
780 | 889 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); | |
781 | #region Vertical attactor | 890 | } // end motor section |
782 | 891 | ||
892 | // Vertical attractor section | ||
783 | Vector3 vertattr = Vector3.Zero; | 893 | Vector3 vertattr = Vector3.Zero; |
784 | Vector3 deflection = Vector3.Zero; | 894 | if (m_verticalAttractionTimescale < 300) |
785 | Vector3 banking = Vector3.Zero; | ||
786 | |||
787 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | ||
788 | { | 895 | { |
789 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | 896 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); |
790 | if (Prim.Linkset.LinksetIsColliding) | 897 | // get present body rotation |
791 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | 898 | Quaternion rotq = m_prim.Orientation; |
792 | 899 | // make a vector pointing up | |
793 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 900 | Vector3 verterr = Vector3.Zero; |
794 | 901 | verterr.Z = 1.0f; | |
795 | // Create a vector of the vehicle "up" in world coordinates | 902 | // rotate it to Body Angle |
796 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | 903 | verterr = verterr * rotq; |
797 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | 904 | // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. |
798 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | 905 | // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go |
799 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | 906 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. |
800 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | 907 | if (verterr.Z < 0.0f) |
801 | // modulated to prevent a stable inverted body. | ||
802 | |||
803 | // Error is 0 (no error) to +/- 2 (max error) | ||
804 | if (verticalError.Z < 0.0f) | ||
805 | { | 908 | { |
806 | verticalError.X = 2.0f - verticalError.X; | 909 | verterr.X = 2.0f - verterr.X; |
807 | verticalError.Y = 2.0f - verticalError.Y; | 910 | verterr.Y = 2.0f - verterr.Y; |
808 | } | 911 | } |
912 | // Error is 0 (no error) to +/- 2 (max error) | ||
809 | // scale it by VAservo | 913 | // scale it by VAservo |
810 | verticalError = verticalError * VAservo; | 914 | verterr = verterr * VAservo; |
811 | 915 | ||
812 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | 916 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so |
813 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | 917 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. |
814 | // Z is not changed. | 918 | vertattr.X = verterr.Y; |
815 | vertattr.X = verticalError.Y; | 919 | vertattr.Y = - verterr.X; |
816 | vertattr.Y = - verticalError.X; | ||
817 | vertattr.Z = 0f; | 920 | vertattr.Z = 0f; |
818 | 921 | ||
819 | // scaling appears better usingsquare-law | 922 | // scaling appears better usingsquare-law |
820 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
821 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 923 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); |
822 | vertattr.X += bounce * angularVelocity.X; | 924 | vertattr.X += bounce * angularVelocity.X; |
823 | vertattr.Y += bounce * angularVelocity.Y; | 925 | vertattr.Y += bounce * angularVelocity.Y; |
824 | 926 | ||
825 | VDetailLog("{0},MoveAngular,verticalAttraction,verticalError={1},bounce={2},vertattr={3}", | 927 | DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", |
826 | Prim.LocalID, verticalError, bounce, vertattr); | 928 | m_prim.LocalID, verterr, bounce, vertattr); |
827 | |||
828 | } | ||
829 | #endregion // Vertical attactor | ||
830 | |||
831 | #region Deflection | ||
832 | |||
833 | //Forward is the prefered direction, but if the reference frame has changed, we need to take this into account as well | ||
834 | if (m_angularDeflectionEfficiency != 0) | ||
835 | { | ||
836 | Vector3 preferredAxisOfMotion = | ||
837 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
838 | preferredAxisOfMotion *= Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
839 | |||
840 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | ||
841 | |||
842 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
843 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
844 | } | ||
845 | |||
846 | #endregion | ||
847 | |||
848 | #region Banking | ||
849 | 929 | ||
850 | if (m_bankingEfficiency != 0) | 930 | } // else vertical attractor is off |
851 | { | ||
852 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | ||
853 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | ||
854 | //Changes which way it banks in and out of turns | ||
855 | 931 | ||
856 | //Use the square of the efficiency, as it looks much more how SL banking works | 932 | // m_lastVertAttractor = vertattr; |
857 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
858 | if (m_bankingEfficiency < 0) | ||
859 | effSquared *= -1; //Keep the negative! | ||
860 | 933 | ||
861 | float mix = Math.Abs(m_bankingMix); | 934 | // Bank section tba |
862 | if (m_angularMotorVelocity.X == 0) | ||
863 | { | ||
864 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
865 | { | ||
866 | Vector3 axisAngle; | ||
867 | float angle; | ||
868 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
869 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
870 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
871 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
872 | else | ||
873 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
874 | }*/ | ||
875 | } | ||
876 | else | ||
877 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | ||
878 | if (!Prim.Linkset.LinksetIsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
879 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
880 | { | ||
881 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
882 | /*if(angVelZ > mix) | ||
883 | angVelZ = mix; | ||
884 | else if(angVelZ < -mix) | ||
885 | angVelZ = -mix;*/ | ||
886 | //This controls how fast and how far the banking occurs | ||
887 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
888 | if (bankingRot.X > 3) | ||
889 | bankingRot.X = 3; | ||
890 | else if (bankingRot.X < -3) | ||
891 | bankingRot.X = -3; | ||
892 | bankingRot *= Prim.ForceOrientation; | ||
893 | banking += bankingRot; | ||
894 | } | ||
895 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
896 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | ||
897 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | ||
898 | } | ||
899 | |||
900 | #endregion | ||
901 | 935 | ||
902 | m_lastVertAttractor = vertattr; | 936 | // Deflection section tba |
903 | 937 | ||
904 | // Sum velocities | 938 | // Sum velocities |
905 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; | 939 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection |
906 | 940 | ||
907 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 941 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) |
908 | { | 942 | { |
909 | m_lastAngularVelocity.X = 0; | 943 | m_lastAngularVelocity.X = 0; |
910 | m_lastAngularVelocity.Y = 0; | 944 | m_lastAngularVelocity.Y = 0; |
911 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 945 | DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); |
912 | } | 946 | } |
913 | 947 | ||
914 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 948 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) |
915 | { | 949 | { |
916 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 950 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. |
917 | VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 951 | DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); |
918 | } | 952 | } |
919 | 953 | ||
920 | // Apply to the body | 954 | // apply friction |
921 | // The above calculates the absolute angular velocity needed | 955 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); |
922 | // Prim.ForceRotationalVelocity = m_lastAngularVelocity; | 956 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; |
923 | |||
924 | // Apply a force to overcome current angular velocity | ||
925 | Vector3 applyAngularForce = (m_lastAngularVelocity - Prim.ForceRotationalVelocity) * Prim.Linkset.LinksetMass; | ||
926 | // Vector3 applyAngularForce = (m_lastAngularVelocity - Prim.ForceRotationalVelocity); | ||
927 | // Prim.AddAngularForce(applyAngularForce, false); | ||
928 | Prim.ApplyTorqueImpulse(applyAngularForce, false); | ||
929 | 957 | ||
930 | // Apply friction for next time | 958 | // Apply to the body |
931 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | 959 | m_prim.RotationalVelocity = m_lastAngularVelocity; |
932 | m_lastAngularVelocity *= Vector3.One - decayamount; | ||
933 | 960 | ||
934 | VDetailLog("{0},MoveAngular,done,applyAForce={1},decay={2},lastAngular={3}", | 961 | DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); |
935 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | ||
936 | } //end MoveAngular | 962 | } //end MoveAngular |
937 | 963 | ||
938 | internal void LimitRotation(float timestep) | 964 | internal void LimitRotation(float timestep) |
939 | { | 965 | { |
940 | Quaternion rotq = Prim.ForceOrientation; | 966 | Quaternion rotq = m_prim.Orientation; |
941 | Quaternion m_rot = rotq; | 967 | Quaternion m_rot = rotq; |
968 | bool changed = false; | ||
942 | if (m_RollreferenceFrame != Quaternion.Identity) | 969 | if (m_RollreferenceFrame != Quaternion.Identity) |
943 | { | 970 | { |
944 | if (rotq.X >= m_RollreferenceFrame.X) | 971 | if (rotq.X >= m_RollreferenceFrame.X) |
945 | { | 972 | { |
946 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | 973 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); |
974 | changed = true; | ||
947 | } | 975 | } |
948 | if (rotq.Y >= m_RollreferenceFrame.Y) | 976 | if (rotq.Y >= m_RollreferenceFrame.Y) |
949 | { | 977 | { |
950 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | 978 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); |
979 | changed = true; | ||
951 | } | 980 | } |
952 | if (rotq.X <= -m_RollreferenceFrame.X) | 981 | if (rotq.X <= -m_RollreferenceFrame.X) |
953 | { | 982 | { |
954 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | 983 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); |
984 | changed = true; | ||
955 | } | 985 | } |
956 | if (rotq.Y <= -m_RollreferenceFrame.Y) | 986 | if (rotq.Y <= -m_RollreferenceFrame.Y) |
957 | { | 987 | { |
958 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | 988 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); |
989 | changed = true; | ||
959 | } | 990 | } |
991 | changed = true; | ||
960 | } | 992 | } |
961 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | 993 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) |
962 | { | 994 | { |
963 | m_rot.X = 0; | 995 | m_rot.X = 0; |
964 | m_rot.Y = 0; | 996 | m_rot.Y = 0; |
997 | changed = true; | ||
965 | } | 998 | } |
966 | if (rotq != m_rot) | 999 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) |
967 | { | 1000 | { |
968 | Prim.ForceOrientation = m_rot; | 1001 | m_rot.X = 0; |
969 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1002 | m_rot.Y = 0; |
1003 | changed = true; | ||
970 | } | 1004 | } |
1005 | if (changed) | ||
1006 | m_prim.Orientation = m_rot; | ||
971 | 1007 | ||
1008 | DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot); | ||
972 | } | 1009 | } |
973 | 1010 | ||
974 | // Invoke the detailed logger and output something if it's enabled. | 1011 | // Invoke the detailed logger and output something if it's enabled. |
975 | private void VDetailLog(string msg, params Object[] args) | 1012 | private void DetailLog(string msg, params Object[] args) |
976 | { | 1013 | { |
977 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | 1014 | if (m_prim.Scene.VehicleLoggingEnabled) |
978 | Prim.PhysicsScene.DetailLog(msg, args); | 1015 | m_prim.Scene.PhysicsLogging.Write(msg, args); |
979 | } | 1016 | } |
980 | } | 1017 | } |
981 | } | 1018 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs index ed3ffa7..d68048b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs | |||
@@ -1,57 +1,55 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyrightD | 9 | * * Redistributions in binary form must reproduce the above copyrightD |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | using OpenMetaverse; | 30 | using OpenMetaverse; |
31 | 31 | ||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | 32 | namespace OpenSim.Region.Physics.BulletSPlugin |
33 | { | 33 | { |
34 | 34 | ||
35 | public sealed class BSConstraintHinge : BSConstraint | 35 | class BSHingeConstraint : BSConstraint |
36 | { | 36 | { |
37 | public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } | 37 | public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, |
38 | 38 | Vector3 pivotInA, Vector3 pivotInB, | |
39 | public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2, | 39 | Vector3 axisInA, Vector3 axisInB, |
40 | Vector3 pivotInA, Vector3 pivotInB, | 40 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
41 | Vector3 axisInA, Vector3 axisInB, | 41 | { |
42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 42 | m_world = world; |
43 | { | 43 | m_body1 = obj1; |
44 | m_world = world; | 44 | m_body2 = obj2; |
45 | m_body1 = obj1; | 45 | m_constraint = new BulletConstraint( |
46 | m_body2 = obj2; | 46 | BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, |
47 | m_constraint = new BulletConstraint( | 47 | pivotInA, pivotInB, |
48 | BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | 48 | axisInA, axisInB, |
49 | pivotInA, pivotInB, | 49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); |
50 | axisInA, axisInB, | 50 | m_enabled = true; |
51 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 51 | } |
52 | m_enabled = true; | 52 | |
53 | } | 53 | } |
54 | 54 | ||
55 | } | 55 | } |
56 | |||
57 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 3a92f93..087b9bb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -32,78 +32,35 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | public abstract class BSLinkset | 35 | public class BSLinkset |
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | 37 | private static string LogHeader = "[BULLETSIM LINKSET]"; |
38 | 38 | ||
39 | public enum LinksetImplementation | 39 | private BSPrim m_linksetRoot; |
40 | { | 40 | public BSPrim LinksetRoot { get { return m_linksetRoot; } } |
41 | Constraint = 0, // linkset tied together with constraints | ||
42 | Compound = 1, // linkset tied together as a compound object | ||
43 | Manual = 2 // linkset tied together manually (code moves all the pieces) | ||
44 | } | ||
45 | // Create the correct type of linkset for this child | ||
46 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) | ||
47 | { | ||
48 | BSLinkset ret = null; | ||
49 | |||
50 | switch ((int)physScene.Params.linksetImplementation) | ||
51 | { | ||
52 | case (int)LinksetImplementation.Compound: | ||
53 | ret = new BSLinksetCompound(physScene, parent); | ||
54 | break; | ||
55 | case (int)LinksetImplementation.Manual: | ||
56 | // ret = new BSLinksetManual(physScene, parent); | ||
57 | break; | ||
58 | default: | ||
59 | ret = new BSLinksetConstraints(physScene, parent); | ||
60 | break; | ||
61 | } | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | public BSPhysObject LinksetRoot { get; protected set; } | ||
66 | 41 | ||
67 | public BSScene PhysicsScene { get; private set; } | 42 | private BSScene m_physicsScene; |
43 | public BSScene PhysicsScene { get { return m_physicsScene; } } | ||
68 | 44 | ||
69 | static int m_nextLinksetID = 1; | 45 | // The children under the root in this linkset |
70 | public int LinksetID { get; private set; } | 46 | private List<BSPrim> m_children; |
71 | |||
72 | // The children under the root in this linkset. | ||
73 | protected HashSet<BSPhysObject> m_children; | ||
74 | 47 | ||
75 | // We lock the diddling of linkset classes to prevent any badness. | 48 | // We lock the diddling of linkset classes to prevent any badness. |
76 | // This locks the modification of the instances of this class. Changes | 49 | // This locks the modification of the instances of this class. Changes |
77 | // to the physical representation is done via the tainting mechenism. | 50 | // to the physical representation is done via the tainting mechenism. |
78 | protected object m_linksetActivityLock = new Object(); | 51 | private object m_linksetActivityLock = new Object(); |
79 | |||
80 | // Some linksets have a preferred physical shape. | ||
81 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | ||
82 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
83 | { | ||
84 | return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
85 | } | ||
86 | 52 | ||
87 | // Linksets move around the children so the linkset might need to compute the child position | ||
88 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
89 | { return member.RawPosition; } | ||
90 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
91 | { return member.RawOrientation; } | ||
92 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
93 | |||
94 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 53 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
95 | protected float m_mass; | 54 | private float m_mass; |
96 | public float LinksetMass | 55 | public float LinksetMass |
97 | { | 56 | { |
98 | get | 57 | get |
99 | { | 58 | { |
100 | m_mass = ComputeLinksetMass(); | 59 | m_mass = ComputeLinksetMass(); |
101 | return m_mass; | 60 | return m_mass; |
102 | } | 61 | } |
103 | } | 62 | } |
104 | 63 | ||
105 | public virtual bool LinksetIsColliding { get { return false; } } | ||
106 | |||
107 | public OMV.Vector3 CenterOfMass | 64 | public OMV.Vector3 CenterOfMass |
108 | { | 65 | { |
109 | get { return ComputeLinksetCenterOfMass(); } | 66 | get { return ComputeLinksetCenterOfMass(); } |
@@ -114,30 +71,23 @@ public abstract class BSLinkset | |||
114 | get { return ComputeLinksetGeometricCenter(); } | 71 | get { return ComputeLinksetGeometricCenter(); } |
115 | } | 72 | } |
116 | 73 | ||
117 | protected void Initialize(BSScene scene, BSPhysObject parent) | 74 | public BSLinkset(BSScene scene, BSPrim parent) |
118 | { | 75 | { |
119 | // A simple linkset of one (no children) | 76 | // A simple linkset of one (no children) |
120 | LinksetID = m_nextLinksetID++; | 77 | m_physicsScene = scene; |
121 | // We create LOTS of linksets. | 78 | m_linksetRoot = parent; |
122 | if (m_nextLinksetID <= 0) | 79 | m_children = new List<BSPrim>(); |
123 | m_nextLinksetID = 1; | 80 | m_mass = parent.MassRaw; |
124 | PhysicsScene = scene; | ||
125 | LinksetRoot = parent; | ||
126 | m_children = new HashSet<BSPhysObject>(); | ||
127 | m_mass = parent.RawMass; | ||
128 | } | 81 | } |
129 | 82 | ||
130 | // Link to a linkset where the child knows the parent. | 83 | // Link to a linkset where the child knows the parent. |
131 | // Parent changing should not happen so do some sanity checking. | 84 | // Parent changing should not happen so do some sanity checking. |
132 | // We return the parent's linkset so the child can track its membership. | 85 | // We return the parent's linkset so the child can track its membership. |
133 | // Called at runtime. | 86 | public BSLinkset AddMeToLinkset(BSPrim child) |
134 | public BSLinkset AddMeToLinkset(BSPhysObject child) | ||
135 | { | 87 | { |
136 | lock (m_linksetActivityLock) | 88 | lock (m_linksetActivityLock) |
137 | { | 89 | { |
138 | // Don't add the root to its own linkset | 90 | AddChildToLinkset(child); |
139 | if (!IsRoot(child)) | ||
140 | AddChildToLinkset(child); | ||
141 | } | 91 | } |
142 | return this; | 92 | return this; |
143 | } | 93 | } |
@@ -145,27 +95,36 @@ public abstract class BSLinkset | |||
145 | // Remove a child from a linkset. | 95 | // Remove a child from a linkset. |
146 | // Returns a new linkset for the child which is a linkset of one (just the | 96 | // Returns a new linkset for the child which is a linkset of one (just the |
147 | // orphened child). | 97 | // orphened child). |
148 | // Called at runtime. | 98 | public BSLinkset RemoveMeFromLinkset(BSPrim child) |
149 | public BSLinkset RemoveMeFromLinkset(BSPhysObject child) | ||
150 | { | 99 | { |
151 | lock (m_linksetActivityLock) | 100 | lock (m_linksetActivityLock) |
152 | { | 101 | { |
153 | if (IsRoot(child)) | 102 | if (IsRoot(child)) |
154 | { | 103 | { |
155 | // Cannot remove the root from a linkset. | 104 | // if root of linkset, take the linkset apart |
156 | return this; | 105 | while (m_children.Count > 0) |
106 | { | ||
107 | // Note that we don't do a foreach because the remove routine | ||
108 | // takes it out of the list. | ||
109 | RemoveChildFromOtherLinkset(m_children[0]); | ||
110 | } | ||
111 | m_children.Clear(); // just to make sure | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | // Just removing a child from an existing linkset | ||
116 | RemoveChildFromLinkset(child); | ||
157 | } | 117 | } |
158 | RemoveChildFromLinkset(child); | ||
159 | } | 118 | } |
160 | 119 | ||
161 | // The child is down to a linkset of just itself | 120 | // The child is down to a linkset of just itself |
162 | return BSLinkset.Factory(PhysicsScene, child); | 121 | return new BSLinkset(PhysicsScene, child); |
163 | } | 122 | } |
164 | 123 | ||
165 | // Return 'true' if the passed object is the root object of this linkset | 124 | // Return 'true' if the passed object is the root object of this linkset |
166 | public bool IsRoot(BSPhysObject requestor) | 125 | public bool IsRoot(BSPrim requestor) |
167 | { | 126 | { |
168 | return (requestor.LocalID == LinksetRoot.LocalID); | 127 | return (requestor.LocalID == m_linksetRoot.LocalID); |
169 | } | 128 | } |
170 | 129 | ||
171 | public int NumberOfChildren { get { return m_children.Count; } } | 130 | public int NumberOfChildren { get { return m_children.Count; } } |
@@ -174,14 +133,12 @@ public abstract class BSLinkset | |||
174 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | 133 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } |
175 | 134 | ||
176 | // Return 'true' if this child is in this linkset | 135 | // Return 'true' if this child is in this linkset |
177 | public bool HasChild(BSPhysObject child) | 136 | public bool HasChild(BSPrim child) |
178 | { | 137 | { |
179 | bool ret = false; | 138 | bool ret = false; |
180 | lock (m_linksetActivityLock) | 139 | lock (m_linksetActivityLock) |
181 | { | 140 | { |
182 | ret = m_children.Contains(child); | 141 | foreach (BSPrim bp in m_children) |
183 | /* Safer version but the above should work | ||
184 | foreach (BSPhysObject bp in m_children) | ||
185 | { | 142 | { |
186 | if (child.LocalID == bp.LocalID) | 143 | if (child.LocalID == bp.LocalID) |
187 | { | 144 | { |
@@ -189,132 +146,274 @@ public abstract class BSLinkset | |||
189 | break; | 146 | break; |
190 | } | 147 | } |
191 | } | 148 | } |
192 | */ | ||
193 | } | 149 | } |
194 | return ret; | 150 | return ret; |
195 | } | 151 | } |
196 | 152 | ||
197 | // Perform an action on each member of the linkset including root prim. | 153 | private float ComputeLinksetMass() |
198 | // Depends on the action on whether this should be done at taint time. | ||
199 | public delegate bool ForEachMemberAction(BSPhysObject obj); | ||
200 | public virtual bool ForEachMember(ForEachMemberAction action) | ||
201 | { | 154 | { |
202 | bool ret = false; | 155 | float mass = m_linksetRoot.MassRaw; |
156 | foreach (BSPrim bp in m_children) | ||
157 | { | ||
158 | mass += bp.MassRaw; | ||
159 | } | ||
160 | return mass; | ||
161 | } | ||
162 | |||
163 | private OMV.Vector3 ComputeLinksetCenterOfMass() | ||
164 | { | ||
165 | OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; | ||
166 | float totalMass = m_linksetRoot.MassRaw; | ||
167 | |||
203 | lock (m_linksetActivityLock) | 168 | lock (m_linksetActivityLock) |
204 | { | 169 | { |
205 | action(LinksetRoot); | 170 | foreach (BSPrim bp in m_children) |
206 | foreach (BSPhysObject po in m_children) | ||
207 | { | 171 | { |
208 | if (action(po)) | 172 | com += bp.Position * bp.MassRaw; |
209 | break; | 173 | totalMass += bp.MassRaw; |
210 | } | 174 | } |
175 | if (totalMass != 0f) | ||
176 | com /= totalMass; | ||
211 | } | 177 | } |
212 | return ret; | 178 | |
179 | return com; | ||
213 | } | 180 | } |
214 | 181 | ||
215 | // I am the root of a linkset and a new child is being added | 182 | private OMV.Vector3 ComputeLinksetGeometricCenter() |
216 | // Called while LinkActivity is locked. | 183 | { |
217 | protected abstract void AddChildToLinkset(BSPhysObject child); | 184 | OMV.Vector3 com = m_linksetRoot.Position; |
218 | 185 | ||
219 | // I am the root of a linkset and one of my children is being removed. | 186 | lock (m_linksetActivityLock) |
220 | // Safe to call even if the child is not really in my linkset. | 187 | { |
221 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | 188 | foreach (BSPrim bp in m_children) |
189 | { | ||
190 | com += bp.Position * bp.MassRaw; | ||
191 | } | ||
192 | com /= (m_children.Count + 1); | ||
193 | } | ||
194 | |||
195 | return com; | ||
196 | } | ||
222 | 197 | ||
223 | // When physical properties are changed the linkset needs to recalculate | 198 | // When physical properties are changed the linkset needs to recalculate |
224 | // its internal properties. | 199 | // its internal properties. |
225 | // May be called at runtime or taint-time. | 200 | public void Refresh(BSPrim requestor) |
226 | public abstract void Refresh(BSPhysObject requestor); | ||
227 | |||
228 | // The object is going dynamic (physical). Do any setup necessary | ||
229 | // for a dynamic linkset. | ||
230 | // Only the state of the passed object can be modified. The rest of the linkset | ||
231 | // has not yet been fully constructed. | ||
232 | // Return 'true' if any properties updated on the passed object. | ||
233 | // Called at taint-time! | ||
234 | public abstract bool MakeDynamic(BSPhysObject child); | ||
235 | |||
236 | // The object is going static (non-physical). Do any setup necessary | ||
237 | // for a static linkset. | ||
238 | // Return 'true' if any properties updated on the passed object. | ||
239 | // Called at taint-time! | ||
240 | public abstract bool MakeStatic(BSPhysObject child); | ||
241 | |||
242 | // Called when a parameter update comes from the physics engine for any object | ||
243 | // of the linkset is received. | ||
244 | // Called at taint-time!! | ||
245 | public abstract void UpdateProperties(BSPhysObject physObject); | ||
246 | |||
247 | // Routine used when rebuilding the body of the root of the linkset | ||
248 | // Destroy all the constraints have have been made to root. | ||
249 | // This is called when the root body is changing. | ||
250 | // Returns 'true' of something was actually removed and would need restoring | ||
251 | // Called at taint-time!! | ||
252 | public abstract bool RemoveBodyDependencies(BSPrim child); | ||
253 | |||
254 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
255 | // this routine will restore the removed constraints. | ||
256 | // Called at taint-time!! | ||
257 | public abstract void RestoreBodyDependencies(BSPrim child); | ||
258 | |||
259 | // ================================================================ | ||
260 | protected virtual float ComputeLinksetMass() | ||
261 | { | 201 | { |
262 | float mass = LinksetRoot.RawMass; | 202 | // If there are no children, there aren't any constraints to recompute |
263 | if (HasAnyChildren) | 203 | if (!HasAnyChildren) |
204 | return; | ||
205 | |||
206 | // Only the root does the recomputation | ||
207 | if (IsRoot(requestor)) | ||
208 | { | ||
209 | PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() | ||
210 | { | ||
211 | RecomputeLinksetConstraintVariables(); | ||
212 | }); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | // Call each of the constraints that make up this linkset and recompute the | ||
217 | // various transforms and variables. Used when objects are added or removed | ||
218 | // from a linkset to make sure the constraints know about the new mass and | ||
219 | // geometry. | ||
220 | // Must only be called at taint time!! | ||
221 | private bool RecomputeLinksetConstraintVariables() | ||
222 | { | ||
223 | float linksetMass = LinksetMass; | ||
224 | lock (m_linksetActivityLock) | ||
264 | { | 225 | { |
265 | lock (m_linksetActivityLock) | 226 | foreach (BSPrim child in m_children) |
266 | { | 227 | { |
267 | foreach (BSPhysObject bp in m_children) | 228 | BSConstraint constrain; |
229 | if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.Body, child.Body, out constrain)) | ||
230 | { | ||
231 | // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}", | ||
232 | // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID); | ||
233 | constrain.RecomputeConstraintVariables(linksetMass); | ||
234 | } | ||
235 | else | ||
268 | { | 236 | { |
269 | mass += bp.RawMass; | 237 | // Non-fatal error that can happen when children are being added to the linkset but |
238 | // their constraints have not been created yet. | ||
239 | // Caused by the fact that m_children is built at run time but building constraints | ||
240 | // happens at taint time. | ||
241 | // m_physicsScene.Logger.ErrorFormat("[BULLETSIM LINKSET] RecomputeLinksetConstraintVariables: constraint not found for root={0}, child={1}", | ||
242 | // m_linksetRoot.Body.ID, child.Body.ID); | ||
270 | } | 243 | } |
271 | } | 244 | } |
272 | } | 245 | } |
273 | return mass; | 246 | return false; |
274 | } | 247 | } |
275 | 248 | ||
276 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() | 249 | // I am the root of a linkset and a new child is being added |
250 | // Called while LinkActivity is locked. | ||
251 | private void AddChildToLinkset(BSPrim child) | ||
277 | { | 252 | { |
278 | OMV.Vector3 com; | 253 | if (!HasChild(child)) |
279 | lock (m_linksetActivityLock) | ||
280 | { | 254 | { |
281 | com = LinksetRoot.Position * LinksetRoot.RawMass; | 255 | m_children.Add(child); |
282 | float totalMass = LinksetRoot.RawMass; | ||
283 | 256 | ||
284 | foreach (BSPhysObject bp in m_children) | 257 | BSPrim rootx = LinksetRoot; // capture the root as of now |
258 | BSPrim childx = child; | ||
259 | m_physicsScene.TaintedObject("AddChildToLinkset", delegate() | ||
285 | { | 260 | { |
286 | com += bp.Position * bp.RawMass; | 261 | // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); |
287 | totalMass += bp.RawMass; | 262 | // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); |
288 | } | 263 | PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child |
289 | if (totalMass != 0f) | 264 | }); |
290 | com /= totalMass; | ||
291 | } | 265 | } |
266 | return; | ||
267 | } | ||
292 | 268 | ||
293 | return com; | 269 | // Forcefully removing a child from a linkset. |
270 | // This is not being called by the child so we have to make sure the child doesn't think | ||
271 | // it's still connected to the linkset. | ||
272 | // Normal OpenSimulator operation will never do this because other SceneObjectPart information | ||
273 | // has to be updated also (like pointer to prim's parent). | ||
274 | private void RemoveChildFromOtherLinkset(BSPrim pchild) | ||
275 | { | ||
276 | pchild.Linkset = new BSLinkset(m_physicsScene, pchild); | ||
277 | RemoveChildFromLinkset(pchild); | ||
294 | } | 278 | } |
295 | 279 | ||
296 | protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() | 280 | // I am the root of a linkset and one of my children is being removed. |
281 | // Safe to call even if the child is not really in my linkset. | ||
282 | private void RemoveChildFromLinkset(BSPrim child) | ||
297 | { | 283 | { |
298 | OMV.Vector3 com; | 284 | if (m_children.Remove(child)) |
299 | lock (m_linksetActivityLock) | ||
300 | { | 285 | { |
301 | com = LinksetRoot.Position; | 286 | BSPrim rootx = LinksetRoot; // capture the root as of now |
302 | 287 | BSPrim childx = child; | |
303 | foreach (BSPhysObject bp in m_children) | 288 | m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() |
304 | { | 289 | { |
305 | com += bp.Position * bp.RawMass; | 290 | // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); |
306 | } | 291 | // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); |
307 | com /= (m_children.Count + 1); | 292 | |
293 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | ||
294 | }); | ||
295 | |||
296 | RecomputeLinksetConstraintVariables(); | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. | ||
301 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
308 | } | 302 | } |
303 | return; | ||
304 | } | ||
309 | 305 | ||
310 | return com; | 306 | // Create a constraint between me (root of linkset) and the passed prim (the child). |
307 | // Called at taint time! | ||
308 | private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) | ||
309 | { | ||
310 | // Zero motion for children so they don't interpolate | ||
311 | childPrim.ZeroMotion(); | ||
312 | |||
313 | // Relative position normalized to the root prim | ||
314 | // Essentually a vector pointing from center of rootPrim to center of childPrim | ||
315 | OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; | ||
316 | |||
317 | // real world coordinate of midpoint between the two objects | ||
318 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
319 | |||
320 | // create a constraint that allows no freedom of movement between the two objects | ||
321 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
322 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | ||
323 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", | ||
324 | rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); | ||
325 | BS6DofConstraint constrain = new BS6DofConstraint( | ||
326 | m_physicsScene.World, rootPrim.Body, childPrim.Body, | ||
327 | midPoint, | ||
328 | true, | ||
329 | true | ||
330 | ); | ||
331 | /* NOTE: attempt to build constraint with full frame computation, etc. | ||
332 | * Using the midpoint is easier since it lets the Bullet code use the transforms | ||
333 | * of the objects. | ||
334 | * Code left here as an example. | ||
335 | // ================================================================================== | ||
336 | // relative position normalized to the root prim | ||
337 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
338 | OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; | ||
339 | |||
340 | // relative rotation of the child to the parent | ||
341 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | ||
342 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
343 | |||
344 | // create a constraint that allows no freedom of movement between the two objects | ||
345 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
346 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | ||
347 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
348 | BS6DofConstraint constrain = new BS6DofConstraint( | ||
349 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | ||
350 | OMV.Vector3.Zero, | ||
351 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
352 | OMV.Vector3.Zero, | ||
353 | OMV.Quaternion.Inverse(childPrim.Orientation), | ||
354 | // A point half way between the parent and child | ||
355 | // childRelativePosition/2, | ||
356 | // childRelativeRotation, | ||
357 | // childRelativePosition/2, | ||
358 | // inverseChildRelativeRotation, | ||
359 | true, | ||
360 | true | ||
361 | ); | ||
362 | // ================================================================================== | ||
363 | */ | ||
364 | |||
365 | m_physicsScene.Constraints.AddConstraint(constrain); | ||
366 | |||
367 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
368 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
369 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
370 | |||
371 | // tweek the constraint to increase stability | ||
372 | constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); | ||
373 | constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), | ||
374 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, | ||
375 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); | ||
376 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); | ||
377 | |||
378 | RecomputeLinksetConstraintVariables(); | ||
379 | } | ||
380 | |||
381 | // Remove linkage between myself and a particular child | ||
382 | // Called at taint time! | ||
383 | private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) | ||
384 | { | ||
385 | // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", | ||
386 | // LogHeader, rootPrim.LocalID, childPrim.LocalID); | ||
387 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
388 | |||
389 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
390 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body); | ||
391 | |||
392 | // Make the child refresh its location | ||
393 | BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); | ||
394 | } | ||
395 | |||
396 | // Remove linkage between myself and any possible children I might have | ||
397 | // Called at taint time! | ||
398 | private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) | ||
399 | { | ||
400 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); | ||
401 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | ||
402 | |||
403 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); | ||
404 | } | ||
405 | |||
406 | // Invoke the detailed logger and output something if it's enabled. | ||
407 | private void DebugLog(string msg, params Object[] args) | ||
408 | { | ||
409 | if (m_physicsScene.ShouldDebugLog) | ||
410 | m_physicsScene.Logger.DebugFormat(msg, args); | ||
311 | } | 411 | } |
312 | 412 | ||
313 | // Invoke the detailed logger and output something if it's enabled. | 413 | // Invoke the detailed logger and output something if it's enabled. |
314 | protected void DetailLog(string msg, params Object[] args) | 414 | private void DetailLog(string msg, params Object[] args) |
315 | { | 415 | { |
316 | if (PhysicsScene.PhysicsLogging.Enabled) | 416 | m_physicsScene.PhysicsLogging.Write(msg, args); |
317 | PhysicsScene.DetailLog(msg, args); | ||
318 | } | 417 | } |
319 | 418 | ||
320 | } | 419 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs deleted file mode 100755 index 12c6d7a..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ /dev/null | |||
@@ -1,273 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public sealed class BSLinksetCompound : BSLinkset | ||
36 | { | ||
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | ||
38 | |||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | ||
40 | { | ||
41 | base.Initialize(scene, parent); | ||
42 | } | ||
43 | |||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
45 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
46 | { | ||
47 | ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
48 | if (IsRoot(requestor) && HasAnyChildren) | ||
49 | { | ||
50 | ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | ||
51 | } | ||
52 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | // When physical properties are changed the linkset needs to recalculate | ||
57 | // its internal properties. | ||
58 | // This is queued in the 'post taint' queue so the | ||
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | ||
61 | { | ||
62 | // External request for Refresh (from BSPrim) is not necessary | ||
63 | // InternalRefresh(requestor); | ||
64 | } | ||
65 | |||
66 | private void InternalRefresh(BSPhysObject requestor) | ||
67 | { | ||
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | ||
69 | // Queue to happen after all the other taint processing | ||
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | ||
71 | { | ||
72 | if (IsRoot(requestor) && HasAnyChildren) | ||
73 | RecomputeLinksetCompound(); | ||
74 | }); | ||
75 | } | ||
76 | |||
77 | // The object is going dynamic (physical). Do any setup necessary | ||
78 | // for a dynamic linkset. | ||
79 | // Only the state of the passed object can be modified. The rest of the linkset | ||
80 | // has not yet been fully constructed. | ||
81 | // Return 'true' if any properties updated on the passed object. | ||
82 | // Called at taint-time! | ||
83 | public override bool MakeDynamic(BSPhysObject child) | ||
84 | { | ||
85 | bool ret = false; | ||
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
87 | if (!IsRoot(child)) | ||
88 | { | ||
89 | // Physical children are removed from the world as the shape ofthe root compound | ||
90 | // shape takes over. | ||
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
93 | ret = true; | ||
94 | } | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
99 | // Return 'true' if any properties updated on the passed object. | ||
100 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
101 | // world if it is a static linkset. | ||
102 | // Called at taint-time! | ||
103 | public override bool MakeStatic(BSPhysObject child) | ||
104 | { | ||
105 | bool ret = false; | ||
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
107 | if (!IsRoot(child)) | ||
108 | { | ||
109 | // The non-physical children can come back to life. | ||
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | ||
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | ||
113 | ret = true; | ||
114 | } | ||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | // Called at taint-time!! | ||
119 | public override void UpdateProperties(BSPhysObject updated) | ||
120 | { | ||
121 | // Nothing to do for constraints on property updates | ||
122 | } | ||
123 | |||
124 | // The children move around in relationship to the root. | ||
125 | // Just grab the current values of wherever it is right now. | ||
126 | public override OMV.Vector3 Position(BSPhysObject member) | ||
127 | { | ||
128 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
129 | } | ||
130 | |||
131 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
132 | { | ||
133 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
134 | } | ||
135 | |||
136 | // Routine called when rebuilding the body of some member of the linkset. | ||
137 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | ||
138 | // Returns 'true' of something was actually removed and would need restoring | ||
139 | // Called at taint-time!! | ||
140 | public override bool RemoveBodyDependencies(BSPrim child) | ||
141 | { | ||
142 | bool ret = false; | ||
143 | |||
144 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | ||
145 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); | ||
146 | |||
147 | if (!IsRoot(child)) | ||
148 | { | ||
149 | // Cause the current shape to be freed and the new one to be built. | ||
150 | InternalRefresh(LinksetRoot); | ||
151 | ret = true; | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
158 | // this routine will restore the removed constraints. | ||
159 | // Called at taint-time!! | ||
160 | public override void RestoreBodyDependencies(BSPrim child) | ||
161 | { | ||
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | ||
163 | } | ||
164 | |||
165 | // ================================================================ | ||
166 | |||
167 | // Add a new child to the linkset. | ||
168 | // Called while LinkActivity is locked. | ||
169 | protected override void AddChildToLinkset(BSPhysObject child) | ||
170 | { | ||
171 | if (!HasChild(child)) | ||
172 | { | ||
173 | m_children.Add(child); | ||
174 | |||
175 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
176 | |||
177 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | ||
178 | InternalRefresh(LinksetRoot); | ||
179 | } | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | // Remove the specified child from the linkset. | ||
184 | // Safe to call even if the child is not really in my linkset. | ||
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | ||
186 | { | ||
187 | if (m_children.Remove(child)) | ||
188 | { | ||
189 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
190 | child.LocalID, | ||
191 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), | ||
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | ||
193 | |||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | ||
195 | child.ForceBodyShapeRebuild(false); | ||
196 | |||
197 | if (!HasAnyChildren) | ||
198 | { | ||
199 | // The linkset is now empty. The root needs rebuilding. | ||
200 | LinksetRoot.ForceBodyShapeRebuild(false); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // Schedule a rebuild of the linkset before the next simulation tick. | ||
205 | InternalRefresh(LinksetRoot); | ||
206 | } | ||
207 | } | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | // Called before the simulation step to make sure the compound based linkset | ||
212 | // is all initialized. | ||
213 | // Constraint linksets are rebuilt every time. | ||
214 | // Note that this works for rebuilding just the root after a linkset is taken apart. | ||
215 | // Called at taint time!! | ||
216 | private void RecomputeLinksetCompound() | ||
217 | { | ||
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | ||
219 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
220 | |||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | ||
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | ||
223 | |||
224 | // Add a shape for each of the other children in the linkset | ||
225 | ForEachMember(delegate(BSPhysObject cPrim) | ||
226 | { | ||
227 | if (!IsRoot(cPrim)) | ||
228 | { | ||
229 | // Each child position and rotation is given relative to the root. | ||
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
233 | |||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | ||
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | ||
236 | |||
237 | if (cPrim.PhysShape.isNativeShape) | ||
238 | { | ||
239 | // Native shapes are not shared so we need to create a new one. | ||
240 | // A mesh or hull is created because scale is not available on a native shape. | ||
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | ||
242 | BulletShape saveShape = cPrim.PhysShape; | ||
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | ||
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
245 | BulletShape newShape = cPrim.PhysShape; | ||
246 | cPrim.PhysShape = saveShape; | ||
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
253 | { | ||
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
256 | } | ||
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
258 | } | ||
259 | } | ||
260 | return false; // 'false' says to move onto the next child in the list | ||
261 | }); | ||
262 | |||
263 | // With all of the linkset packed into the root prim, it has the mass of everyone. | ||
264 | float linksetMass = LinksetMass; | ||
265 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | ||
266 | |||
267 | // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. | ||
268 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
269 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
270 | |||
271 | } | ||
272 | } | ||
273 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs deleted file mode 100755 index d2387fb..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ /dev/null | |||
@@ -1,327 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public sealed class BSLinksetConstraints : BSLinkset | ||
36 | { | ||
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | ||
38 | |||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) | ||
40 | { | ||
41 | base.Initialize(scene, parent); | ||
42 | } | ||
43 | |||
44 | // When physical properties are changed the linkset needs to recalculate | ||
45 | // its internal properties. | ||
46 | // This is queued in the 'post taint' queue so the | ||
47 | // refresh will happen once after all the other taints are applied. | ||
48 | public override void Refresh(BSPhysObject requestor) | ||
49 | { | ||
50 | // Queue to happen after all the other taint processing | ||
51 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | ||
52 | { | ||
53 | if (HasAnyChildren && IsRoot(requestor)) | ||
54 | RecomputeLinksetConstraints(); | ||
55 | }); | ||
56 | } | ||
57 | |||
58 | // The object is going dynamic (physical). Do any setup necessary | ||
59 | // for a dynamic linkset. | ||
60 | // Only the state of the passed object can be modified. The rest of the linkset | ||
61 | // has not yet been fully constructed. | ||
62 | // Return 'true' if any properties updated on the passed object. | ||
63 | // Called at taint-time! | ||
64 | public override bool MakeDynamic(BSPhysObject child) | ||
65 | { | ||
66 | // What is done for each object in BSPrim is what we want. | ||
67 | return false; | ||
68 | } | ||
69 | |||
70 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
71 | // Return 'true' if any properties updated on the passed object. | ||
72 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
73 | // world if it is a static linkset. | ||
74 | // Called at taint-time! | ||
75 | public override bool MakeStatic(BSPhysObject child) | ||
76 | { | ||
77 | // What is done for each object in BSPrim is what we want. | ||
78 | return false; | ||
79 | } | ||
80 | |||
81 | // Called at taint-time!! | ||
82 | public override void UpdateProperties(BSPhysObject updated) | ||
83 | { | ||
84 | // Nothing to do for constraints on property updates | ||
85 | } | ||
86 | |||
87 | // The children of the linkset are moved around by the constraints. | ||
88 | // Just grab the current values of wherever it is right now. | ||
89 | public override OMV.Vector3 Position(BSPhysObject member) | ||
90 | { | ||
91 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
92 | } | ||
93 | |||
94 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
95 | { | ||
96 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
97 | } | ||
98 | |||
99 | // Routine called when rebuilding the body of some member of the linkset. | ||
100 | // Destroy all the constraints have have been made to root and set | ||
101 | // up to rebuild the constraints before the next simulation step. | ||
102 | // Returns 'true' of something was actually removed and would need restoring | ||
103 | // Called at taint-time!! | ||
104 | public override bool RemoveBodyDependencies(BSPrim child) | ||
105 | { | ||
106 | bool ret = false; | ||
107 | |||
108 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | ||
109 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); | ||
110 | |||
111 | lock (m_linksetActivityLock) | ||
112 | { | ||
113 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. | ||
114 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
115 | // Cause the constraints, et al to be rebuilt before the next simulation step. | ||
116 | Refresh(LinksetRoot); | ||
117 | } | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
122 | // this routine will restore the removed constraints. | ||
123 | // Called at taint-time!! | ||
124 | public override void RestoreBodyDependencies(BSPrim child) | ||
125 | { | ||
126 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | ||
127 | } | ||
128 | |||
129 | // ================================================================ | ||
130 | |||
131 | // Add a new child to the linkset. | ||
132 | // Called while LinkActivity is locked. | ||
133 | protected override void AddChildToLinkset(BSPhysObject child) | ||
134 | { | ||
135 | if (!HasChild(child)) | ||
136 | { | ||
137 | m_children.Add(child); | ||
138 | |||
139 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
140 | |||
141 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | ||
142 | Refresh(LinksetRoot); | ||
143 | } | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | // Remove the specified child from the linkset. | ||
148 | // Safe to call even if the child is not really in my linkset. | ||
149 | protected override void RemoveChildFromLinkset(BSPhysObject child) | ||
150 | { | ||
151 | if (m_children.Remove(child)) | ||
152 | { | ||
153 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | ||
154 | BSPhysObject childx = child; | ||
155 | |||
156 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
157 | childx.LocalID, | ||
158 | rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), | ||
159 | childx.LocalID, childx.PhysBody.ptr.ToString("X")); | ||
160 | |||
161 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | ||
162 | { | ||
163 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | ||
164 | }); | ||
165 | // See that the linkset parameters are recomputed at the end of the taint time. | ||
166 | Refresh(LinksetRoot); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | // Non-fatal occurance. | ||
171 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
172 | } | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
177 | // Called at taint time! | ||
178 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | ||
179 | { | ||
180 | // Don't build the constraint when asked. Put it off until just before the simulation step. | ||
181 | Refresh(rootPrim); | ||
182 | } | ||
183 | |||
184 | private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) | ||
185 | { | ||
186 | // Zero motion for children so they don't interpolate | ||
187 | childPrim.ZeroMotion(); | ||
188 | |||
189 | // Relative position normalized to the root prim | ||
190 | // Essentually a vector pointing from center of rootPrim to center of childPrim | ||
191 | OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; | ||
192 | |||
193 | // real world coordinate of midpoint between the two objects | ||
194 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
195 | |||
196 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | ||
197 | rootPrim.LocalID, | ||
198 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), | ||
199 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), | ||
200 | rootPrim.Position, childPrim.Position, midPoint); | ||
201 | |||
202 | // create a constraint that allows no freedom of movement between the two objects | ||
203 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
204 | |||
205 | BSConstraint6Dof constrain = new BSConstraint6Dof( | ||
206 | PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); | ||
207 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); | ||
208 | |||
209 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | ||
210 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | ||
211 | * of the objects. | ||
212 | * Code left for future programmers. | ||
213 | // ================================================================================== | ||
214 | // relative position normalized to the root prim | ||
215 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
216 | OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; | ||
217 | |||
218 | // relative rotation of the child to the parent | ||
219 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | ||
220 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
221 | |||
222 | DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
223 | BS6DofConstraint constrain = new BS6DofConstraint( | ||
224 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | ||
225 | OMV.Vector3.Zero, | ||
226 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
227 | OMV.Vector3.Zero, | ||
228 | OMV.Quaternion.Inverse(childPrim.Orientation), | ||
229 | true, | ||
230 | true | ||
231 | ); | ||
232 | // ================================================================================== | ||
233 | */ | ||
234 | |||
235 | PhysicsScene.Constraints.AddConstraint(constrain); | ||
236 | |||
237 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
238 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
239 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
240 | |||
241 | // tweek the constraint to increase stability | ||
242 | constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); | ||
243 | constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), | ||
244 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, | ||
245 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); | ||
246 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); | ||
247 | if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) | ||
248 | { | ||
249 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | ||
250 | } | ||
251 | return constrain; | ||
252 | } | ||
253 | |||
254 | // Remove linkage between the linkset root and a particular child | ||
255 | // The root and child bodies are passed in because we need to remove the constraint between | ||
256 | // the bodies that were present at unlink time. | ||
257 | // Called at taint time! | ||
258 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | ||
259 | { | ||
260 | bool ret = false; | ||
261 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | ||
262 | rootPrim.LocalID, | ||
263 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), | ||
264 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); | ||
265 | |||
266 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
267 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | ||
268 | { | ||
269 | // Make the child refresh its location | ||
270 | BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); | ||
271 | ret = true; | ||
272 | } | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | // Remove linkage between myself and any possible children I might have. | ||
278 | // Returns 'true' of any constraints were destroyed. | ||
279 | // Called at taint time! | ||
280 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | ||
281 | { | ||
282 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | ||
283 | |||
284 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | ||
285 | } | ||
286 | |||
287 | // Call each of the constraints that make up this linkset and recompute the | ||
288 | // various transforms and variables. Create constraints of not created yet. | ||
289 | // Called before the simulation step to make sure the constraint based linkset | ||
290 | // is all initialized. | ||
291 | // Called at taint time!! | ||
292 | private void RecomputeLinksetConstraints() | ||
293 | { | ||
294 | float linksetMass = LinksetMass; | ||
295 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | ||
296 | |||
297 | // DEBUG: see of inter-linkset collisions are causing problems | ||
298 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
299 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
300 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | ||
301 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); | ||
302 | |||
303 | foreach (BSPhysObject child in m_children) | ||
304 | { | ||
305 | // A child in the linkset physically shows the mass of the whole linkset. | ||
306 | // This allows Bullet to apply enough force on the child to move the whole linkset. | ||
307 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | ||
308 | child.UpdatePhysicalMassProperties(linksetMass); | ||
309 | |||
310 | BSConstraint constrain; | ||
311 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | ||
312 | { | ||
313 | // If constraint doesn't exist yet, create it. | ||
314 | constrain = BuildConstraint(LinksetRoot, child); | ||
315 | } | ||
316 | constrain.RecomputeConstraintVariables(linksetMass); | ||
317 | |||
318 | // DEBUG: see of inter-linkset collisions are causing problems | ||
319 | // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr, | ||
320 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
321 | |||
322 | // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG | ||
323 | } | ||
324 | |||
325 | } | ||
326 | } | ||
327 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs deleted file mode 100755 index 7127aaf..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ /dev/null | |||
@@ -1,248 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | // Class to wrap all objects. | ||
38 | // The rest of BulletSim doesn't need to keep checking for avatars or prims | ||
39 | // unless the difference is significant. | ||
40 | public abstract class BSPhysObject : PhysicsActor | ||
41 | { | ||
42 | protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName) | ||
43 | { | ||
44 | PhysicsScene = parentScene; | ||
45 | LocalID = localID; | ||
46 | PhysObjectName = name; | ||
47 | TypeName = typeName; | ||
48 | |||
49 | Linkset = BSLinkset.Factory(PhysicsScene, this); | ||
50 | LastAssetBuildFailed = false; | ||
51 | |||
52 | CollisionCollection = new CollisionEventUpdate(); | ||
53 | SubscribedEventsMs = 0; | ||
54 | CollidingStep = 0; | ||
55 | CollidingGroundStep = 0; | ||
56 | } | ||
57 | |||
58 | public BSScene PhysicsScene { get; protected set; } | ||
59 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | ||
60 | public string PhysObjectName { get; protected set; } | ||
61 | public string TypeName { get; protected set; } | ||
62 | |||
63 | public BSLinkset Linkset { get; set; } | ||
64 | |||
65 | // Return the object mass without calculating it or having side effects | ||
66 | public abstract float RawMass { get; } | ||
67 | // Set the raw mass but also update physical mass properties (inertia, ...) | ||
68 | public abstract void UpdatePhysicalMassProperties(float mass); | ||
69 | |||
70 | // Reference to the physical body (btCollisionObject) of this object | ||
71 | public BulletBody PhysBody; | ||
72 | // Reference to the physical shape (btCollisionShape) of this object | ||
73 | public BulletShape PhysShape; | ||
74 | |||
75 | // 'true' if the mesh's underlying asset failed to build. | ||
76 | // This will keep us from looping after the first time the build failed. | ||
77 | public bool LastAssetBuildFailed { get; set; } | ||
78 | |||
79 | // The objects base shape information. Null if not a prim type shape. | ||
80 | public PrimitiveBaseShape BaseShape { get; protected set; } | ||
81 | // Some types of objects have preferred physical representations. | ||
82 | // Returns SHAPE_UNKNOWN if there is no preference. | ||
83 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape | ||
84 | { | ||
85 | get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; } | ||
86 | } | ||
87 | |||
88 | // When the physical properties are updated, an EntityProperty holds the update values. | ||
89 | // Keep the current and last EntityProperties to enable computation of differences | ||
90 | // between the current update and the previous values. | ||
91 | public EntityProperties CurrentEntityProperties { get; set; } | ||
92 | public EntityProperties LastEntityProperties { get; set; } | ||
93 | |||
94 | public abstract OMV.Vector3 Scale { get; set; } | ||
95 | public abstract bool IsSolid { get; } | ||
96 | public abstract bool IsStatic { get; } | ||
97 | |||
98 | // Stop all physical motion. | ||
99 | public abstract void ZeroMotion(); | ||
100 | |||
101 | // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. | ||
102 | public virtual void StepVehicle(float timeStep) { } | ||
103 | |||
104 | // Update the physical location and motion of the object. Called with data from Bullet. | ||
105 | public abstract void UpdateProperties(EntityProperties entprop); | ||
106 | |||
107 | // Tell the object to clean up. | ||
108 | public abstract void Destroy(); | ||
109 | |||
110 | public abstract OMV.Vector3 RawPosition { get; set; } | ||
111 | public abstract OMV.Vector3 ForcePosition { get; set; } | ||
112 | |||
113 | public abstract OMV.Quaternion RawOrientation { get; set; } | ||
114 | public abstract OMV.Quaternion ForceOrientation { get; set; } | ||
115 | |||
116 | public abstract OMV.Vector3 ForceVelocity { get; set; } | ||
117 | |||
118 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | ||
119 | |||
120 | public abstract float ForceBuoyancy { get; set; } | ||
121 | |||
122 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | ||
123 | |||
124 | #region Collisions | ||
125 | |||
126 | // Requested number of milliseconds between collision events. Zero means disabled. | ||
127 | protected int SubscribedEventsMs { get; set; } | ||
128 | // Given subscription, the time that a collision may be passed up | ||
129 | protected int NextCollisionOkTime { get; set; } | ||
130 | // The simulation step that last had a collision | ||
131 | protected long CollidingStep { get; set; } | ||
132 | // The simulation step that last had a collision with the ground | ||
133 | protected long CollidingGroundStep { get; set; } | ||
134 | // The collision flags we think are set in Bullet | ||
135 | protected CollisionFlags CurrentCollisionFlags { get; set; } | ||
136 | |||
137 | // The collisions that have been collected this tick | ||
138 | protected CollisionEventUpdate CollisionCollection; | ||
139 | |||
140 | // The simulation step is telling this object about a collision. | ||
141 | // Return 'true' if a collision was processed and should be sent up. | ||
142 | // Called at taint time from within the Step() function | ||
143 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, | ||
144 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
145 | { | ||
146 | bool ret = false; | ||
147 | |||
148 | // The following lines make IsColliding() and IsCollidingGround() work | ||
149 | CollidingStep = PhysicsScene.SimulationStep; | ||
150 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | ||
151 | { | ||
152 | CollidingGroundStep = PhysicsScene.SimulationStep; | ||
153 | } | ||
154 | |||
155 | // prims in the same linkset cannot collide with each other | ||
156 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) | ||
157 | { | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | // if someone has subscribed for collision events.... | ||
162 | if (SubscribedEvents()) { | ||
163 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
164 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", | ||
165 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); | ||
166 | |||
167 | ret = true; | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | // Send the collected collisions into the simulator. | ||
173 | // Called at taint time from within the Step() function thus no locking problems | ||
174 | // with CollisionCollection and ObjectsWithNoMoreCollisions. | ||
175 | // Return 'true' if there were some actual collisions passed up | ||
176 | public virtual bool SendCollisions() | ||
177 | { | ||
178 | bool ret = true; | ||
179 | // If the 'no collision' call, force it to happen right now so quick collision_end | ||
180 | bool force = CollisionCollection.Count == 0; | ||
181 | |||
182 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
183 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | ||
184 | { | ||
185 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; | ||
186 | |||
187 | // We are called if we previously had collisions. If there are no collisions | ||
188 | // this time, send up one last empty event so OpenSim can sense collision end. | ||
189 | if (CollisionCollection.Count == 0) | ||
190 | { | ||
191 | // If I have no collisions this time, remove me from the list of objects with collisions. | ||
192 | ret = false; | ||
193 | } | ||
194 | |||
195 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | ||
196 | base.SendCollisionUpdate(CollisionCollection); | ||
197 | |||
198 | // The collisionCollection structure is passed around in the simulator. | ||
199 | // Make sure we don't have a handle to that one and that a new one is used for next time. | ||
200 | CollisionCollection = new CollisionEventUpdate(); | ||
201 | } | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | // Subscribe for collision events. | ||
206 | // Parameter is the millisecond rate the caller wishes collision events to occur. | ||
207 | public override void SubscribeEvents(int ms) { | ||
208 | // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); | ||
209 | SubscribedEventsMs = ms; | ||
210 | if (ms > 0) | ||
211 | { | ||
212 | // make sure first collision happens | ||
213 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | ||
214 | |||
215 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | ||
216 | { | ||
217 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
218 | }); | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | // Subscribing for zero or less is the same as unsubscribing | ||
223 | UnSubscribeEvents(); | ||
224 | } | ||
225 | } | ||
226 | public override void UnSubscribeEvents() { | ||
227 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | ||
228 | SubscribedEventsMs = 0; | ||
229 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | ||
230 | { | ||
231 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
232 | }); | ||
233 | } | ||
234 | // Return 'true' if the simulator wants collision events | ||
235 | public override bool SubscribedEvents() { | ||
236 | return (SubscribedEventsMs > 0); | ||
237 | } | ||
238 | |||
239 | #endregion // Collisions | ||
240 | |||
241 | // High performance detailed logging routine used by the physical objects. | ||
242 | protected void DetailLog(string msg, params Object[] args) | ||
243 | { | ||
244 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
245 | PhysicsScene.DetailLog(msg, args); | ||
246 | } | ||
247 | } | ||
248 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs index 20f5180..0f027b8 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | |||
@@ -33,7 +33,7 @@ using OpenMetaverse; | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | /// <summary> | 35 | /// <summary> |
36 | /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. | 36 | /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. |
37 | /// This module interfaces to an unmanaged C++ library which makes the | 37 | /// This module interfaces to an unmanaged C++ library which makes the |
38 | /// actual calls into the Bullet physics engine. | 38 | /// actual calls into the Bullet physics engine. |
39 | /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. | 39 | /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. |
@@ -62,7 +62,7 @@ public class BSPlugin : IPhysicsPlugin | |||
62 | if (Util.IsWindows()) | 62 | if (Util.IsWindows()) |
63 | Util.LoadArchSpecificWindowsDll("BulletSim.dll"); | 63 | Util.LoadArchSpecificWindowsDll("BulletSim.dll"); |
64 | // If not Windows, loading is performed by the | 64 | // If not Windows, loading is performed by the |
65 | // Mono loader as specified in | 65 | // Mono loader as specified in |
66 | // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". | 66 | // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". |
67 | 67 | ||
68 | _mScene = new BSScene(sceneIdentifier); | 68 | _mScene = new BSScene(sceneIdentifier); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index aaa0d93..9c20004 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -24,9 +24,6 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | |||
28 | // Uncomment this it enable code to do all shape an body memory management | ||
29 | // in the C# code. | ||
30 | using System; | 27 | using System; |
31 | using System.Reflection; | 28 | using System.Reflection; |
32 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
@@ -39,18 +36,32 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet; | |||
39 | 36 | ||
40 | namespace OpenSim.Region.Physics.BulletSPlugin | 37 | namespace OpenSim.Region.Physics.BulletSPlugin |
41 | { | 38 | { |
42 | |||
43 | [Serializable] | 39 | [Serializable] |
44 | public sealed class BSPrim : BSPhysObject | 40 | public sealed class BSPrim : PhysicsActor |
45 | { | 41 | { |
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
47 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 43 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
48 | 44 | ||
49 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | 45 | private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); } |
50 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | 46 | |
47 | private IMesh _mesh; | ||
48 | private PrimitiveBaseShape _pbs; | ||
49 | private ShapeData.PhysicsShapeType _shapeType; | ||
50 | private ulong _meshKey; | ||
51 | private ulong _hullKey; | ||
52 | private List<ConvexResult> _hulls; | ||
53 | |||
54 | private BSScene _scene; | ||
55 | public BSScene Scene { get { return _scene; } } | ||
56 | private String _avName; | ||
57 | private uint _localID = 0; | ||
58 | |||
59 | // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. | ||
60 | // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
51 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 61 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
52 | // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer | 62 | private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer |
53 | 63 | ||
64 | private bool _stopped; | ||
54 | private bool _grabbed; | 65 | private bool _grabbed; |
55 | private bool _isSelected; | 66 | private bool _isSelected; |
56 | private bool _isVolumeDetect; | 67 | private bool _isVolumeDetect; |
@@ -78,6 +89,25 @@ public sealed class BSPrim : BSPhysObject | |||
78 | private bool _kinematic; | 89 | private bool _kinematic; |
79 | private float _buoyancy; | 90 | private float _buoyancy; |
80 | 91 | ||
92 | // Membership in a linkset is controlled by this class. | ||
93 | private BSLinkset _linkset; | ||
94 | public BSLinkset Linkset | ||
95 | { | ||
96 | get { return _linkset; } | ||
97 | set { _linkset = value; } | ||
98 | } | ||
99 | |||
100 | private int _subscribedEventsMs = 0; | ||
101 | private int _nextCollisionOkTime = 0; | ||
102 | long _collidingStep; | ||
103 | long _collidingGroundStep; | ||
104 | |||
105 | private BulletBody m_body; | ||
106 | public BulletBody Body { | ||
107 | get { return m_body; } | ||
108 | set { m_body = value; } | ||
109 | } | ||
110 | |||
81 | private BSDynamics _vehicle; | 111 | private BSDynamics _vehicle; |
82 | 112 | ||
83 | private OMV.Vector3 _PIDTarget; | 113 | private OMV.Vector3 _PIDTarget; |
@@ -92,112 +122,108 @@ public sealed class BSPrim : BSPhysObject | |||
92 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 122 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
93 | { | 123 | { |
94 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); | 124 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); |
95 | base.BaseInitialize(parent_scene, localID, primName, "BSPrim"); | 125 | _localID = localID; |
96 | _physicsActorType = (int)ActorTypes.Prim; | 126 | _avName = primName; |
127 | _scene = parent_scene; | ||
97 | _position = pos; | 128 | _position = pos; |
98 | _size = size; | 129 | _size = size; |
99 | Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type | 130 | _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type |
100 | _orientation = rotation; | 131 | _orientation = rotation; |
101 | _buoyancy = 1f; | 132 | _buoyancy = 1f; |
102 | _velocity = OMV.Vector3.Zero; | 133 | _velocity = OMV.Vector3.Zero; |
103 | _rotationalVelocity = OMV.Vector3.Zero; | 134 | _rotationalVelocity = OMV.Vector3.Zero; |
104 | BaseShape = pbs; | 135 | _hullKey = 0; |
136 | _meshKey = 0; | ||
137 | _pbs = pbs; | ||
105 | _isPhysical = pisPhysical; | 138 | _isPhysical = pisPhysical; |
106 | _isVolumeDetect = false; | 139 | _isVolumeDetect = false; |
107 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material | 140 | _subscribedEventsMs = 0; |
108 | _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material | 141 | _friction = _scene.Params.defaultFriction; // TODO: compute based on object material |
109 | _restitution = PhysicsScene.Params.defaultRestitution; | 142 | _density = _scene.Params.defaultDensity; // TODO: compute based on object material |
110 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness | 143 | _restitution = _scene.Params.defaultRestitution; |
144 | _linkset = new BSLinkset(_scene, this); // a linkset of one | ||
145 | _vehicle = new BSDynamics(this); // add vehicleness | ||
111 | _mass = CalculateMass(); | 146 | _mass = CalculateMass(); |
112 | |||
113 | // No body or shape yet | ||
114 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); | ||
115 | PhysShape = new BulletShape(IntPtr.Zero); | ||
116 | |||
117 | DetailLog("{0},BSPrim.constructor,call", LocalID); | ||
118 | // do the actual object creation at taint time | 147 | // do the actual object creation at taint time |
119 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | 148 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
149 | _scene.TaintedObject("BSPrim.create", delegate() | ||
120 | { | 150 | { |
121 | CreateGeomAndObject(true); | 151 | RecreateGeomAndObject(); |
122 | 152 | ||
123 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); | 153 | // Get the pointer to the physical body for this object. |
154 | // At the moment, we're still letting BulletSim manage the creation and destruction | ||
155 | // of the object. Someday we'll move that into the C# code. | ||
156 | m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
124 | }); | 157 | }); |
125 | } | 158 | } |
126 | 159 | ||
127 | // called when this prim is being destroyed and we should free all the resources | 160 | // called when this prim is being destroyed and we should free all the resources |
128 | public override void Destroy() | 161 | public void Destroy() |
129 | { | 162 | { |
130 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 163 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
131 | 164 | ||
132 | // Undo any links between me and any other object | 165 | // Undo any links between me and any other object |
133 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 166 | BSPrim parentBefore = _linkset.LinksetRoot; |
134 | int childrenBefore = Linkset.NumberOfChildren; | 167 | int childrenBefore = _linkset.NumberOfChildren; |
135 | 168 | ||
136 | Linkset = Linkset.RemoveMeFromLinkset(this); | 169 | _linkset = _linkset.RemoveMeFromLinkset(this); |
137 | 170 | ||
138 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", | 171 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", |
139 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | 172 | LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); |
140 | 173 | ||
141 | // Undo any vehicle properties | 174 | // Undo any vehicle properties |
142 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 175 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
143 | 176 | ||
144 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() | 177 | _scene.TaintedObject("BSPrim.destroy", delegate() |
145 | { | 178 | { |
146 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 179 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
147 | // If there are physical body and shape, release my use of same. | 180 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. |
148 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 181 | BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); |
149 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
150 | }); | 182 | }); |
151 | } | 183 | } |
152 | 184 | ||
153 | // No one uses this property. | 185 | public override bool Stopped { |
154 | public override bool Stopped { | 186 | get { return _stopped; } |
155 | get { return false; } | ||
156 | } | 187 | } |
157 | public override OMV.Vector3 Size { | 188 | public override OMV.Vector3 Size { |
158 | get { return _size; } | 189 | get { return _size; } |
159 | set { | 190 | set { |
160 | _size = value; | 191 | _size = value; |
161 | ForceBodyShapeRebuild(false); | 192 | _scene.TaintedObject("BSPrim.setSize", delegate() |
162 | } | 193 | { |
194 | _mass = CalculateMass(); // changing size changes the mass | ||
195 | BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); | ||
196 | // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical); | ||
197 | RecreateGeomAndObject(); | ||
198 | }); | ||
199 | } | ||
163 | } | 200 | } |
164 | // Scale is what we set in the physics engine. It is different than 'size' in that | 201 | public override PrimitiveBaseShape Shape { |
165 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | ||
166 | public override OMV.Vector3 Scale { get; set; } | ||
167 | |||
168 | public override PrimitiveBaseShape Shape { | ||
169 | set { | 202 | set { |
170 | BaseShape = value; | 203 | _pbs = value; |
171 | ForceBodyShapeRebuild(false); | 204 | _scene.TaintedObject("BSPrim.setShape", delegate() |
172 | } | 205 | { |
206 | _mass = CalculateMass(); // changing the shape changes the mass | ||
207 | RecreateGeomAndObject(); | ||
208 | }); | ||
209 | } | ||
173 | } | 210 | } |
174 | // Whatever the linkset wants is what I want. | 211 | public override uint LocalID { |
175 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape | 212 | set { _localID = value; } |
176 | { get { return Linkset.PreferredPhysicalShape(this); } } | 213 | get { return _localID; } |
177 | |||
178 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | ||
179 | { | ||
180 | LastAssetBuildFailed = false; | ||
181 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() | ||
182 | { | ||
183 | _mass = CalculateMass(); // changing the shape changes the mass | ||
184 | CreateGeomAndObject(true); | ||
185 | }); | ||
186 | return true; | ||
187 | } | 214 | } |
188 | public override bool Grabbed { | 215 | public override bool Grabbed { |
189 | set { _grabbed = value; | 216 | set { _grabbed = value; |
190 | } | 217 | } |
191 | } | 218 | } |
192 | public override bool Selected { | 219 | public override bool Selected { |
193 | set { | 220 | set { |
194 | _isSelected = value; | 221 | _isSelected = value; |
195 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 222 | _scene.TaintedObject("BSPrim.setSelected", delegate() |
196 | { | 223 | { |
197 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 224 | SetObjectDynamic(); |
198 | SetObjectDynamic(false); | ||
199 | }); | 225 | }); |
200 | } | 226 | } |
201 | } | 227 | } |
202 | public override void CrossingFailure() { return; } | 228 | public override void CrossingFailure() { return; } |
203 | 229 | ||
@@ -206,255 +232,158 @@ public sealed class BSPrim : BSPhysObject | |||
206 | BSPrim parent = obj as BSPrim; | 232 | BSPrim parent = obj as BSPrim; |
207 | if (parent != null) | 233 | if (parent != null) |
208 | { | 234 | { |
209 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 235 | DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID); |
210 | int childrenBefore = Linkset.NumberOfChildren; | 236 | BSPrim parentBefore = _linkset.LinksetRoot; |
237 | int childrenBefore = _linkset.NumberOfChildren; | ||
211 | 238 | ||
212 | Linkset = parent.Linkset.AddMeToLinkset(this); | 239 | _linkset = parent.Linkset.AddMeToLinkset(this); |
213 | 240 | ||
214 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | 241 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", |
215 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | 242 | LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); |
216 | } | 243 | } |
217 | return; | 244 | return; |
218 | } | 245 | } |
219 | 246 | ||
220 | // delink me from my linkset | 247 | // delink me from my linkset |
221 | public override void delink() { | 248 | public override void delink() { |
222 | // TODO: decide if this parent checking needs to happen at taint time | 249 | // TODO: decide if this parent checking needs to happen at taint time |
223 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | 250 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen |
251 | DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, | ||
252 | _linkset.LinksetRoot._avName+"/"+_linkset.LinksetRoot.LocalID.ToString()); | ||
224 | 253 | ||
225 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 254 | BSPrim parentBefore = _linkset.LinksetRoot; |
226 | int childrenBefore = Linkset.NumberOfChildren; | 255 | int childrenBefore = _linkset.NumberOfChildren; |
256 | |||
257 | _linkset = _linkset.RemoveMeFromLinkset(this); | ||
227 | 258 | ||
228 | Linkset = Linkset.RemoveMeFromLinkset(this); | 259 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", |
229 | 260 | LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); | |
230 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | 261 | return; |
231 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
232 | return; | ||
233 | } | 262 | } |
234 | 263 | ||
235 | // Set motion values to zero. | 264 | // Set motion values to zero. |
236 | // Do it to the properties so the values get set in the physics engine. | 265 | // Do it to the properties so the values get set in the physics engine. |
237 | // Push the setting of the values to the viewer. | 266 | // Push the setting of the values to the viewer. |
238 | // Called at taint time! | 267 | // Called at taint time! |
239 | public override void ZeroMotion() | 268 | public void ZeroMotion() |
240 | { | 269 | { |
241 | _velocity = OMV.Vector3.Zero; | 270 | _velocity = OMV.Vector3.Zero; |
242 | _acceleration = OMV.Vector3.Zero; | 271 | _acceleration = OMV.Vector3.Zero; |
243 | _rotationalVelocity = OMV.Vector3.Zero; | 272 | _rotationalVelocity = OMV.Vector3.Zero; |
244 | 273 | ||
245 | // Zero some other properties in the physics engine | 274 | // Zero some other properties directly into the physics engine |
246 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 275 | BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); |
276 | BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero); | ||
277 | BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
278 | BulletSimAPI.ClearForces2(Body.Ptr); | ||
247 | } | 279 | } |
248 | 280 | ||
249 | public override void LockAngularMotion(OMV.Vector3 axis) | 281 | public override void LockAngularMotion(OMV.Vector3 axis) |
250 | { | 282 | { |
251 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 283 | // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
252 | return; | 284 | return; |
253 | } | 285 | } |
254 | 286 | ||
255 | public override OMV.Vector3 RawPosition | 287 | public override OMV.Vector3 Position { |
256 | { | 288 | get { |
257 | get { return _position; } | 289 | if (!_linkset.IsRoot(this)) |
258 | set { _position = value; } | 290 | // child prims move around based on their parent. Need to get the latest location |
259 | } | 291 | _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
260 | public override OMV.Vector3 Position { | ||
261 | get { | ||
262 | // child prims move around based on their parent. Need to get the latest location | ||
263 | if (!Linkset.IsRoot(this)) | ||
264 | _position = Linkset.Position(this); | ||
265 | 292 | ||
266 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | 293 | // don't do the GetObjectPosition for root elements because this function is called a zillion times |
267 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 294 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
268 | return _position; | 295 | return _position; |
269 | } | 296 | } |
270 | set { | 297 | set { |
271 | // If you must push the position into the physics engine, use ForcePosition. | ||
272 | if (_position == value) | ||
273 | { | ||
274 | return; | ||
275 | } | ||
276 | _position = value; | 298 | _position = value; |
277 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | 299 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? |
278 | PositionSanityCheck(); | 300 | _scene.TaintedObject("BSPrim.setPosition", delegate() |
279 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | ||
280 | { | 301 | { |
281 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 302 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
282 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 303 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
283 | ActivateIfPhysical(false); | ||
284 | }); | ||
285 | } | ||
286 | } | ||
287 | public override OMV.Vector3 ForcePosition { | ||
288 | get { | ||
289 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | ||
290 | return _position; | ||
291 | } | ||
292 | set { | ||
293 | _position = value; | ||
294 | PositionSanityCheck(); | ||
295 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
296 | ActivateIfPhysical(false); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
301 | // Check for being below terrain and being out of bounds. | ||
302 | // Returns 'true' of the position was made sane by some action. | ||
303 | private bool PositionSanityCheck() | ||
304 | { | ||
305 | bool ret = false; | ||
306 | |||
307 | // If totally below the ground, move the prim up | ||
308 | // TODO: figure out the right solution for this... only for dynamic objects? | ||
309 | /* | ||
310 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | ||
311 | if (Position.Z < terrainHeight) | ||
312 | { | ||
313 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | ||
314 | _position.Z = terrainHeight + 2.0f; | ||
315 | ret = true; | ||
316 | } | ||
317 | */ | ||
318 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
319 | { | ||
320 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | ||
321 | // TODO: a floating motor so object will bob in the water | ||
322 | if (Position.Z < waterHeight) | ||
323 | { | ||
324 | _position.Z = waterHeight; | ||
325 | ret = true; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | // TODO: check for out of bounds | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | // A version of the sanity check that also makes sure a new position value is | ||
334 | // pushed to the physics engine. This routine would be used by anyone | ||
335 | // who is not already pushing the value. | ||
336 | private bool PositionSanityCheck(bool inTaintTime) | ||
337 | { | ||
338 | bool ret = false; | ||
339 | if (PositionSanityCheck()) | ||
340 | { | ||
341 | // The new position value must be pushed into the physics engine but we can't | ||
342 | // just assign to "Position" because of potential call loops. | ||
343 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate() | ||
344 | { | ||
345 | DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
346 | ForcePosition = _position; | ||
347 | }); | 304 | }); |
348 | ret = true; | 305 | } |
349 | } | ||
350 | return ret; | ||
351 | } | 306 | } |
352 | 307 | ||
353 | // Return the effective mass of the object. | 308 | // Return the effective mass of the object. |
354 | // If there are multiple items in the linkset, add them together for the root | 309 | // If there are multiple items in the linkset, add them together for the root |
355 | public override float Mass | 310 | public override float Mass |
356 | { | 311 | { |
357 | get | 312 | get |
358 | { | 313 | { |
359 | return Linkset.LinksetMass; | 314 | return _linkset.LinksetMass; |
360 | // return _mass; | ||
361 | } | 315 | } |
362 | } | 316 | } |
363 | 317 | ||
364 | // used when we only want this prim's mass and not the linkset thing | 318 | // used when we only want this prim's mass and not the linkset thing |
365 | public override float RawMass { | 319 | public float MassRaw { get { return _mass; } } |
366 | get { return _mass; } | ||
367 | } | ||
368 | // Set the physical mass to the passed mass. | ||
369 | // Note that this does not change _mass! | ||
370 | public override void UpdatePhysicalMassProperties(float physMass) | ||
371 | { | ||
372 | if (IsStatic) | ||
373 | { | ||
374 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, OMV.Vector3.Zero); | ||
375 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
380 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | ||
381 | // center of mass is at the zero of the object | ||
382 | BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | ||
383 | // BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | ||
384 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, localInertia); | ||
385 | } | ||
386 | } | ||
387 | 320 | ||
388 | // Is this used? | 321 | // Is this used? |
389 | public override OMV.Vector3 CenterOfMass | 322 | public override OMV.Vector3 CenterOfMass |
390 | { | 323 | { |
391 | get { return Linkset.CenterOfMass; } | 324 | get { return _linkset.CenterOfMass; } |
392 | } | 325 | } |
393 | 326 | ||
394 | // Is this used? | 327 | // Is this used? |
395 | public override OMV.Vector3 GeometricCenter | 328 | public override OMV.Vector3 GeometricCenter |
396 | { | 329 | { |
397 | get { return Linkset.GeometricCenter; } | 330 | get { return _linkset.GeometricCenter; } |
398 | } | 331 | } |
399 | 332 | ||
400 | public override OMV.Vector3 Force { | 333 | public override OMV.Vector3 Force { |
401 | get { return _force; } | 334 | get { return _force; } |
402 | set { | 335 | set { |
403 | _force = value; | 336 | _force = value; |
404 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() | 337 | _scene.TaintedObject("BSPrim.setForce", delegate() |
405 | { | 338 | { |
406 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 339 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |
407 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 340 | // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); |
341 | BulletSimAPI.SetObjectForce2(Body.Ptr, _force); | ||
408 | }); | 342 | }); |
409 | } | 343 | } |
410 | } | 344 | } |
411 | 345 | ||
412 | public override int VehicleType { | 346 | public override int VehicleType { |
413 | get { | 347 | get { |
414 | return (int)_vehicle.Type; // if we are a vehicle, return that type | 348 | return (int)_vehicle.Type; // if we are a vehicle, return that type |
415 | } | 349 | } |
416 | set { | 350 | set { |
417 | Vehicle type = (Vehicle)value; | 351 | Vehicle type = (Vehicle)value; |
418 | 352 | BSPrim vehiclePrim = this; | |
419 | // Tell the scene about the vehicle so it will get processing each frame. | 353 | _scene.TaintedObject("setVehicleType", delegate() |
420 | PhysicsScene.VehicleInSceneTypeChanged(this, type); | ||
421 | |||
422 | PhysicsScene.TaintedObject("setVehicleType", delegate() | ||
423 | { | 354 | { |
424 | // Done at taint time so we're sure the physics engine is not using the variables | 355 | // Done at taint time so we're sure the physics engine is not using the variables |
425 | // Vehicle code changes the parameters for this vehicle type. | 356 | // Vehicle code changes the parameters for this vehicle type. |
426 | _vehicle.ProcessTypeChange(type); | 357 | _vehicle.ProcessTypeChange(type); |
427 | ActivateIfPhysical(false); | 358 | // Tell the scene about the vehicle so it will get processing each frame. |
359 | _scene.VehicleInSceneTypeChanged(this, type); | ||
428 | }); | 360 | }); |
429 | } | 361 | } |
430 | } | 362 | } |
431 | public override void VehicleFloatParam(int param, float value) | 363 | public override void VehicleFloatParam(int param, float value) |
432 | { | 364 | { |
433 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 365 | _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
434 | { | 366 | { |
435 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 367 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); |
436 | ActivateIfPhysical(false); | ||
437 | }); | 368 | }); |
438 | } | 369 | } |
439 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 370 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
440 | { | 371 | { |
441 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 372 | _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
442 | { | 373 | { |
443 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 374 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); |
444 | ActivateIfPhysical(false); | ||
445 | }); | 375 | }); |
446 | } | 376 | } |
447 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 377 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
448 | { | 378 | { |
449 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 379 | _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
450 | { | 380 | { |
451 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 381 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); |
452 | ActivateIfPhysical(false); | ||
453 | }); | 382 | }); |
454 | } | 383 | } |
455 | public override void VehicleFlags(int param, bool remove) | 384 | public override void VehicleFlags(int param, bool remove) |
456 | { | 385 | { |
457 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | 386 | _scene.TaintedObject("BSPrim.VehicleFlags", delegate() |
458 | { | 387 | { |
459 | _vehicle.ProcessVehicleFlags(param, remove); | 388 | _vehicle.ProcessVehicleFlags(param, remove); |
460 | }); | 389 | }); |
@@ -462,355 +391,143 @@ public sealed class BSPrim : BSPhysObject | |||
462 | 391 | ||
463 | // Called each simulation step to advance vehicle characteristics. | 392 | // Called each simulation step to advance vehicle characteristics. |
464 | // Called from Scene when doing simulation step so we're in taint processing time. | 393 | // Called from Scene when doing simulation step so we're in taint processing time. |
465 | public override void StepVehicle(float timeStep) | 394 | public void StepVehicle(float timeStep) |
466 | { | 395 | { |
467 | if (IsPhysical && _vehicle.IsActive) | 396 | if (IsPhysical) |
468 | { | ||
469 | _vehicle.Step(timeStep); | 397 | _vehicle.Step(timeStep); |
470 | /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step | ||
471 | PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate() | ||
472 | { | ||
473 | // This resets the interpolation values and recomputes the tensor variables | ||
474 | BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation); | ||
475 | }); | ||
476 | */ | ||
477 | } | ||
478 | } | 398 | } |
479 | 399 | ||
480 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 400 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
481 | public override void SetVolumeDetect(int param) { | 401 | public override void SetVolumeDetect(int param) { |
482 | bool newValue = (param != 0); | 402 | bool newValue = (param != 0); |
483 | if (_isVolumeDetect != newValue) | 403 | _isVolumeDetect = newValue; |
404 | _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | ||
484 | { | 405 | { |
485 | _isVolumeDetect = newValue; | 406 | SetObjectDynamic(); |
486 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | 407 | }); |
487 | { | 408 | return; |
488 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | ||
489 | SetObjectDynamic(true); | ||
490 | }); | ||
491 | } | ||
492 | return; | ||
493 | } | 409 | } |
494 | public override OMV.Vector3 Velocity { | 410 | |
495 | get { return _velocity; } | 411 | public override OMV.Vector3 Velocity { |
412 | get { return _velocity; } | ||
496 | set { | 413 | set { |
497 | _velocity = value; | 414 | _velocity = value; |
498 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 415 | _scene.TaintedObject("BSPrim.setVelocity", delegate() |
499 | { | 416 | { |
500 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 417 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
501 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 418 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); |
502 | }); | 419 | }); |
503 | } | 420 | } |
504 | } | ||
505 | public override OMV.Vector3 ForceVelocity { | ||
506 | get { return _velocity; } | ||
507 | set { | ||
508 | _velocity = value; | ||
509 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
510 | } | ||
511 | } | 421 | } |
512 | public override OMV.Vector3 Torque { | 422 | public override OMV.Vector3 Torque { |
513 | get { return _torque; } | 423 | get { return _torque; } |
514 | set { | 424 | set { _torque = value; |
515 | _torque = value; | ||
516 | AddAngularForce(_torque, false, false); | ||
517 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 425 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |
518 | } | 426 | } |
519 | } | 427 | } |
520 | public override float CollisionScore { | 428 | public override float CollisionScore { |
521 | get { return _collisionScore; } | 429 | get { return _collisionScore; } |
522 | set { _collisionScore = value; | 430 | set { _collisionScore = value; |
523 | } | 431 | } |
524 | } | 432 | } |
525 | public override OMV.Vector3 Acceleration { | 433 | public override OMV.Vector3 Acceleration { |
526 | get { return _acceleration; } | 434 | get { return _acceleration; } |
527 | set { _acceleration = value; } | 435 | set { _acceleration = value; } |
528 | } | 436 | } |
529 | public override OMV.Quaternion RawOrientation | 437 | public override OMV.Quaternion Orientation { |
530 | { | ||
531 | get { return _orientation; } | ||
532 | set { _orientation = value; } | ||
533 | } | ||
534 | public override OMV.Quaternion Orientation { | ||
535 | get { | 438 | get { |
536 | // Children move around because tied to parent. Get a fresh value. | 439 | if (!_linkset.IsRoot(this)) |
537 | if (!Linkset.IsRoot(this)) | ||
538 | { | 440 | { |
539 | _orientation = Linkset.Orientation(this); | 441 | // Children move around because tied to parent. Get a fresh value. |
442 | _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); | ||
540 | } | 443 | } |
541 | return _orientation; | 444 | return _orientation; |
542 | } | 445 | } |
543 | set { | 446 | set { |
544 | if (_orientation == value) | ||
545 | return; | ||
546 | _orientation = value; | 447 | _orientation = value; |
547 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 448 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? |
548 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 449 | _scene.TaintedObject("BSPrim.setOrientation", delegate() |
549 | { | 450 | { |
550 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 451 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
551 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 452 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
552 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 453 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
553 | }); | 454 | }); |
554 | } | 455 | } |
555 | } | 456 | } |
556 | // Go directly to Bullet to get/set the value. | 457 | public override int PhysicsActorType { |
557 | public override OMV.Quaternion ForceOrientation | 458 | get { return _physicsActorType; } |
558 | { | 459 | set { _physicsActorType = value; |
559 | get | 460 | } |
560 | { | ||
561 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | ||
562 | return _orientation; | ||
563 | } | ||
564 | set | ||
565 | { | ||
566 | _orientation = value; | ||
567 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
568 | } | ||
569 | } | 461 | } |
570 | public override int PhysicsActorType { | 462 | public override bool IsPhysical { |
571 | get { return _physicsActorType; } | 463 | get { return _isPhysical; } |
572 | set { _physicsActorType = value; } | ||
573 | } | ||
574 | public override bool IsPhysical { | ||
575 | get { return _isPhysical; } | ||
576 | set { | 464 | set { |
577 | if (_isPhysical != value) | 465 | _isPhysical = value; |
466 | _scene.TaintedObject("BSPrim.setIsPhysical", delegate() | ||
578 | { | 467 | { |
579 | _isPhysical = value; | 468 | SetObjectDynamic(); |
580 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 469 | }); |
581 | { | 470 | } |
582 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | ||
583 | SetObjectDynamic(true); | ||
584 | // whether phys-to-static or static-to-phys, the object is not moving. | ||
585 | ZeroMotion(); | ||
586 | }); | ||
587 | } | ||
588 | } | ||
589 | } | 471 | } |
590 | 472 | ||
591 | // An object is static (does not move) if selected or not physical | 473 | // An object is static (does not move) if selected or not physical |
592 | public override bool IsStatic | 474 | private bool IsStatic |
593 | { | 475 | { |
594 | get { return _isSelected || !IsPhysical; } | 476 | get { return _isSelected || !IsPhysical; } |
595 | } | 477 | } |
596 | 478 | ||
597 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | 479 | // An object is solid if it's not phantom and if it's not doing VolumeDetect |
598 | public override bool IsSolid | 480 | private bool IsSolid |
599 | { | 481 | { |
600 | get { return !IsPhantom && !_isVolumeDetect; } | 482 | get { return !IsPhantom && !_isVolumeDetect; } |
601 | } | 483 | } |
602 | 484 | ||
603 | // Make gravity work if the object is physical and not selected | 485 | // Make gravity work if the object is physical and not selected |
604 | // Called at taint-time!! | 486 | // No locking here because only called when it is safe |
605 | private void SetObjectDynamic(bool forceRebuild) | 487 | private void SetObjectDynamic() |
606 | { | ||
607 | // Recreate the physical object if necessary | ||
608 | CreateGeomAndObject(forceRebuild); | ||
609 | } | ||
610 | |||
611 | // Convert the simulator's physical properties into settings on BulletSim objects. | ||
612 | // There are four flags we're interested in: | ||
613 | // IsStatic: Object does not move, otherwise the object has mass and moves | ||
614 | // isSolid: other objects bounce off of this object | ||
615 | // isVolumeDetect: other objects pass through but can generate collisions | ||
616 | // collisionEvents: whether this object returns collision events | ||
617 | private void UpdatePhysicalParameters() | ||
618 | { | ||
619 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); | ||
620 | |||
621 | // Mangling all the physical properties requires the object not be in the physical world. | ||
622 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | ||
623 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
624 | |||
625 | // Set up the object physicalness (does gravity and collisions move this object) | ||
626 | MakeDynamic(IsStatic); | ||
627 | |||
628 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | ||
629 | _vehicle.Refresh(); | ||
630 | |||
631 | // Arrange for collision events if the simulator wants them | ||
632 | EnableCollisions(SubscribedEvents()); | ||
633 | |||
634 | // Make solid or not (do things bounce off or pass through this object). | ||
635 | MakeSolid(IsSolid); | ||
636 | |||
637 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
638 | |||
639 | // Rebuild its shape | ||
640 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
641 | |||
642 | // Collision filter can be set only when the object is in the world | ||
643 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | ||
644 | { | ||
645 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | ||
646 | } | ||
647 | |||
648 | // Recompute any linkset parameters. | ||
649 | // When going from non-physical to physical, this re-enables the constraints that | ||
650 | // had been automatically disabled when the mass was set to zero. | ||
651 | Linkset.Refresh(this); | ||
652 | |||
653 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | ||
654 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); | ||
655 | } | ||
656 | |||
657 | // "Making dynamic" means changing to and from static. | ||
658 | // When static, gravity does not effect the object and it is fixed in space. | ||
659 | // When dynamic, the object can fall and be pushed by others. | ||
660 | // This is independent of its 'solidness' which controls what passes through | ||
661 | // this object and what interacts with it. | ||
662 | private void MakeDynamic(bool makeStatic) | ||
663 | { | 488 | { |
664 | if (makeStatic) | 489 | // RA: remove this for the moment. |
665 | { | 490 | // The problem is that dynamic objects are hulls so if we are becoming physical |
666 | // Become a Bullet 'static' object type | 491 | // the shape has to be checked and possibly built. |
667 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 492 | // Maybe a VerifyCorrectPhysicalShape() routine? |
668 | // Stop all movement | 493 | // RecreateGeomAndObject(); |
669 | ZeroMotion(); | ||
670 | // Center of mass is at the center of the object | ||
671 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
672 | // Mass is zero which disables a bunch of physics stuff in Bullet | ||
673 | UpdatePhysicalMassProperties(0f); | ||
674 | // Set collision detection parameters | ||
675 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
676 | { | ||
677 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
678 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
679 | } | ||
680 | // There can be special things needed for implementing linksets | ||
681 | Linkset.MakeStatic(this); | ||
682 | // The activation state is 'disabled' so Bullet will not try to act on it. | ||
683 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
684 | // Start it out sleeping and physical actions could wake it up. | ||
685 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
686 | |||
687 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | ||
688 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | // Not a Bullet static object | ||
693 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
694 | |||
695 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | ||
696 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); | ||
697 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); | ||
698 | |||
699 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | ||
700 | // Since this can be called multiple times, only zero forces when becoming physical | ||
701 | // BulletSimAPI.ClearAllForces2(BSBody.ptr); | ||
702 | 494 | ||
703 | // For good measure, make sure the transform is set through to the motion state | 495 | // Bullet wants static objects to have a mass of zero |
704 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 496 | float mass = IsStatic ? 0f : _mass; |
705 | 497 | ||
706 | // Center of mass is at the center of the object | 498 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); |
707 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
708 | |||
709 | // A dynamic object has mass | ||
710 | UpdatePhysicalMassProperties(RawMass); | ||
711 | |||
712 | // Set collision detection parameters | ||
713 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
714 | { | ||
715 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
716 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
717 | } | ||
718 | |||
719 | // Various values for simulation limits | ||
720 | BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); | ||
721 | BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); | ||
722 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | ||
723 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | ||
724 | |||
725 | // There might be special things needed for implementing linksets. | ||
726 | Linkset.MakeDynamic(this); | ||
727 | |||
728 | // Force activation of the object so Bullet will act on it. | ||
729 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | ||
730 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | ||
731 | // BulletSimAPI.Activate2(BSBody.ptr, true); | ||
732 | |||
733 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | ||
734 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | // "Making solid" means that other object will not pass through this object. | ||
739 | // To make transparent, we create a Bullet ghost object. | ||
740 | // Note: This expects to be called from the UpdatePhysicalParameters() routine as | ||
741 | // the functions after this one set up the state of a possibly newly created collision body. | ||
742 | private void MakeSolid(bool makeSolid) | ||
743 | { | ||
744 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); | ||
745 | if (makeSolid) | ||
746 | { | ||
747 | // Verify the previous code created the correct shape for this type of thing. | ||
748 | if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) | ||
749 | { | ||
750 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
751 | } | ||
752 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) | ||
757 | { | ||
758 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
759 | } | ||
760 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
761 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | ||
762 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | ||
763 | } | ||
764 | } | ||
765 | 499 | ||
766 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | 500 | // recompute any linkset parameters |
767 | // they need waking up when parameters are changed. | 501 | _linkset.Refresh(this); |
768 | // Called in taint-time!! | ||
769 | private void ActivateIfPhysical(bool forceIt) | ||
770 | { | ||
771 | if (IsPhysical) | ||
772 | BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | ||
773 | } | ||
774 | 502 | ||
775 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 503 | CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr); |
776 | private void EnableCollisions(bool wantsCollisionEvents) | 504 | // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf); |
777 | { | ||
778 | if (wantsCollisionEvents) | ||
779 | { | ||
780 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
781 | } | ||
782 | else | ||
783 | { | ||
784 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
785 | } | ||
786 | } | 505 | } |
787 | 506 | ||
788 | // prims don't fly | 507 | // prims don't fly |
789 | public override bool Flying { | 508 | public override bool Flying { |
790 | get { return _flying; } | 509 | get { return _flying; } |
791 | set { | 510 | set { _flying = value; } |
792 | _flying = value; | ||
793 | } | ||
794 | } | 511 | } |
795 | public override bool SetAlwaysRun { | 512 | public override bool SetAlwaysRun { |
796 | get { return _setAlwaysRun; } | 513 | get { return _setAlwaysRun; } |
797 | set { _setAlwaysRun = value; } | 514 | set { _setAlwaysRun = value; } |
798 | } | 515 | } |
799 | public override bool ThrottleUpdates { | 516 | public override bool ThrottleUpdates { |
800 | get { return _throttleUpdates; } | 517 | get { return _throttleUpdates; } |
801 | set { _throttleUpdates = value; } | 518 | set { _throttleUpdates = value; } |
802 | } | 519 | } |
803 | public override bool IsColliding { | 520 | public override bool IsColliding { |
804 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | 521 | get { return (_collidingStep == _scene.SimulationStep); } |
805 | set { _isColliding = value; } | 522 | set { _isColliding = value; } |
806 | } | 523 | } |
807 | public override bool CollidingGround { | 524 | public override bool CollidingGround { |
808 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | 525 | get { return (_collidingGroundStep == _scene.SimulationStep); } |
809 | set { _collidingGround = value; } | 526 | set { _collidingGround = value; } |
810 | } | 527 | } |
811 | public override bool CollidingObj { | 528 | public override bool CollidingObj { |
812 | get { return _collidingObj; } | 529 | get { return _collidingObj; } |
813 | set { _collidingObj = value; } | 530 | set { _collidingObj = value; } |
814 | } | 531 | } |
815 | public bool IsPhantom { | 532 | public bool IsPhantom { |
816 | get { | 533 | get { |
@@ -820,19 +537,10 @@ public sealed class BSPrim : BSPhysObject | |||
820 | return false; | 537 | return false; |
821 | } | 538 | } |
822 | } | 539 | } |
823 | public override bool FloatOnWater { | 540 | public override bool FloatOnWater { |
824 | set { | 541 | set { _floatOnWater = value; } |
825 | _floatOnWater = value; | ||
826 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | ||
827 | { | ||
828 | if (_floatOnWater) | ||
829 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
830 | else | ||
831 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
832 | }); | ||
833 | } | ||
834 | } | 542 | } |
835 | public override OMV.Vector3 RotationalVelocity { | 543 | public override OMV.Vector3 RotationalVelocity { |
836 | get { | 544 | get { |
837 | /* | 545 | /* |
838 | OMV.Vector3 pv = OMV.Vector3.Zero; | 546 | OMV.Vector3 pv = OMV.Vector3.Zero; |
@@ -844,76 +552,58 @@ public sealed class BSPrim : BSPhysObject | |||
844 | */ | 552 | */ |
845 | 553 | ||
846 | return _rotationalVelocity; | 554 | return _rotationalVelocity; |
847 | } | 555 | } |
848 | set { | 556 | set { |
849 | _rotationalVelocity = value; | 557 | _rotationalVelocity = value; |
850 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 558 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
851 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 559 | _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
852 | { | 560 | { |
853 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 561 | // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
854 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | 562 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); |
855 | }); | 563 | }); |
856 | } | 564 | } |
857 | } | ||
858 | public override OMV.Vector3 ForceRotationalVelocity { | ||
859 | get { | ||
860 | return _rotationalVelocity; | ||
861 | } | ||
862 | set { | ||
863 | _rotationalVelocity = value; | ||
864 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
865 | } | ||
866 | } | 565 | } |
867 | public override bool Kinematic { | 566 | public override bool Kinematic { |
868 | get { return _kinematic; } | 567 | get { return _kinematic; } |
869 | set { _kinematic = value; | 568 | set { _kinematic = value; |
870 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); | 569 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); |
871 | } | 570 | } |
872 | } | 571 | } |
873 | public override float Buoyancy { | 572 | public override float Buoyancy { |
874 | get { return _buoyancy; } | 573 | get { return _buoyancy; } |
875 | set { | 574 | set { |
876 | _buoyancy = value; | 575 | _buoyancy = value; |
877 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | 576 | _scene.TaintedObject("BSPrim.setBuoyancy", delegate() |
878 | { | 577 | { |
879 | ForceBuoyancy = _buoyancy; | 578 | // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
579 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | ||
880 | }); | 580 | }); |
881 | } | 581 | } |
882 | } | ||
883 | public override float ForceBuoyancy { | ||
884 | get { return _buoyancy; } | ||
885 | set { | ||
886 | _buoyancy = value; | ||
887 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
888 | // Buoyancy is faked by changing the gravity applied to the object | ||
889 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
890 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
891 | } | ||
892 | } | 582 | } |
893 | 583 | ||
894 | // Used for MoveTo | 584 | // Used for MoveTo |
895 | public override OMV.Vector3 PIDTarget { | 585 | public override OMV.Vector3 PIDTarget { |
896 | set { _PIDTarget = value; } | 586 | set { _PIDTarget = value; } |
897 | } | 587 | } |
898 | public override bool PIDActive { | 588 | public override bool PIDActive { |
899 | set { _usePID = value; } | 589 | set { _usePID = value; } |
900 | } | 590 | } |
901 | public override float PIDTau { | 591 | public override float PIDTau { |
902 | set { _PIDTau = value; } | 592 | set { _PIDTau = value; } |
903 | } | 593 | } |
904 | 594 | ||
905 | // Used for llSetHoverHeight and maybe vehicle height | 595 | // Used for llSetHoverHeight and maybe vehicle height |
906 | // Hover Height will override MoveTo target's Z | 596 | // Hover Height will override MoveTo target's Z |
907 | public override bool PIDHoverActive { | 597 | public override bool PIDHoverActive { |
908 | set { _useHoverPID = value; } | 598 | set { _useHoverPID = value; } |
909 | } | 599 | } |
910 | public override float PIDHoverHeight { | 600 | public override float PIDHoverHeight { |
911 | set { _PIDHoverHeight = value; } | 601 | set { _PIDHoverHeight = value; } |
912 | } | 602 | } |
913 | public override PIDHoverType PIDHoverType { | 603 | public override PIDHoverType PIDHoverType { |
914 | set { _PIDHoverType = value; } | 604 | set { _PIDHoverType = value; } |
915 | } | 605 | } |
916 | public override float PIDHoverTau { | 606 | public override float PIDHoverTau { |
917 | set { _PIDHoverTao = value; } | 607 | set { _PIDHoverTao = value; } |
918 | } | 608 | } |
919 | 609 | ||
@@ -925,9 +615,6 @@ public sealed class BSPrim : BSPhysObject | |||
925 | 615 | ||
926 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | 616 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); |
927 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 617 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
928 | AddForce(force, pushforce, false); | ||
929 | } | ||
930 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
931 | // for an object, doesn't matter if force is a pushforce or not | 618 | // for an object, doesn't matter if force is a pushforce or not |
932 | if (force.IsFinite()) | 619 | if (force.IsFinite()) |
933 | { | 620 | { |
@@ -937,78 +624,56 @@ public sealed class BSPrim : BSPhysObject | |||
937 | } | 624 | } |
938 | else | 625 | else |
939 | { | 626 | { |
940 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 627 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); |
941 | return; | 628 | return; |
942 | } | 629 | } |
943 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | 630 | _scene.TaintedObject("BSPrim.AddForce", delegate() |
944 | { | 631 | { |
945 | OMV.Vector3 fSum = OMV.Vector3.Zero; | 632 | OMV.Vector3 fSum = OMV.Vector3.Zero; |
946 | lock (m_accumulatedForces) | 633 | lock (m_accumulatedForces) |
947 | { | 634 | { |
948 | // Sum the accumulated additional forces for one big force to apply once. | ||
949 | foreach (OMV.Vector3 v in m_accumulatedForces) | 635 | foreach (OMV.Vector3 v in m_accumulatedForces) |
950 | { | 636 | { |
951 | fSum += v; | 637 | fSum += v; |
952 | } | 638 | } |
953 | m_accumulatedForces.Clear(); | 639 | m_accumulatedForces.Clear(); |
954 | } | 640 | } |
955 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); | 641 | // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force); |
956 | if (fSum != OMV.Vector3.Zero) | 642 | BulletSimAPI.AddObjectForce2(Body.Ptr, fSum); |
957 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | ||
958 | }); | 643 | }); |
959 | } | 644 | } |
960 | 645 | ||
961 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); | 646 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
962 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 647 | // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); |
963 | AddAngularForce(force, pushforce, false); | 648 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); |
964 | } | 649 | } |
965 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | 650 | public override void SetMomentum(OMV.Vector3 momentum) { |
966 | { | 651 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); |
967 | if (force.IsFinite()) | 652 | } |
968 | { | 653 | public override void SubscribeEvents(int ms) { |
969 | // _force += force; | 654 | _subscribedEventsMs = ms; |
970 | lock (m_accumulatedAngularForces) | 655 | if (ms > 0) |
971 | m_accumulatedAngularForces.Add(new OMV.Vector3(force)); | ||
972 | } | ||
973 | else | ||
974 | { | ||
975 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
976 | return; | ||
977 | } | ||
978 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||
979 | { | 656 | { |
980 | OMV.Vector3 fSum = OMV.Vector3.Zero; | 657 | // make sure first collision happens |
981 | lock (m_accumulatedAngularForces) | 658 | _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; |
982 | { | 659 | |
983 | // Sum the accumulated additional forces for one big force to apply once. | 660 | Scene.TaintedObject("BSPrim.SubscribeEvents", delegate() |
984 | foreach (OMV.Vector3 v in m_accumulatedAngularForces) | ||
985 | { | ||
986 | fSum += v; | ||
987 | } | ||
988 | m_accumulatedAngularForces.Clear(); | ||
989 | } | ||
990 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); | ||
991 | if (fSum != OMV.Vector3.Zero) | ||
992 | { | 661 | { |
993 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | 662 | BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
994 | _torque = fSum; | 663 | }); |
995 | } | 664 | } |
996 | }); | ||
997 | } | 665 | } |
998 | // A torque impulse. | 666 | public override void UnSubscribeEvents() { |
999 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 667 | _subscribedEventsMs = 0; |
1000 | { | 668 | Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate() |
1001 | OMV.Vector3 applyImpulse = impulse; | ||
1002 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | ||
1003 | { | 669 | { |
1004 | DetailLog("{0},BSPrim.ApplyTorqueImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | 670 | BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1005 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||
1006 | }); | 671 | }); |
1007 | } | 672 | } |
1008 | 673 | public override bool SubscribedEvents() { | |
1009 | public override void SetMomentum(OMV.Vector3 momentum) { | 674 | return (_subscribedEventsMs > 0); |
1010 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | ||
1011 | } | 675 | } |
676 | |||
1012 | #region Mass Calculation | 677 | #region Mass Calculation |
1013 | 678 | ||
1014 | private float CalculateMass() | 679 | private float CalculateMass() |
@@ -1017,19 +682,19 @@ public sealed class BSPrim : BSPhysObject | |||
1017 | float tmp; | 682 | float tmp; |
1018 | 683 | ||
1019 | float returnMass = 0; | 684 | float returnMass = 0; |
1020 | float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; | 685 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; |
1021 | float hollowVolume = hollowAmount * hollowAmount; | 686 | float hollowVolume = hollowAmount * hollowAmount; |
1022 | 687 | ||
1023 | switch (BaseShape.ProfileShape) | 688 | switch (_pbs.ProfileShape) |
1024 | { | 689 | { |
1025 | case ProfileShape.Square: | 690 | case ProfileShape.Square: |
1026 | // default box | 691 | // default box |
1027 | 692 | ||
1028 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | 693 | if (_pbs.PathCurve == (byte)Extrusion.Straight) |
1029 | { | 694 | { |
1030 | if (hollowAmount > 0.0) | 695 | if (hollowAmount > 0.0) |
1031 | { | 696 | { |
1032 | switch (BaseShape.HollowShape) | 697 | switch (_pbs.HollowShape) |
1033 | { | 698 | { |
1034 | case HollowShape.Square: | 699 | case HollowShape.Square: |
1035 | case HollowShape.Same: | 700 | case HollowShape.Same: |
@@ -1053,19 +718,19 @@ public sealed class BSPrim : BSPhysObject | |||
1053 | } | 718 | } |
1054 | } | 719 | } |
1055 | 720 | ||
1056 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | 721 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) |
1057 | { | 722 | { |
1058 | //a tube | 723 | //a tube |
1059 | 724 | ||
1060 | volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); | 725 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); |
1061 | tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); | 726 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); |
1062 | volume -= volume*tmp*tmp; | 727 | volume -= volume*tmp*tmp; |
1063 | 728 | ||
1064 | if (hollowAmount > 0.0) | 729 | if (hollowAmount > 0.0) |
1065 | { | 730 | { |
1066 | hollowVolume *= hollowAmount; | 731 | hollowVolume *= hollowAmount; |
1067 | 732 | ||
1068 | switch (BaseShape.HollowShape) | 733 | switch (_pbs.HollowShape) |
1069 | { | 734 | { |
1070 | case HollowShape.Square: | 735 | case HollowShape.Square: |
1071 | case HollowShape.Same: | 736 | case HollowShape.Same: |
@@ -1090,13 +755,13 @@ public sealed class BSPrim : BSPhysObject | |||
1090 | 755 | ||
1091 | case ProfileShape.Circle: | 756 | case ProfileShape.Circle: |
1092 | 757 | ||
1093 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | 758 | if (_pbs.PathCurve == (byte)Extrusion.Straight) |
1094 | { | 759 | { |
1095 | volume *= 0.78539816339f; // elipse base | 760 | volume *= 0.78539816339f; // elipse base |
1096 | 761 | ||
1097 | if (hollowAmount > 0.0) | 762 | if (hollowAmount > 0.0) |
1098 | { | 763 | { |
1099 | switch (BaseShape.HollowShape) | 764 | switch (_pbs.HollowShape) |
1100 | { | 765 | { |
1101 | case HollowShape.Same: | 766 | case HollowShape.Same: |
1102 | case HollowShape.Circle: | 767 | case HollowShape.Circle: |
@@ -1118,19 +783,19 @@ public sealed class BSPrim : BSPhysObject | |||
1118 | } | 783 | } |
1119 | } | 784 | } |
1120 | 785 | ||
1121 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | 786 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) |
1122 | { | 787 | { |
1123 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); | 788 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); |
1124 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); | 789 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); |
1125 | volume *= (1.0f - tmp * tmp); | 790 | volume *= (1.0f - tmp * tmp); |
1126 | 791 | ||
1127 | if (hollowAmount > 0.0) | 792 | if (hollowAmount > 0.0) |
1128 | { | 793 | { |
1129 | 794 | ||
1130 | // calculate the hollow volume by it's shape compared to the prim shape | 795 | // calculate the hollow volume by it's shape compared to the prim shape |
1131 | hollowVolume *= hollowAmount; | 796 | hollowVolume *= hollowAmount; |
1132 | 797 | ||
1133 | switch (BaseShape.HollowShape) | 798 | switch (_pbs.HollowShape) |
1134 | { | 799 | { |
1135 | case HollowShape.Same: | 800 | case HollowShape.Same: |
1136 | case HollowShape.Circle: | 801 | case HollowShape.Circle: |
@@ -1154,7 +819,7 @@ public sealed class BSPrim : BSPhysObject | |||
1154 | break; | 819 | break; |
1155 | 820 | ||
1156 | case ProfileShape.HalfCircle: | 821 | case ProfileShape.HalfCircle: |
1157 | if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | 822 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) |
1158 | { | 823 | { |
1159 | volume *= 0.52359877559829887307710723054658f; | 824 | volume *= 0.52359877559829887307710723054658f; |
1160 | } | 825 | } |
@@ -1162,7 +827,7 @@ public sealed class BSPrim : BSPhysObject | |||
1162 | 827 | ||
1163 | case ProfileShape.EquilateralTriangle: | 828 | case ProfileShape.EquilateralTriangle: |
1164 | 829 | ||
1165 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | 830 | if (_pbs.PathCurve == (byte)Extrusion.Straight) |
1166 | { | 831 | { |
1167 | volume *= 0.32475953f; | 832 | volume *= 0.32475953f; |
1168 | 833 | ||
@@ -1170,7 +835,7 @@ public sealed class BSPrim : BSPhysObject | |||
1170 | { | 835 | { |
1171 | 836 | ||
1172 | // calculate the hollow volume by it's shape compared to the prim shape | 837 | // calculate the hollow volume by it's shape compared to the prim shape |
1173 | switch (BaseShape.HollowShape) | 838 | switch (_pbs.HollowShape) |
1174 | { | 839 | { |
1175 | case HollowShape.Same: | 840 | case HollowShape.Same: |
1176 | case HollowShape.Triangle: | 841 | case HollowShape.Triangle: |
@@ -1195,11 +860,11 @@ public sealed class BSPrim : BSPhysObject | |||
1195 | volume *= (1.0f - hollowVolume); | 860 | volume *= (1.0f - hollowVolume); |
1196 | } | 861 | } |
1197 | } | 862 | } |
1198 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | 863 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) |
1199 | { | 864 | { |
1200 | volume *= 0.32475953f; | 865 | volume *= 0.32475953f; |
1201 | volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); | 866 | volume *= 0.01f * (float)(200 - _pbs.PathScaleX); |
1202 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); | 867 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); |
1203 | volume *= (1.0f - tmp * tmp); | 868 | volume *= (1.0f - tmp * tmp); |
1204 | 869 | ||
1205 | if (hollowAmount > 0.0) | 870 | if (hollowAmount > 0.0) |
@@ -1207,7 +872,7 @@ public sealed class BSPrim : BSPhysObject | |||
1207 | 872 | ||
1208 | hollowVolume *= hollowAmount; | 873 | hollowVolume *= hollowAmount; |
1209 | 874 | ||
1210 | switch (BaseShape.HollowShape) | 875 | switch (_pbs.HollowShape) |
1211 | { | 876 | { |
1212 | case HollowShape.Same: | 877 | case HollowShape.Same: |
1213 | case HollowShape.Triangle: | 878 | case HollowShape.Triangle: |
@@ -1247,26 +912,26 @@ public sealed class BSPrim : BSPhysObject | |||
1247 | float profileBegin; | 912 | float profileBegin; |
1248 | float profileEnd; | 913 | float profileEnd; |
1249 | 914 | ||
1250 | if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) | 915 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) |
1251 | { | 916 | { |
1252 | taperX1 = BaseShape.PathScaleX * 0.01f; | 917 | taperX1 = _pbs.PathScaleX * 0.01f; |
1253 | if (taperX1 > 1.0f) | 918 | if (taperX1 > 1.0f) |
1254 | taperX1 = 2.0f - taperX1; | 919 | taperX1 = 2.0f - taperX1; |
1255 | taperX = 1.0f - taperX1; | 920 | taperX = 1.0f - taperX1; |
1256 | 921 | ||
1257 | taperY1 = BaseShape.PathScaleY * 0.01f; | 922 | taperY1 = _pbs.PathScaleY * 0.01f; |
1258 | if (taperY1 > 1.0f) | 923 | if (taperY1 > 1.0f) |
1259 | taperY1 = 2.0f - taperY1; | 924 | taperY1 = 2.0f - taperY1; |
1260 | taperY = 1.0f - taperY1; | 925 | taperY = 1.0f - taperY1; |
1261 | } | 926 | } |
1262 | else | 927 | else |
1263 | { | 928 | { |
1264 | taperX = BaseShape.PathTaperX * 0.01f; | 929 | taperX = _pbs.PathTaperX * 0.01f; |
1265 | if (taperX < 0.0f) | 930 | if (taperX < 0.0f) |
1266 | taperX = -taperX; | 931 | taperX = -taperX; |
1267 | taperX1 = 1.0f - taperX; | 932 | taperX1 = 1.0f - taperX; |
1268 | 933 | ||
1269 | taperY = BaseShape.PathTaperY * 0.01f; | 934 | taperY = _pbs.PathTaperY * 0.01f; |
1270 | if (taperY < 0.0f) | 935 | if (taperY < 0.0f) |
1271 | taperY = -taperY; | 936 | taperY = -taperY; |
1272 | taperY1 = 1.0f - taperY; | 937 | taperY1 = 1.0f - taperY; |
@@ -1276,18 +941,20 @@ public sealed class BSPrim : BSPhysObject | |||
1276 | 941 | ||
1277 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | 942 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); |
1278 | 943 | ||
1279 | pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; | 944 | pathBegin = (float)_pbs.PathBegin * 2.0e-5f; |
1280 | pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; | 945 | pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; |
1281 | volume *= (pathEnd - pathBegin); | 946 | volume *= (pathEnd - pathBegin); |
1282 | 947 | ||
1283 | // this is crude aproximation | 948 | // this is crude aproximation |
1284 | profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; | 949 | profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; |
1285 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; | 950 | profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; |
1286 | volume *= (profileEnd - profileBegin); | 951 | volume *= (profileEnd - profileBegin); |
1287 | 952 | ||
1288 | returnMass = _density * volume; | 953 | returnMass = _density * volume; |
1289 | 954 | ||
1290 | /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. | 955 | /* |
956 | * This change means each object keeps its own mass and the Mass property | ||
957 | * will return the sum if we're part of a linkset. | ||
1291 | if (IsRootOfLinkset) | 958 | if (IsRootOfLinkset) |
1292 | { | 959 | { |
1293 | foreach (BSPrim prim in _childrenPrims) | 960 | foreach (BSPrim prim in _childrenPrims) |
@@ -1300,42 +967,296 @@ public sealed class BSPrim : BSPhysObject | |||
1300 | if (returnMass <= 0) | 967 | if (returnMass <= 0) |
1301 | returnMass = 0.0001f; | 968 | returnMass = 0.0001f; |
1302 | 969 | ||
1303 | if (returnMass > PhysicsScene.MaximumObjectMass) | 970 | if (returnMass > _scene.MaximumObjectMass) |
1304 | returnMass = PhysicsScene.MaximumObjectMass; | 971 | returnMass = _scene.MaximumObjectMass; |
1305 | 972 | ||
1306 | return returnMass; | 973 | return returnMass; |
1307 | }// end CalculateMass | 974 | }// end CalculateMass |
1308 | #endregion Mass Calculation | 975 | #endregion Mass Calculation |
1309 | 976 | ||
1310 | // Rebuild the geometry and object. | 977 | // Create the geometry information in Bullet for later use |
1311 | // This is called when the shape changes so we need to recreate the mesh/hull. | 978 | // The objects needs a hull if it's physical otherwise a mesh is enough |
1312 | // Called at taint-time!!! | 979 | // No locking here because this is done when we know physics is not simulating |
1313 | private void CreateGeomAndObject(bool forceRebuild) | 980 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used |
981 | // Returns 'true' if the geometry was rebuilt | ||
982 | private bool CreateGeom(bool forceRebuild) | ||
1314 | { | 983 | { |
1315 | // If this prim is part of a linkset, we must remove and restore the physical | 984 | // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. |
1316 | // links if the body is rebuilt. | 985 | bool ret = false; |
1317 | bool needToRestoreLinkset = false; | 986 | if (!_scene.NeedsMeshing(_pbs)) |
1318 | |||
1319 | // Create the correct physical representation for this type of object. | ||
1320 | // Updates BSBody and BSShape with the new information. | ||
1321 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | ||
1322 | // Returns 'true' if either the body or the shape was changed. | ||
1323 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | ||
1324 | { | 987 | { |
1325 | // Called if the current prim body is about to be destroyed. | 988 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) |
1326 | // Remove all the physical dependencies on the old body. | 989 | { |
1327 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | 990 | // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) |
1328 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 991 | // { |
1329 | }); | 992 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); |
993 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) | ||
994 | { | ||
995 | // DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild); | ||
996 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | ||
997 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
998 | _scale = _size; | ||
999 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
1000 | ret = true; | ||
1001 | } | ||
1002 | // } | ||
1003 | } | ||
1004 | else | ||
1005 | { | ||
1006 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size); | ||
1007 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)) | ||
1008 | { | ||
1009 | // DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild); | ||
1010 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | ||
1011 | _scale = _size; | ||
1012 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
1013 | ret = true; | ||
1014 | } | ||
1015 | } | ||
1016 | } | ||
1017 | else | ||
1018 | { | ||
1019 | if (IsPhysical) | ||
1020 | { | ||
1021 | if (forceRebuild || _hullKey == 0) | ||
1022 | { | ||
1023 | // physical objects require a hull for interaction. | ||
1024 | // This will create the mesh if it doesn't already exist | ||
1025 | CreateGeomHull(); | ||
1026 | ret = true; | ||
1027 | } | ||
1028 | } | ||
1029 | else | ||
1030 | { | ||
1031 | if (forceRebuild || _meshKey == 0) | ||
1032 | { | ||
1033 | // Static (non-physical) objects only need a mesh for bumping into | ||
1034 | CreateGeomMesh(); | ||
1035 | ret = true; | ||
1036 | } | ||
1037 | } | ||
1038 | } | ||
1039 | return ret; | ||
1040 | } | ||
1041 | |||
1042 | // No locking here because this is done when we know physics is not simulating | ||
1043 | private void CreateGeomMesh() | ||
1044 | { | ||
1045 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | ||
1046 | ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
1047 | // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey); | ||
1048 | |||
1049 | // if this new shape is the same as last time, don't recreate the mesh | ||
1050 | if (_meshKey == newMeshKey) return; | ||
1051 | |||
1052 | // DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey); | ||
1053 | // Since we're recreating new, get rid of any previously generated shape | ||
1054 | if (_meshKey != 0) | ||
1055 | { | ||
1056 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); | ||
1057 | // DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey); | ||
1058 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | ||
1059 | _mesh = null; | ||
1060 | _meshKey = 0; | ||
1061 | } | ||
1062 | |||
1063 | _meshKey = newMeshKey; | ||
1064 | // always pass false for physicalness as this creates some sort of bounding box which we don't need | ||
1065 | _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false); | ||
1066 | |||
1067 | int[] indices = _mesh.getIndexListAsInt(); | ||
1068 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1069 | |||
1070 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
1071 | int vi = 0; | ||
1072 | foreach (OMV.Vector3 vv in vertices) | ||
1073 | { | ||
1074 | verticesAsFloats[vi++] = vv.X; | ||
1075 | verticesAsFloats[vi++] = vv.Y; | ||
1076 | verticesAsFloats[vi++] = vv.Z; | ||
1077 | } | ||
1078 | |||
1079 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
1080 | // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); | ||
1081 | BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, | ||
1082 | vertices.Count, verticesAsFloats); | ||
1083 | |||
1084 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; | ||
1085 | // meshes are already scaled by the meshmerizer | ||
1086 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1087 | // DetailLog("{0},BSPrim.CreateGeomMesh,done", LocalID); | ||
1088 | return; | ||
1089 | } | ||
1090 | |||
1091 | // No locking here because this is done when we know physics is not simulating | ||
1092 | private void CreateGeomHull() | ||
1093 | { | ||
1094 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | ||
1095 | ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
1096 | // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey); | ||
1097 | |||
1098 | // if the hull hasn't changed, don't rebuild it | ||
1099 | if (newHullKey == _hullKey) return; | ||
1330 | 1100 | ||
1331 | if (needToRestoreLinkset) | 1101 | // DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey); |
1102 | |||
1103 | // Since we're recreating new, get rid of any previously generated shape | ||
1104 | if (_hullKey != 0) | ||
1332 | { | 1105 | { |
1333 | // If physical body dependencies were removed, restore them | 1106 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); |
1334 | Linkset.RestoreBodyDependencies(this); | 1107 | // DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey); |
1108 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); | ||
1109 | _hullKey = 0; | ||
1110 | } | ||
1111 | |||
1112 | _hullKey = newHullKey; | ||
1113 | |||
1114 | // Make sure the underlying mesh exists and is correct | ||
1115 | CreateGeomMesh(); | ||
1116 | |||
1117 | int[] indices = _mesh.getIndexListAsInt(); | ||
1118 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1119 | |||
1120 | //format conversion from IMesh format to DecompDesc format | ||
1121 | List<int> convIndices = new List<int>(); | ||
1122 | List<float3> convVertices = new List<float3>(); | ||
1123 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
1124 | { | ||
1125 | convIndices.Add(indices[ii]); | ||
1126 | } | ||
1127 | foreach (OMV.Vector3 vv in vertices) | ||
1128 | { | ||
1129 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
1130 | } | ||
1131 | |||
1132 | // setup and do convex hull conversion | ||
1133 | _hulls = new List<ConvexResult>(); | ||
1134 | DecompDesc dcomp = new DecompDesc(); | ||
1135 | dcomp.mIndices = convIndices; | ||
1136 | dcomp.mVertices = convVertices; | ||
1137 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
1138 | // create the hull into the _hulls variable | ||
1139 | convexBuilder.process(dcomp); | ||
1140 | |||
1141 | // Convert the vertices and indices for passing to unmanaged. | ||
1142 | // The hull information is passed as a large floating point array. | ||
1143 | // The format is: | ||
1144 | // convHulls[0] = number of hulls | ||
1145 | // convHulls[1] = number of vertices in first hull | ||
1146 | // convHulls[2] = hull centroid X coordinate | ||
1147 | // convHulls[3] = hull centroid Y coordinate | ||
1148 | // convHulls[4] = hull centroid Z coordinate | ||
1149 | // convHulls[5] = first hull vertex X | ||
1150 | // convHulls[6] = first hull vertex Y | ||
1151 | // convHulls[7] = first hull vertex Z | ||
1152 | // convHulls[8] = second hull vertex X | ||
1153 | // ... | ||
1154 | // convHulls[n] = number of vertices in second hull | ||
1155 | // convHulls[n+1] = second hull centroid X coordinate | ||
1156 | // ... | ||
1157 | // | ||
1158 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
1159 | // data structures that do not need to be converted in order to pass to Bullet. | ||
1160 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
1161 | int hullCount = _hulls.Count; | ||
1162 | int totalVertices = 1; // include one for the count of the hulls | ||
1163 | foreach (ConvexResult cr in _hulls) | ||
1164 | { | ||
1165 | totalVertices += 4; // add four for the vertex count and centroid | ||
1166 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
1167 | } | ||
1168 | float[] convHulls = new float[totalVertices]; | ||
1169 | |||
1170 | convHulls[0] = (float)hullCount; | ||
1171 | int jj = 1; | ||
1172 | foreach (ConvexResult cr in _hulls) | ||
1173 | { | ||
1174 | // copy vertices for index access | ||
1175 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
1176 | int kk = 0; | ||
1177 | foreach (float3 ff in cr.HullVertices) | ||
1178 | { | ||
1179 | verts[kk++] = ff; | ||
1180 | } | ||
1181 | |||
1182 | // add to the array one hull's worth of data | ||
1183 | convHulls[jj++] = cr.HullIndices.Count; | ||
1184 | convHulls[jj++] = 0f; // centroid x,y,z | ||
1185 | convHulls[jj++] = 0f; | ||
1186 | convHulls[jj++] = 0f; | ||
1187 | foreach (int ind in cr.HullIndices) | ||
1188 | { | ||
1189 | convHulls[jj++] = verts[ind].x; | ||
1190 | convHulls[jj++] = verts[ind].y; | ||
1191 | convHulls[jj++] = verts[ind].z; | ||
1192 | } | ||
1335 | } | 1193 | } |
1336 | 1194 | ||
1337 | // Make sure the properties are set on the new object | 1195 | // create the hull definition in Bullet |
1338 | UpdatePhysicalParameters(); | 1196 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); |
1197 | BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); | ||
1198 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; | ||
1199 | // meshes are already scaled by the meshmerizer | ||
1200 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1201 | // DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID); | ||
1202 | return; | ||
1203 | } | ||
1204 | |||
1205 | // Callback from convex hull creater with a newly created hull. | ||
1206 | // Just add it to the collection of hulls for this shape. | ||
1207 | private void HullReturn(ConvexResult result) | ||
1208 | { | ||
1209 | _hulls.Add(result); | ||
1210 | return; | ||
1211 | } | ||
1212 | |||
1213 | // Create an object in Bullet if it has not already been created | ||
1214 | // No locking here because this is done when the physics engine is not simulating | ||
1215 | // Returns 'true' if an object was actually created. | ||
1216 | private bool CreateObject() | ||
1217 | { | ||
1218 | // this routine is called when objects are rebuilt. | ||
1219 | |||
1220 | // the mesh or hull must have already been created in Bullet | ||
1221 | ShapeData shape; | ||
1222 | FillShapeInfo(out shape); | ||
1223 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); | ||
1224 | bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape); | ||
1225 | |||
1226 | // the CreateObject() may have recreated the rigid body. Make sure we have the latest. | ||
1227 | Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
1228 | |||
1229 | return ret; | ||
1230 | } | ||
1231 | |||
1232 | // Copy prim's info into the BulletSim shape description structure | ||
1233 | public void FillShapeInfo(out ShapeData shape) | ||
1234 | { | ||
1235 | shape.ID = _localID; | ||
1236 | shape.Type = _shapeType; | ||
1237 | shape.Position = _position; | ||
1238 | shape.Rotation = _orientation; | ||
1239 | shape.Velocity = _velocity; | ||
1240 | shape.Scale = _scale; | ||
1241 | shape.Mass = _isPhysical ? _mass : 0f; | ||
1242 | shape.Buoyancy = _buoyancy; | ||
1243 | shape.HullKey = _hullKey; | ||
1244 | shape.MeshKey = _meshKey; | ||
1245 | shape.Friction = _friction; | ||
1246 | shape.Restitution = _restitution; | ||
1247 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; | ||
1248 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | // Rebuild the geometry and object. | ||
1253 | // This is called when the shape changes so we need to recreate the mesh/hull. | ||
1254 | // No locking here because this is done when the physics engine is not simulating | ||
1255 | private void RecreateGeomAndObject() | ||
1256 | { | ||
1257 | // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); | ||
1258 | if (CreateGeom(true)) | ||
1259 | CreateObject(); | ||
1339 | return; | 1260 | return; |
1340 | } | 1261 | } |
1341 | 1262 | ||
@@ -1356,7 +1277,7 @@ public sealed class BSPrim : BSPhysObject | |||
1356 | const float ACCELERATION_TOLERANCE = 0.01f; | 1277 | const float ACCELERATION_TOLERANCE = 0.01f; |
1357 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | 1278 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; |
1358 | 1279 | ||
1359 | public override void UpdateProperties(EntityProperties entprop) | 1280 | public void UpdateProperties(EntityProperties entprop) |
1360 | { | 1281 | { |
1361 | /* | 1282 | /* |
1362 | UpdatedProperties changed = 0; | 1283 | UpdatedProperties changed = 0; |
@@ -1404,7 +1325,7 @@ public sealed class BSPrim : BSPhysObject | |||
1404 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | 1325 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. |
1405 | 1326 | ||
1406 | // Updates only for individual prims and for the root object of a linkset. | 1327 | // Updates only for individual prims and for the root object of a linkset. |
1407 | if (Linkset.IsRoot(this)) | 1328 | if (_linkset.IsRoot(this)) |
1408 | { | 1329 | { |
1409 | // Assign to the local variables so the normal set action does not happen | 1330 | // Assign to the local variables so the normal set action does not happen |
1410 | _position = entprop.Position; | 1331 | _position = entprop.Position; |
@@ -1413,32 +1334,69 @@ public sealed class BSPrim : BSPhysObject | |||
1413 | _acceleration = entprop.Acceleration; | 1334 | _acceleration = entprop.Acceleration; |
1414 | _rotationalVelocity = entprop.RotationalVelocity; | 1335 | _rotationalVelocity = entprop.RotationalVelocity; |
1415 | 1336 | ||
1416 | // remember the current and last set values | 1337 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", |
1417 | LastEntityProperties = CurrentEntityProperties; | 1338 | // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); |
1418 | CurrentEntityProperties = entprop; | 1339 | // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
1419 | 1340 | // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | |
1420 | PositionSanityCheck(true); | ||
1421 | |||
1422 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | ||
1423 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | ||
1424 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | ||
1425 | |||
1426 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | ||
1427 | 1341 | ||
1428 | base.RequestPhysicsterseUpdate(); | 1342 | base.RequestPhysicsterseUpdate(); |
1429 | } | 1343 | } |
1430 | /* | 1344 | /* |
1431 | else | 1345 | else |
1432 | { | 1346 | { |
1433 | // For debugging, report the movement of children | 1347 | // For debugging, we also report the movement of children |
1434 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1348 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
1435 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | 1349 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, |
1436 | entprop.Acceleration, entprop.RotationalVelocity); | 1350 | entprop.Acceleration, entprop.RotationalVelocity); |
1437 | } | 1351 | } |
1438 | */ | 1352 | */ |
1353 | } | ||
1354 | |||
1355 | // I've collided with something | ||
1356 | CollisionEventUpdate collisionCollection; | ||
1357 | public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
1358 | { | ||
1359 | // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); | ||
1360 | |||
1361 | // The following lines make IsColliding() and IsCollidingGround() work | ||
1362 | _collidingStep = _scene.SimulationStep; | ||
1363 | if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) | ||
1364 | { | ||
1365 | _collidingGroundStep = _scene.SimulationStep; | ||
1366 | } | ||
1367 | |||
1368 | // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith); | ||
1369 | |||
1370 | // if someone is subscribed to collision events.... | ||
1371 | if (_subscribedEventsMs != 0) { | ||
1372 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
1373 | int nowTime = _scene.SimulationNowTime; | ||
1374 | if (nowTime >= _nextCollisionOkTime) { | ||
1375 | _nextCollisionOkTime = nowTime + _subscribedEventsMs; | ||
1439 | 1376 | ||
1440 | // The linkset implimentation might want to know about this. | 1377 | if (collisionCollection == null) |
1441 | Linkset.UpdateProperties(this); | 1378 | collisionCollection = new CollisionEventUpdate(); |
1379 | collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
1380 | } | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | // The scene is telling us it's time to pass our collected collisions into the simulator | ||
1385 | public void SendCollisions() | ||
1386 | { | ||
1387 | if (collisionCollection != null && collisionCollection.Count > 0) | ||
1388 | { | ||
1389 | base.SendCollisionUpdate(collisionCollection); | ||
1390 | // The collisionCollection structure is passed around in the simulator. | ||
1391 | // Make sure we don't have a handle to that one and that a new one is used next time. | ||
1392 | collisionCollection = null; | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | // Invoke the detailed logger and output something if it's enabled. | ||
1397 | private void DetailLog(string msg, params Object[] args) | ||
1398 | { | ||
1399 | Scene.PhysicsLogging.Write(msg, args); | ||
1442 | } | 1400 | } |
1443 | } | 1401 | } |
1444 | } | 1402 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 740f339..a31c578 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,88 +39,96 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Test sculpties (verified that they don't work) | 42 | // Debug linkset |
43 | // Test with multiple regions in one simulator | ||
44 | // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) | ||
45 | // Test sculpties | ||
43 | // Compute physics FPS reasonably | 46 | // Compute physics FPS reasonably |
44 | // Based on material, set density and friction | 47 | // Based on material, set density and friction |
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | 48 | // More efficient memory usage when passing hull information from BSPrim to BulletSim |
49 | // Move all logic out of the C++ code and into the C# code for easier future modifications. | ||
46 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | 50 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? |
47 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | 51 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) |
48 | // At the moment, physical and phantom causes object to drop through the terrain | 52 | // At the moment, physical and phantom causes object to drop through the terrain |
49 | // Physical phantom objects and related typing (collision options ) | 53 | // Physical phantom objects and related typing (collision options ) |
54 | // Use collision masks for collision with terrain and phantom objects | ||
50 | // Check out llVolumeDetect. Must do something for that. | 55 | // Check out llVolumeDetect. Must do something for that. |
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
53 | // Should prim.link() and prim.delink() membership checking happen at taint time? | 56 | // Should prim.link() and prim.delink() membership checking happen at taint time? |
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | 57 | // changing the position and orientation of a linked prim must rebuild the constraint with the root. |
58 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once | ||
55 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | 59 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect |
60 | // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) | ||
56 | // Implement LockAngularMotion | 61 | // Implement LockAngularMotion |
57 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | 62 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) |
63 | // Does NeedsMeshing() really need to exclude all the different shapes? | ||
58 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | 64 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. |
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | 65 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? |
60 | // Check terrain size. 128 or 127? | 66 | // Check terrain size. 128 or 127? |
61 | // Raycast | 67 | // Raycast |
62 | // | 68 | // |
63 | namespace OpenSim.Region.Physics.BulletSPlugin | 69 | namespace OpenSim.Region.Physics.BulletSPlugin |
64 | { | 70 | { |
65 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | 71 | public class BSScene : PhysicsScene, IPhysicsParameters |
66 | { | 72 | { |
67 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 73 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
68 | private static readonly string LogHeader = "[BULLETS SCENE]"; | 74 | private static readonly string LogHeader = "[BULLETS SCENE]"; |
69 | 75 | ||
70 | // The name of the region we're working for. | 76 | public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } |
71 | public string RegionName { get; private set; } | ||
72 | 77 | ||
73 | public string BulletSimVersion = "?"; | 78 | public string BulletSimVersion = "?"; |
74 | 79 | ||
75 | public Dictionary<uint, BSPhysObject> PhysObjects; | 80 | private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); |
76 | public BSShapeCollection Shapes; | 81 | private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); |
77 | 82 | private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); | |
78 | // Keeping track of the objects with collisions so we can report begin and end of a collision | 83 | private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>(); |
79 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | 84 | private List<BSPrim> m_vehicles = new List<BSPrim>(); |
80 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | 85 | private float[] m_heightMap; |
81 | // Keep track of all the avatars so we can send them a collision event | 86 | private float m_waterLevel; |
82 | // every tick so OpenSim will update its animation. | 87 | private uint m_worldID; |
83 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 88 | public uint WorldID { get { return m_worldID; } } |
84 | |||
85 | // List of all the objects that have vehicle properties and should be called | ||
86 | // to update each physics step. | ||
87 | private List<BSPhysObject> m_vehicles = new List<BSPhysObject>(); | ||
88 | 89 | ||
89 | // let my minuions use my logger | 90 | // let my minuions use my logger |
90 | public ILog Logger { get { return m_log; } } | 91 | public ILog Logger { get { return m_log; } } |
91 | 92 | ||
92 | public IMesher mesher; | 93 | private bool m_initialized = false; |
93 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
94 | public float MeshLOD { get; private set; } | ||
95 | public float MeshMegaPrimLOD { get; private set; } | ||
96 | public float MeshMegaPrimThreshold { get; private set; } | ||
97 | public float SculptLOD { get; private set; } | ||
98 | 94 | ||
99 | public uint WorldID { get; private set; } | 95 | private int m_detailedStatsStep = 0; |
100 | public BulletSim World { get; private set; } | 96 | |
97 | public IMesher mesher; | ||
98 | private float m_meshLOD; | ||
99 | public float MeshLOD | ||
100 | { | ||
101 | get { return m_meshLOD; } | ||
102 | } | ||
103 | private float m_sculptLOD; | ||
104 | public float SculptLOD | ||
105 | { | ||
106 | get { return m_sculptLOD; } | ||
107 | } | ||
101 | 108 | ||
102 | // All the constraints that have been allocated in this instance. | 109 | private BulletSim m_worldSim; |
103 | public BSConstraintCollection Constraints { get; private set; } | 110 | public BulletSim World |
111 | { | ||
112 | get { return m_worldSim; } | ||
113 | } | ||
114 | private BSConstraintCollection m_constraintCollection; | ||
115 | public BSConstraintCollection Constraints | ||
116 | { | ||
117 | get { return m_constraintCollection; } | ||
118 | } | ||
104 | 119 | ||
105 | // Simulation parameters | ||
106 | private int m_maxSubSteps; | 120 | private int m_maxSubSteps; |
107 | private float m_fixedTimeStep; | 121 | private float m_fixedTimeStep; |
108 | private long m_simulationStep = 0; | 122 | private long m_simulationStep = 0; |
109 | public long SimulationStep { get { return m_simulationStep; } } | 123 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | 124 | |
125 | public float LastSimulatedTimestep { get; private set; } | ||
111 | 126 | ||
112 | // A value of the time now so all the collision and update routines do not have to get their own | 127 | // A value of the time now so all the collision and update routines do not have to get their own |
113 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 128 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
114 | public int SimulationNowTime { get; private set; } | 129 | private int m_simulationNowTime; |
115 | 130 | public int SimulationNowTime { get { return m_simulationNowTime; } } | |
116 | // True if initialized and ready to do simulation steps | ||
117 | private bool m_initialized = false; | ||
118 | |||
119 | // Flag which is true when processing taints. | ||
120 | // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. | ||
121 | public bool InTaintTime { get; private set; } | ||
122 | 131 | ||
123 | // Pinned memory used to pass step information between managed and unmanaged | ||
124 | private int m_maxCollisionsPerFrame; | 132 | private int m_maxCollisionsPerFrame; |
125 | private CollisionDesc[] m_collisionArray; | 133 | private CollisionDesc[] m_collisionArray; |
126 | private GCHandle m_collisionArrayPinnedHandle; | 134 | private GCHandle m_collisionArrayPinnedHandle; |
@@ -129,19 +137,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
129 | private EntityProperties[] m_updateArray; | 137 | private EntityProperties[] m_updateArray; |
130 | private GCHandle m_updateArrayPinnedHandle; | 138 | private GCHandle m_updateArrayPinnedHandle; |
131 | 139 | ||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | 140 | private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed |
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 141 | private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes |
134 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
135 | 142 | ||
136 | public float PID_D { get; private set; } // derivative | 143 | public float PID_D { get; private set; } // derivative |
137 | public float PID_P { get; private set; } // proportional | 144 | public float PID_P { get; private set; } // proportional |
138 | 145 | ||
139 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | 146 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero |
140 | public const uint GROUNDPLANE_ID = 1; | 147 | public const uint GROUNDPLANE_ID = 1; |
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | ||
142 | |||
143 | private float m_waterLevel; | ||
144 | public BSTerrainManager TerrainManager { get; private set; } | ||
145 | 148 | ||
146 | public ConfigurationParameters Params | 149 | public ConfigurationParameters Params |
147 | { | 150 | { |
@@ -151,18 +154,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
151 | { | 154 | { |
152 | get { return new Vector3(0f, 0f, Params.gravity); } | 155 | get { return new Vector3(0f, 0f, Params.gravity); } |
153 | } | 156 | } |
154 | // Just the Z value of the gravity | 157 | |
155 | public float DefaultGravityZ | 158 | private float m_maximumObjectMass; |
159 | public float MaximumObjectMass | ||
156 | { | 160 | { |
157 | get { return Params.gravity; } | 161 | get { return m_maximumObjectMass; } |
158 | } | 162 | } |
159 | 163 | ||
160 | public float MaximumObjectMass { get; private set; } | ||
161 | |||
162 | // When functions in the unmanaged code must be called, it is only | ||
163 | // done at a known time just before the simulation step. The taint | ||
164 | // system saves all these function calls and executes them in | ||
165 | // order before the simulation. | ||
166 | public delegate void TaintCallback(); | 164 | public delegate void TaintCallback(); |
167 | private struct TaintCallbackEntry | 165 | private struct TaintCallbackEntry |
168 | { | 166 | { |
@@ -174,19 +172,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
174 | callback = c; | 172 | callback = c; |
175 | } | 173 | } |
176 | } | 174 | } |
177 | private Object _taintLock = new Object(); // lock for using the next object | 175 | private List<TaintCallbackEntry> _taintedObjects; |
178 | private List<TaintCallbackEntry> _taintOperations; | 176 | private Object _taintLock = new Object(); |
179 | private Dictionary<string, TaintCallbackEntry> _postTaintOperations; | ||
180 | private List<TaintCallbackEntry> _postStepOperations; | ||
181 | 177 | ||
182 | // A pointer to an instance if this structure is passed to the C++ code | 178 | // A pointer to an instance if this structure is passed to the C++ code |
183 | // Used to pass basic configuration values to the unmanaged code. | ||
184 | ConfigurationParameters[] m_params; | 179 | ConfigurationParameters[] m_params; |
185 | GCHandle m_paramsHandle; | 180 | GCHandle m_paramsHandle; |
186 | 181 | ||
187 | // Handle to the callback used by the unmanaged code to call into the managed code. | 182 | public bool ShouldDebugLog { get; private set; } |
188 | // Used for debug logging. | 183 | |
189 | // Need to store the handle in a persistant variable so it won't be freed. | ||
190 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | 184 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; |
191 | 185 | ||
192 | // Sometimes you just have to log everything. | 186 | // Sometimes you just have to log everything. |
@@ -195,26 +189,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 189 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 190 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 191 | private int m_physicsLoggingFileMinutes; |
198 | // 'true' of the vehicle code is to log lots of details | ||
199 | public bool VehicleLoggingEnabled { get; private set; } | ||
200 | 192 | ||
201 | #region Construction and Initialization | 193 | private bool m_vehicleLoggingEnabled; |
194 | public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } } | ||
195 | |||
202 | public BSScene(string identifier) | 196 | public BSScene(string identifier) |
203 | { | 197 | { |
204 | m_initialized = false; | 198 | m_initialized = false; |
205 | // we are passed the name of the region we're working for. | ||
206 | RegionName = identifier; | ||
207 | } | 199 | } |
208 | 200 | ||
209 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | 201 | public override void Initialise(IMesher meshmerizer, IConfigSource config) |
210 | { | 202 | { |
211 | mesher = meshmerizer; | ||
212 | _taintOperations = new List<TaintCallbackEntry>(); | ||
213 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
214 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
215 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | ||
216 | Shapes = new BSShapeCollection(this); | ||
217 | |||
218 | // Allocate pinned memory to pass parameters. | 203 | // Allocate pinned memory to pass parameters. |
219 | m_params = new ConfigurationParameters[1]; | 204 | m_params = new ConfigurationParameters[1]; |
220 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); | 205 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); |
@@ -230,7 +215,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
230 | 215 | ||
231 | // Enable very detailed logging. | 216 | // Enable very detailed logging. |
232 | // By creating an empty logger when not logging, the log message invocation code | 217 | // By creating an empty logger when not logging, the log message invocation code |
233 | // can be left in and every call doesn't have to check for null. | 218 | // can be left in and every call doesn't have to check for null. |
234 | if (m_physicsLoggingEnabled) | 219 | if (m_physicsLoggingEnabled) |
235 | { | 220 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 221 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
@@ -240,43 +225,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
240 | PhysicsLogging = new Logging.LogWriter(); | 225 | PhysicsLogging = new Logging.LogWriter(); |
241 | } | 226 | } |
242 | 227 | ||
243 | // If Debug logging level, enable logging from the unmanaged code | 228 | // Get the version of the DLL |
244 | m_DebugLogCallbackHandle = null; | 229 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. |
230 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
231 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
232 | |||
233 | // if Debug, enable logging from the unmanaged code | ||
245 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) | 234 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) |
246 | { | 235 | { |
247 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | 236 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); |
248 | if (PhysicsLogging.Enabled) | 237 | if (PhysicsLogging.Enabled) |
249 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
250 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); | 238 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); |
251 | else | 239 | else |
252 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | 240 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); |
241 | // the handle is saved in a variable to make sure it doesn't get freed after this call | ||
242 | BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); | ||
253 | } | 243 | } |
254 | 244 | ||
255 | // Get the version of the DLL | 245 | _taintedObjects = new List<TaintCallbackEntry>(); |
256 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
257 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
258 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
259 | 246 | ||
260 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 247 | mesher = meshmerizer; |
261 | // a child in a mega-region. | 248 | // The bounding box for the simulated world |
262 | // Bullet actually doesn't care about the extents of the simulated | 249 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); |
263 | // area. It tracks active objects no matter where they are. | ||
264 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
265 | 250 | ||
266 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 251 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); |
267 | World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | 252 | m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), |
268 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | 253 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), |
269 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | 254 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); |
270 | m_DebugLogCallbackHandle)); | ||
271 | |||
272 | Constraints = new BSConstraintCollection(World); | ||
273 | 255 | ||
274 | TerrainManager = new BSTerrainManager(this); | 256 | // Initialization to support the transition to a new API which puts most of the logic |
275 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 257 | // into the C# code so it is easier to modify and add to. |
258 | m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); | ||
259 | m_constraintCollection = new BSConstraintCollection(World); | ||
276 | 260 | ||
277 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); | ||
278 | |||
279 | InTaintTime = false; | ||
280 | m_initialized = true; | 261 | m_initialized = true; |
281 | } | 262 | } |
282 | 263 | ||
@@ -300,13 +281,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
300 | // Very detailed logging for physics debugging | 281 | // Very detailed logging for physics debugging |
301 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | 282 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 283 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 284 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 285 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
305 | // Very detailed logging for vehicle debugging | 286 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 287 | m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
307 | |||
308 | // Do any replacements in the parameters | ||
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | ||
310 | } | 288 | } |
311 | } | 289 | } |
312 | } | 290 | } |
@@ -331,50 +309,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
331 | { | 309 | { |
332 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | 310 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); |
333 | } | 311 | } |
334 | 312 | ||
335 | // Called directly from unmanaged code so don't do much | 313 | // Called directly from unmanaged code so don't do much |
336 | private void BulletLoggerPhysLog(string msg) | 314 | private void BulletLoggerPhysLog(string msg) |
337 | { | 315 | { |
338 | DetailLog("[BULLETS UNMANAGED]:" + msg); | 316 | PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); |
339 | } | ||
340 | |||
341 | public override void Dispose() | ||
342 | { | ||
343 | // m_log.DebugFormat("{0}: Dispose()", LogHeader); | ||
344 | |||
345 | // make sure no stepping happens while we're deleting stuff | ||
346 | m_initialized = false; | ||
347 | |||
348 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
349 | |||
350 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
351 | { | ||
352 | kvp.Value.Destroy(); | ||
353 | } | ||
354 | PhysObjects.Clear(); | ||
355 | |||
356 | // Now that the prims are all cleaned up, there should be no constraints left | ||
357 | if (Constraints != null) | ||
358 | { | ||
359 | Constraints.Dispose(); | ||
360 | Constraints = null; | ||
361 | } | ||
362 | |||
363 | if (Shapes != null) | ||
364 | { | ||
365 | Shapes.Dispose(); | ||
366 | Shapes = null; | ||
367 | } | ||
368 | |||
369 | // Anything left in the unmanaged code should be cleaned out | ||
370 | BulletSimAPI.Shutdown2(World.ptr); | ||
371 | |||
372 | // Not logging any more | ||
373 | PhysicsLogging.Close(); | ||
374 | } | 317 | } |
375 | #endregion // Construction and Initialization | ||
376 | |||
377 | #region Prim and Avatar addition and removal | ||
378 | 318 | ||
379 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) | 319 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) |
380 | { | 320 | { |
@@ -389,13 +329,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
389 | if (!m_initialized) return null; | 329 | if (!m_initialized) return null; |
390 | 330 | ||
391 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); | 331 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); |
392 | lock (PhysObjects) PhysObjects.Add(localID, actor); | 332 | lock (m_avatars) m_avatars.Add(localID, actor); |
393 | |||
394 | // TODO: Remove kludge someday. | ||
395 | // We must generate a collision for avatars whether they collide or not. | ||
396 | // This is required by OpenSim to update avatar animations, etc. | ||
397 | lock (m_avatars) m_avatars.Add(actor); | ||
398 | |||
399 | return actor; | 333 | return actor; |
400 | } | 334 | } |
401 | 335 | ||
@@ -410,9 +344,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
410 | { | 344 | { |
411 | try | 345 | try |
412 | { | 346 | { |
413 | lock (PhysObjects) PhysObjects.Remove(actor.LocalID); | 347 | lock (m_avatars) m_avatars.Remove(actor.LocalID); |
414 | // Remove kludge someday | ||
415 | lock (m_avatars) m_avatars.Remove(bsactor); | ||
416 | } | 348 | } |
417 | catch (Exception e) | 349 | catch (Exception e) |
418 | { | 350 | { |
@@ -430,11 +362,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
430 | BSPrim bsprim = prim as BSPrim; | 362 | BSPrim bsprim = prim as BSPrim; |
431 | if (bsprim != null) | 363 | if (bsprim != null) |
432 | { | 364 | { |
433 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); | 365 | // DetailLog("{0},RemovePrim,call", bsprim.LocalID); |
434 | // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); | 366 | // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); |
435 | try | 367 | try |
436 | { | 368 | { |
437 | lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); | 369 | lock (m_prims) m_prims.Remove(bsprim.LocalID); |
438 | } | 370 | } |
439 | catch (Exception e) | 371 | catch (Exception e) |
440 | { | 372 | { |
@@ -456,21 +388,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
456 | 388 | ||
457 | if (!m_initialized) return null; | 389 | if (!m_initialized) return null; |
458 | 390 | ||
459 | DetailLog("{0},AddPrimShape,call", localID); | 391 | // DetailLog("{0},AddPrimShape,call", localID); |
460 | 392 | ||
461 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); | 393 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); |
462 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 394 | lock (m_prims) m_prims.Add(localID, prim); |
463 | return prim; | 395 | return prim; |
464 | } | 396 | } |
465 | 397 | ||
466 | // This is a call from the simulator saying that some physical property has been updated. | 398 | // This is a call from the simulator saying that some physical property has been updated. |
467 | // The BulletSim driver senses the changing of relevant properties so this taint | 399 | // The BulletSim driver senses the changing of relevant properties so this taint |
468 | // information call is not needed. | 400 | // information call is not needed. |
469 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } | 401 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } |
470 | 402 | ||
471 | #endregion // Prim and Avatar addition and removal | ||
472 | |||
473 | #region Simulation | ||
474 | // Simulate one timestep | 403 | // Simulate one timestep |
475 | public override float Simulate(float timeStep) | 404 | public override float Simulate(float timeStep) |
476 | { | 405 | { |
@@ -479,45 +408,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
479 | int collidersCount = 0; | 408 | int collidersCount = 0; |
480 | IntPtr collidersPtr; | 409 | IntPtr collidersPtr; |
481 | 410 | ||
482 | int beforeTime = 0; | 411 | LastSimulatedTimestep = timeStep; |
483 | int simTime = 0; | ||
484 | 412 | ||
485 | // prevent simulation until we've been initialized | 413 | // prevent simulation until we've been initialized |
486 | if (!m_initialized) return 5.0f; | 414 | if (!m_initialized) return 10.0f; |
415 | |||
416 | int simulateStartTime = Util.EnvironmentTickCount(); | ||
487 | 417 | ||
488 | // update the prim states while we know the physics engine is not busy | 418 | // update the prim states while we know the physics engine is not busy |
489 | int numTaints = _taintOperations.Count; | ||
490 | ProcessTaints(); | 419 | ProcessTaints(); |
491 | 420 | ||
492 | // Some of the prims operate with special vehicle properties | 421 | // Some of the prims operate with special vehicle properties |
493 | ProcessVehicles(timeStep); | 422 | ProcessVehicles(timeStep); |
494 | numTaints += _taintOperations.Count; | ||
495 | ProcessTaints(); // the vehicles might have added taints | 423 | ProcessTaints(); // the vehicles might have added taints |
496 | 424 | ||
497 | // step the physical world one interval | 425 | // step the physical world one interval |
498 | m_simulationStep++; | 426 | m_simulationStep++; |
499 | int numSubSteps = 0; | 427 | int numSubSteps = 0; |
500 | |||
501 | try | 428 | try |
502 | { | 429 | { |
503 | // DumpVehicles(); // DEBUG | 430 | numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, |
504 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | ||
505 | |||
506 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | ||
507 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | 431 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); |
508 | 432 | // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); | |
509 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
510 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | ||
511 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | ||
512 | // DumpVehicles(); // DEBUG | ||
513 | } | 433 | } |
514 | catch (Exception e) | 434 | catch (Exception e) |
515 | { | 435 | { |
516 | m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", | 436 | m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); |
517 | LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); | 437 | // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); |
518 | DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", | 438 | // updatedEntityCount = 0; |
519 | DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); | ||
520 | updatedEntityCount = 0; | ||
521 | collidersCount = 0; | 439 | collidersCount = 0; |
522 | } | 440 | } |
523 | 441 | ||
@@ -525,7 +443,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
525 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 443 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in |
526 | 444 | ||
527 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 445 | // Get a value for 'now' so all the collision and update routines don't have to get their own |
528 | SimulationNowTime = Util.EnvironmentTickCount(); | 446 | m_simulationNowTime = Util.EnvironmentTickCount(); |
529 | 447 | ||
530 | // If there were collisions, process them by sending the event to the prim. | 448 | // If there were collisions, process them by sending the event to the prim. |
531 | // Collisions must be processed before updates. | 449 | // Collisions must be processed before updates. |
@@ -544,32 +462,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
544 | 462 | ||
545 | // The above SendCollision's batch up the collisions on the objects. | 463 | // The above SendCollision's batch up the collisions on the objects. |
546 | // Now push the collisions into the simulator. | 464 | // Now push the collisions into the simulator. |
547 | if (ObjectsWithCollisions.Count > 0) | 465 | foreach (BSPrim bsp in m_primsWithCollisions) |
548 | { | 466 | bsp.SendCollisions(); |
549 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | 467 | m_primsWithCollisions.Clear(); |
550 | if (!bsp.SendCollisions()) | 468 | |
551 | { | 469 | // This is a kludge to get avatar movement updated. |
552 | // If the object is done colliding, see that it's removed from the colliding list | 470 | // Don't send collisions only if there were collisions -- send everytime. |
553 | ObjectsWithNoMoreCollisions.Add(bsp); | 471 | // ODE sends collisions even if there are none and this is used to update |
554 | } | 472 | // avatar animations and stuff. |
555 | } | 473 | // foreach (BSCharacter bsc in m_avatarsWithCollisions) |
556 | 474 | // bsc.SendCollisions(); | |
557 | // This is a kludge to get avatar movement updates. | 475 | foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) |
558 | // The simulator expects collisions for avatars even if there are have been no collisions. | 476 | kvp.Value.SendCollisions(); |
559 | // The event updates avatar animations and stuff. | 477 | m_avatarsWithCollisions.Clear(); |
560 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
561 | foreach (BSPhysObject bsp in m_avatars) | ||
562 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
563 | bsp.SendCollisions(); | ||
564 | |||
565 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
566 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
567 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
568 | { | ||
569 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
570 | ObjectsWithCollisions.Remove(po); | ||
571 | ObjectsWithNoMoreCollisions.Clear(); | ||
572 | } | ||
573 | 478 | ||
574 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 479 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
575 | if (updatedEntityCount > 0) | 480 | if (updatedEntityCount > 0) |
@@ -577,310 +482,320 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
577 | for (int ii = 0; ii < updatedEntityCount; ii++) | 482 | for (int ii = 0; ii < updatedEntityCount; ii++) |
578 | { | 483 | { |
579 | EntityProperties entprop = m_updateArray[ii]; | 484 | EntityProperties entprop = m_updateArray[ii]; |
580 | BSPhysObject pobj; | 485 | BSPrim prim; |
581 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | 486 | if (m_prims.TryGetValue(entprop.ID, out prim)) |
487 | { | ||
488 | prim.UpdateProperties(entprop); | ||
489 | continue; | ||
490 | } | ||
491 | BSCharacter actor; | ||
492 | if (m_avatars.TryGetValue(entprop.ID, out actor)) | ||
582 | { | 493 | { |
583 | pobj.UpdateProperties(entprop); | 494 | actor.UpdateProperties(entprop); |
495 | continue; | ||
584 | } | 496 | } |
585 | } | 497 | } |
586 | } | 498 | } |
587 | 499 | ||
588 | ProcessPostStepTaints(); | 500 | // If enabled, call into the physics engine to dump statistics |
589 | 501 | if (m_detailedStatsStep > 0) | |
590 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 502 | { |
591 | // Only enable this in a limited test world with few objects. | 503 | if ((m_simulationStep % m_detailedStatsStep) == 0) |
592 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 504 | { |
505 | BulletSimAPI.DumpBulletStatistics(); | ||
506 | } | ||
507 | } | ||
593 | 508 | ||
594 | // The physics engine returns the number of milliseconds it simulated this call. | 509 | // this is a waste since the outside routine also calcuates the physics simulation |
595 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 510 | // period. TODO: There should be a way of computing physics frames from simulator computation. |
596 | // We multiply by 55 to give a recognizable running rate (55 or less). | 511 | // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); |
597 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 512 | // return (timeStep * (float)simulateTotalTime); |
598 | // return timeStep * 1000 * 55; | 513 | |
514 | // TODO: FIX THIS: fps calculation possibly wrong. | ||
515 | // This calculation says 1/timeStep is the ideal frame rate. Any time added to | ||
516 | // that by the physics simulation gives a slower frame rate. | ||
517 | long totalSimulationTime = Util.EnvironmentTickCountSubtract(simulateStartTime); | ||
518 | if (totalSimulationTime >= timeStep) | ||
519 | return 0; | ||
520 | return 1f / (timeStep + totalSimulationTime); | ||
599 | } | 521 | } |
600 | 522 | ||
601 | // Something has collided | 523 | // Something has collided |
602 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) | 524 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) |
603 | { | 525 | { |
604 | if (localID <= TerrainManager.HighestTerrainID) | 526 | if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) |
605 | { | 527 | { |
606 | return; // don't send collisions to the terrain | 528 | return; // don't send collisions to the terrain |
607 | } | 529 | } |
608 | 530 | ||
609 | BSPhysObject collider; | 531 | ActorTypes type = ActorTypes.Prim; |
610 | if (!PhysObjects.TryGetValue(localID, out collider)) | 532 | if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) |
611 | { | 533 | type = ActorTypes.Ground; |
612 | // If the object that is colliding cannot be found, just ignore the collision. | 534 | else if (m_avatars.ContainsKey(collidingWith)) |
613 | DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); | 535 | type = ActorTypes.Agent; |
536 | |||
537 | BSPrim prim; | ||
538 | if (m_prims.TryGetValue(localID, out prim)) { | ||
539 | prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration); | ||
540 | m_primsWithCollisions.Add(prim); | ||
614 | return; | 541 | return; |
615 | } | 542 | } |
616 | 543 | BSCharacter actor; | |
617 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 544 | if (m_avatars.TryGetValue(localID, out actor)) { |
618 | BSPhysObject collidee = null; | 545 | actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); |
619 | PhysObjects.TryGetValue(collidingWith, out collidee); | 546 | m_avatarsWithCollisions.Add(actor); |
620 | 547 | return; | |
621 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | ||
622 | |||
623 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | ||
624 | { | ||
625 | // If a collision was posted, remember to send it to the simulator | ||
626 | ObjectsWithCollisions.Add(collider); | ||
627 | } | 548 | } |
628 | |||
629 | return; | 549 | return; |
630 | } | 550 | } |
631 | 551 | ||
632 | #endregion // Simulation | ||
633 | |||
634 | public override void GetResults() { } | 552 | public override void GetResults() { } |
635 | 553 | ||
636 | #region Terrain | ||
637 | |||
638 | public override void SetTerrain(float[] heightMap) { | 554 | public override void SetTerrain(float[] heightMap) { |
639 | TerrainManager.SetTerrain(heightMap); | 555 | m_heightMap = heightMap; |
556 | this.TaintedObject("BSScene.SetTerrain", delegate() | ||
557 | { | ||
558 | BulletSimAPI.SetHeightmap(m_worldID, m_heightMap); | ||
559 | }); | ||
640 | } | 560 | } |
641 | 561 | ||
642 | public override void SetWaterLevel(float baseheight) | 562 | // Someday we will have complex terrain with caves and tunnels |
563 | // For the moment, it's flat and convex | ||
564 | public float GetTerrainHeightAtXYZ(Vector3 loc) | ||
643 | { | 565 | { |
644 | m_waterLevel = baseheight; | 566 | return GetTerrainHeightAtXY(loc.X, loc.Y); |
645 | } | ||
646 | // Someday.... | ||
647 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
648 | { | ||
649 | return m_waterLevel; | ||
650 | } | 567 | } |
651 | 568 | ||
652 | public override void DeleteTerrain() | 569 | public float GetTerrainHeightAtXY(float tX, float tY) |
653 | { | 570 | { |
654 | // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); | 571 | if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize) |
572 | return 30; | ||
573 | return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; | ||
655 | } | 574 | } |
656 | 575 | ||
657 | // Although no one seems to check this, I do support combining. | 576 | public override void SetWaterLevel(float baseheight) |
658 | public override bool SupportsCombining() | ||
659 | { | 577 | { |
660 | return TerrainManager.SupportsCombining(); | 578 | m_waterLevel = baseheight; |
579 | // TODO: pass to physics engine so things will float? | ||
661 | } | 580 | } |
662 | // This call says I am a child to region zero in a mega-region. 'pScene' is that | 581 | public float GetWaterLevel() |
663 | // of region zero, 'offset' is my offset from regions zero's origin, and | ||
664 | // 'extents' is the largest XY that is handled in my region. | ||
665 | public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
666 | { | 582 | { |
667 | TerrainManager.Combine(pScene, offset, extents); | 583 | return m_waterLevel; |
668 | } | 584 | } |
669 | 585 | ||
670 | // Unhook all the combining that I know about. | 586 | public override void DeleteTerrain() |
671 | public override void UnCombine(PhysicsScene pScene) | ||
672 | { | 587 | { |
673 | TerrainManager.UnCombine(pScene); | 588 | // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); |
674 | } | 589 | } |
675 | 590 | ||
676 | #endregion // Terrain | 591 | public override void Dispose() |
677 | |||
678 | public override Dictionary<uint, float> GetTopColliders() | ||
679 | { | 592 | { |
680 | return new Dictionary<uint, float>(); | 593 | // m_log.DebugFormat("{0}: Dispose()", LogHeader); |
681 | } | ||
682 | 594 | ||
683 | public override bool IsThreaded { get { return false; } } | 595 | // make sure no stepping happens while we're deleting stuff |
596 | m_initialized = false; | ||
684 | 597 | ||
685 | #region Taints | 598 | foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) |
599 | { | ||
600 | kvp.Value.Destroy(); | ||
601 | } | ||
602 | m_avatars.Clear(); | ||
686 | 603 | ||
687 | // Calls to the PhysicsActors can't directly call into the physics engine | 604 | foreach (KeyValuePair<uint, BSPrim> kvp in m_prims) |
688 | // because it might be busy. We delay changes to a known time. | 605 | { |
689 | // We rely on C#'s closure to save and restore the context for the delegate. | 606 | kvp.Value.Destroy(); |
690 | public void TaintedObject(String ident, TaintCallback callback) | 607 | } |
691 | { | 608 | m_prims.Clear(); |
692 | if (!m_initialized) return; | ||
693 | 609 | ||
694 | lock (_taintLock) | 610 | // Now that the prims are all cleaned up, there should be no constraints left |
611 | if (m_constraintCollection != null) | ||
695 | { | 612 | { |
696 | _taintOperations.Add(new TaintCallbackEntry(ident, callback)); | 613 | m_constraintCollection.Dispose(); |
614 | m_constraintCollection = null; | ||
697 | } | 615 | } |
698 | 616 | ||
699 | return; | 617 | // Anything left in the unmanaged code should be cleaned out |
700 | } | 618 | BulletSimAPI.Shutdown(WorldID); |
701 | 619 | ||
702 | // Sometimes a potentially tainted operation can be used in and out of taint time. | 620 | // Not logging any more |
703 | // This routine executes the command immediately if in taint-time otherwise it is queued. | 621 | PhysicsLogging.Close(); |
704 | public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) | ||
705 | { | ||
706 | if (inTaintTime) | ||
707 | callback(); | ||
708 | else | ||
709 | TaintedObject(ident, callback); | ||
710 | } | 622 | } |
711 | 623 | ||
712 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | 624 | public override Dictionary<uint, float> GetTopColliders() |
713 | // a callback into itself to do the actual property change. That callback is called | ||
714 | // here just before the physics engine is called to step the simulation. | ||
715 | public void ProcessTaints() | ||
716 | { | 625 | { |
717 | InTaintTime = true; | 626 | return new Dictionary<uint, float>(); |
718 | ProcessRegularTaints(); | ||
719 | ProcessPostTaintTaints(); | ||
720 | InTaintTime = false; | ||
721 | } | 627 | } |
722 | 628 | ||
723 | private void ProcessRegularTaints() | 629 | public override bool IsThreaded { get { return false; } } |
630 | |||
631 | /// <summary> | ||
632 | /// Routine to figure out if we need to mesh this prim with our mesher | ||
633 | /// </summary> | ||
634 | /// <param name="pbs"></param> | ||
635 | /// <returns>true if the prim needs meshing</returns> | ||
636 | public bool NeedsMeshing(PrimitiveBaseShape pbs) | ||
724 | { | 637 | { |
725 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | 638 | // most of this is redundant now as the mesher will return null if it cant mesh a prim |
639 | // but we still need to check for sculptie meshing being enabled so this is the most | ||
640 | // convenient place to do it for now... | ||
641 | |||
642 | // int iPropertiesNotSupportedDefault = 0; | ||
643 | |||
644 | if (pbs.SculptEntry && !_meshSculptedPrim) | ||
726 | { | 645 | { |
727 | int taintCount = m_taintsToProcessPerStep; | 646 | // Render sculpties as boxes |
728 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | 647 | return false; |
729 | while (_taintOperations.Count > 0 && taintCount-- > 0) | 648 | } |
649 | |||
650 | // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet | ||
651 | // can use an internal representation for the prim | ||
652 | if (!_forceSimplePrimMeshing) | ||
653 | { | ||
654 | if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
655 | || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 | ||
656 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) | ||
730 | { | 657 | { |
731 | bool gotOne = false; | 658 | |
732 | lock (_taintLock) | 659 | if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
733 | { | 660 | && pbs.ProfileHollow == 0 |
734 | if (_taintOperations.Count > 0) | 661 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 |
735 | { | 662 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 |
736 | oneCallback = _taintOperations[0]; | 663 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 |
737 | _taintOperations.RemoveAt(0); | 664 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
738 | gotOne = true; | 665 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) |
739 | } | ||
740 | } | ||
741 | if (gotOne) | ||
742 | { | 666 | { |
743 | try | 667 | return false; |
744 | { | ||
745 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); | ||
746 | oneCallback.callback(); | ||
747 | } | ||
748 | catch (Exception e) | ||
749 | { | ||
750 | DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
751 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
752 | } | ||
753 | } | 668 | } |
754 | } | 669 | } |
755 | /* | 670 | } |
756 | // swizzle a new list into the list location so we can process what's there | 671 | |
757 | List<TaintCallbackEntry> oldList; | 672 | /* TODO: verify that the mesher will now do all these shapes |
758 | lock (_taintLock) | 673 | if (pbs.ProfileHollow != 0) |
674 | iPropertiesNotSupportedDefault++; | ||
675 | |||
676 | if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) | ||
677 | iPropertiesNotSupportedDefault++; | ||
678 | |||
679 | if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) | ||
680 | iPropertiesNotSupportedDefault++; | ||
681 | |||
682 | if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) | ||
683 | iPropertiesNotSupportedDefault++; | ||
684 | |||
685 | if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) | ||
686 | iPropertiesNotSupportedDefault++; | ||
687 | |||
688 | if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) | ||
689 | iPropertiesNotSupportedDefault++; | ||
690 | |||
691 | if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) | ||
692 | iPropertiesNotSupportedDefault++; | ||
693 | |||
694 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) | ||
695 | iPropertiesNotSupportedDefault++; | ||
696 | |||
697 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) | ||
698 | iPropertiesNotSupportedDefault++; | ||
699 | |||
700 | // test for torus | ||
701 | if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) | ||
702 | { | ||
703 | if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
759 | { | 704 | { |
760 | oldList = _taintedObjects; | 705 | iPropertiesNotSupportedDefault++; |
761 | _taintedObjects = new List<TaintCallbackEntry>(); | ||
762 | } | 706 | } |
763 | 707 | } | |
764 | foreach (TaintCallbackEntry tcbe in oldList) | 708 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) |
709 | { | ||
710 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
765 | { | 711 | { |
766 | try | 712 | iPropertiesNotSupportedDefault++; |
767 | { | 713 | } |
768 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | 714 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits |
769 | tcbe.callback(); | 715 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) |
770 | } | 716 | { |
771 | catch (Exception e) | 717 | iPropertiesNotSupportedDefault++; |
772 | { | ||
773 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
774 | } | ||
775 | } | 718 | } |
776 | oldList.Clear(); | ||
777 | */ | ||
778 | } | 719 | } |
779 | } | 720 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) |
780 | |||
781 | // Schedule an update to happen after all the regular taints are processed. | ||
782 | // Note that new requests for the same operation ("ident") for the same object ("ID") | ||
783 | // will replace any previous operation by the same object. | ||
784 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) | ||
785 | { | ||
786 | if (!m_initialized) return; | ||
787 | |||
788 | string uniqueIdent = ident + "-" + ID.ToString(); | ||
789 | lock (_taintLock) | ||
790 | { | 721 | { |
791 | _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); | 722 | if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) |
723 | { | ||
724 | iPropertiesNotSupportedDefault++; | ||
725 | } | ||
792 | } | 726 | } |
793 | 727 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | |
794 | return; | ||
795 | } | ||
796 | |||
797 | private void ProcessPostTaintTaints() | ||
798 | { | ||
799 | if (_postTaintOperations.Count > 0) | ||
800 | { | 728 | { |
801 | Dictionary<string, TaintCallbackEntry> oldList; | 729 | if (pbs.PathCurve == (byte)Extrusion.Straight) |
802 | lock (_taintLock) | ||
803 | { | 730 | { |
804 | oldList = _postTaintOperations; | 731 | iPropertiesNotSupportedDefault++; |
805 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
806 | } | 732 | } |
807 | 733 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | |
808 | foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList) | ||
809 | { | 734 | { |
810 | try | 735 | iPropertiesNotSupportedDefault++; |
811 | { | ||
812 | DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG | ||
813 | kvp.Value.callback(); | ||
814 | } | ||
815 | catch (Exception e) | ||
816 | { | ||
817 | m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); | ||
818 | } | ||
819 | } | 736 | } |
820 | oldList.Clear(); | ||
821 | } | 737 | } |
738 | if (iPropertiesNotSupportedDefault == 0) | ||
739 | { | ||
740 | return false; | ||
741 | } | ||
742 | */ | ||
743 | return true; | ||
822 | } | 744 | } |
823 | 745 | ||
824 | public void PostStepTaintObject(String ident, TaintCallback callback) | 746 | // Calls to the PhysicsActors can't directly call into the physics engine |
747 | // because it might be busy. We delay changes to a known time. | ||
748 | // We rely on C#'s closure to save and restore the context for the delegate. | ||
749 | public void TaintedObject(String ident, TaintCallback callback) | ||
825 | { | 750 | { |
826 | if (!m_initialized) return; | 751 | if (!m_initialized) return; |
827 | 752 | ||
828 | lock (_taintLock) | 753 | lock (_taintLock) |
829 | { | 754 | _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); |
830 | _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
831 | } | ||
832 | |||
833 | return; | 755 | return; |
834 | } | 756 | } |
835 | 757 | ||
836 | private void ProcessPostStepTaints() | 758 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues |
759 | // a callback into itself to do the actual property change. That callback is called | ||
760 | // here just before the physics engine is called to step the simulation. | ||
761 | public void ProcessTaints() | ||
837 | { | 762 | { |
838 | if (_postStepOperations.Count > 0) | 763 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process |
839 | { | 764 | { |
765 | // swizzle a new list into the list location so we can process what's there | ||
840 | List<TaintCallbackEntry> oldList; | 766 | List<TaintCallbackEntry> oldList; |
841 | lock (_taintLock) | 767 | lock (_taintLock) |
842 | { | 768 | { |
843 | oldList = _postStepOperations; | 769 | oldList = _taintedObjects; |
844 | _postStepOperations = new List<TaintCallbackEntry>(); | 770 | _taintedObjects = new List<TaintCallbackEntry>(); |
845 | } | 771 | } |
846 | 772 | ||
847 | foreach (TaintCallbackEntry tcbe in oldList) | 773 | foreach (TaintCallbackEntry tcbe in oldList) |
848 | { | 774 | { |
849 | try | 775 | try |
850 | { | 776 | { |
851 | DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
852 | tcbe.callback(); | 777 | tcbe.callback(); |
853 | } | 778 | } |
854 | catch (Exception e) | 779 | catch (Exception e) |
855 | { | 780 | { |
856 | m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | 781 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); |
857 | } | 782 | } |
858 | } | 783 | } |
859 | oldList.Clear(); | 784 | oldList.Clear(); |
860 | } | 785 | } |
861 | } | 786 | } |
862 | 787 | ||
863 | public bool AssertInTaintTime(string whereFrom) | ||
864 | { | ||
865 | if (!InTaintTime) | ||
866 | { | ||
867 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | ||
868 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | ||
869 | Util.PrintCallStack(); | ||
870 | } | ||
871 | return InTaintTime; | ||
872 | } | ||
873 | |||
874 | #endregion // Taints | ||
875 | |||
876 | #region Vehicles | 788 | #region Vehicles |
877 | 789 | ||
878 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) | 790 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) |
879 | { | 791 | { |
880 | RemoveVehiclePrim(vehic); | 792 | if (newType == Vehicle.TYPE_NONE) |
881 | if (newType != Vehicle.TYPE_NONE) | ||
882 | { | 793 | { |
883 | // make it so the scene will call us each tick to do vehicle things | 794 | RemoveVehiclePrim(vehic); |
795 | } | ||
796 | else | ||
797 | { | ||
798 | // make it so the scene will call us each tick to do vehicle things | ||
884 | AddVehiclePrim(vehic); | 799 | AddVehiclePrim(vehic); |
885 | } | 800 | } |
886 | } | 801 | } |
@@ -912,22 +827,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
912 | } | 827 | } |
913 | 828 | ||
914 | // Some prims have extra vehicle actions | 829 | // Some prims have extra vehicle actions |
915 | // Called at taint time! | 830 | // no locking because only called when physics engine is not busy |
916 | private void ProcessVehicles(float timeStep) | 831 | private void ProcessVehicles(float timeStep) |
917 | { | 832 | { |
918 | foreach (BSPhysObject pobj in m_vehicles) | 833 | foreach (BSPrim prim in m_vehicles) |
919 | { | 834 | { |
920 | pobj.StepVehicle(timeStep); | 835 | prim.StepVehicle(timeStep); |
921 | } | 836 | } |
922 | } | 837 | } |
923 | #endregion Vehicles | 838 | #endregion Vehicles |
924 | 839 | ||
925 | #region INI and command line parameter processing | 840 | #region Parameters |
926 | 841 | ||
927 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | 842 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); |
928 | delegate float ParamGet(BSScene scene); | 843 | delegate float ParamGet(BSScene scene); |
929 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | 844 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); |
930 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
931 | 845 | ||
932 | private struct ParameterDefn | 846 | private struct ParameterDefn |
933 | { | 847 | { |
@@ -937,7 +851,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
937 | public ParamUser userParam; // get the value from the configuration file | 851 | public ParamUser userParam; // get the value from the configuration file |
938 | public ParamGet getter; // return the current value stored for this parameter | 852 | public ParamGet getter; // return the current value stored for this parameter |
939 | public ParamSet setter; // set the current value for this parameter | 853 | public ParamSet setter; // set the current value for this parameter |
940 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
941 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | 854 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) |
942 | { | 855 | { |
943 | name = n; | 856 | name = n; |
@@ -946,17 +859,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
946 | userParam = u; | 859 | userParam = u; |
947 | getter = g; | 860 | getter = g; |
948 | setter = s; | 861 | setter = s; |
949 | onObject = null; | ||
950 | } | ||
951 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
952 | { | ||
953 | name = n; | ||
954 | desc = d; | ||
955 | defaultValue = v; | ||
956 | userParam = u; | ||
957 | getter = g; | ||
958 | setter = s; | ||
959 | onObject = o; | ||
960 | } | 862 | } |
961 | } | 863 | } |
962 | 864 | ||
@@ -967,7 +869,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
967 | // getters and setters. | 869 | // getters and setters. |
968 | // It is easiest to find an existing definition and copy it. | 870 | // It is easiest to find an existing definition and copy it. |
969 | // Parameter values are floats. Booleans are converted to a floating value. | 871 | // Parameter values are floats. Booleans are converted to a floating value. |
970 | // | 872 | // |
971 | // A ParameterDefn() takes the following parameters: | 873 | // A ParameterDefn() takes the following parameters: |
972 | // -- the text name of the parameter. This is used for console input and ini file. | 874 | // -- the text name of the parameter. This is used for console input and ini file. |
973 | // -- a short text description of the parameter. This shows up in the console listing. | 875 | // -- a short text description of the parameter. This shows up in the console listing. |
@@ -978,7 +880,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
978 | // | 880 | // |
979 | // The single letter parameters for the delegates are: | 881 | // The single letter parameters for the delegates are: |
980 | // s = BSScene | 882 | // s = BSScene |
981 | // o = BSPhysObject | ||
982 | // p = string parameter name | 883 | // p = string parameter name |
983 | // l = localID of referenced object | 884 | // l = localID of referenced object |
984 | // v = float value | 885 | // v = float value |
@@ -987,40 +888,25 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
987 | { | 888 | { |
988 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | 889 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", |
989 | ConfigurationParameters.numericTrue, | 890 | ConfigurationParameters.numericTrue, |
990 | (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, | 891 | (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, |
991 | (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); }, | 892 | (s) => { return s.NumericBool(s._meshSculptedPrim); }, |
992 | (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ), | 893 | (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), |
993 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | 894 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", |
994 | ConfigurationParameters.numericFalse, | 895 | ConfigurationParameters.numericFalse, |
995 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | 896 | (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, |
996 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | 897 | (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, |
997 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | 898 | (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), |
998 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
999 | ConfigurationParameters.numericTrue, | ||
1000 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1001 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
1002 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
1003 | 899 | ||
1004 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 900 | new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
1005 | 8f, | 901 | 8f, |
1006 | (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); }, | 902 | (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, |
1007 | (s) => { return s.MeshLOD; }, | 903 | (s) => { return (float)s.m_meshLOD; }, |
1008 | (s,p,l,v) => { s.MeshLOD = v; } ), | 904 | (s,p,l,v) => { s.m_meshLOD = (int)v; } ), |
1009 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | 905 | new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", |
1010 | 16f, | ||
1011 | (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
1012 | (s) => { return s.MeshMegaPrimLOD; }, | ||
1013 | (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ), | ||
1014 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
1015 | 10f, | ||
1016 | (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
1017 | (s) => { return s.MeshMegaPrimThreshold; }, | ||
1018 | (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ), | ||
1019 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
1020 | 32f, | 906 | 32f, |
1021 | (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); }, | 907 | (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, |
1022 | (s) => { return s.SculptLOD; }, | 908 | (s) => { return (float)s.m_sculptLOD; }, |
1023 | (s,p,l,v) => { s.SculptLOD = v; } ), | 909 | (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), |
1024 | 910 | ||
1025 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | 911 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", |
1026 | 10f, | 912 | 10f, |
@@ -1042,16 +928,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1042 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | 928 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, |
1043 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | 929 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, |
1044 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | 930 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), |
1045 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
1046 | 100f, | ||
1047 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
1048 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
1049 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
1050 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | 931 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", |
1051 | 10000.01f, | 932 | 10000.01f, |
1052 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | 933 | (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, |
1053 | (s) => { return (float)s.MaximumObjectMass; }, | 934 | (s) => { return (float)s.m_maximumObjectMass; }, |
1054 | (s,p,l,v) => { s.MaximumObjectMass = v; } ), | 935 | (s,p,l,v) => { s.m_maximumObjectMass = v; } ), |
1055 | 936 | ||
1056 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | 937 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", |
1057 | 2200f, | 938 | 2200f, |
@@ -1088,118 +969,104 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1088 | -9.80665f, | 969 | -9.80665f, |
1089 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | 970 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, |
1090 | (s) => { return s.m_params[0].gravity; }, | 971 | (s) => { return s.m_params[0].gravity; }, |
1091 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | 972 | (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), |
1092 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
1093 | 973 | ||
1094 | 974 | ||
1095 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | 975 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", |
1096 | 0f, | 976 | 0f, |
1097 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | 977 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, |
1098 | (s) => { return s.m_params[0].linearDamping; }, | 978 | (s) => { return s.m_params[0].linearDamping; }, |
1099 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, | 979 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), |
1100 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ), | ||
1101 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | 980 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |
1102 | 0f, | 981 | 0f, |
1103 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | 982 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, |
1104 | (s) => { return s.m_params[0].angularDamping; }, | 983 | (s) => { return s.m_params[0].angularDamping; }, |
1105 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, | 984 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), |
1106 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ), | ||
1107 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | 985 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", |
1108 | 0.2f, | 986 | 0.2f, |
1109 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | 987 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, |
1110 | (s) => { return s.m_params[0].deactivationTime; }, | 988 | (s) => { return s.m_params[0].deactivationTime; }, |
1111 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, | 989 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), |
1112 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||
1113 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | 990 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |
1114 | 0.8f, | 991 | 0.8f, |
1115 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | 992 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, |
1116 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | 993 | (s) => { return s.m_params[0].linearSleepingThreshold; }, |
1117 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, | 994 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), |
1118 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1119 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | 995 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |
1120 | 1.0f, | 996 | 1.0f, |
1121 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | 997 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, |
1122 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | 998 | (s) => { return s.m_params[0].angularSleepingThreshold; }, |
1123 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, | 999 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), |
1124 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1125 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | 1000 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |
1126 | 0f, // set to zero to disable | 1001 | 0f, // set to zero to disable |
1127 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | 1002 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, |
1128 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | 1003 | (s) => { return s.m_params[0].ccdMotionThreshold; }, |
1129 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, | 1004 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), |
1130 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||
1131 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | 1005 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , |
1132 | 0f, | 1006 | 0f, |
1133 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | 1007 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, |
1134 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | 1008 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, |
1135 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, | 1009 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), |
1136 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||
1137 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | 1010 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , |
1138 | 0.1f, | 1011 | 0.1f, |
1139 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | 1012 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, |
1140 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | 1013 | (s) => { return s.m_params[0].contactProcessingThreshold; }, |
1141 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | 1014 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), |
1142 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||
1143 | 1015 | ||
1144 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1016 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1145 | 0.5f, | 1017 | 0.5f, |
1146 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1018 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
1147 | (s) => { return s.m_params[0].terrainFriction; }, | 1019 | (s) => { return s.m_params[0].terrainFriction; }, |
1148 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | 1020 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), |
1149 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | 1021 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , |
1150 | 0.8f, | 1022 | 0.8f, |
1151 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | 1023 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, |
1152 | (s) => { return s.m_params[0].terrainHitFraction; }, | 1024 | (s) => { return s.m_params[0].terrainHitFraction; }, |
1153 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), | 1025 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), |
1154 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | 1026 | new ParameterDefn("TerrainRestitution", "Bouncyness" , |
1155 | 0f, | 1027 | 0f, |
1156 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1028 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
1157 | (s) => { return s.m_params[0].terrainRestitution; }, | 1029 | (s) => { return s.m_params[0].terrainRestitution; }, |
1158 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | 1030 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), |
1159 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1031 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
1160 | 0.2f, | 1032 | 0.5f, |
1161 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1033 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
1162 | (s) => { return s.m_params[0].avatarFriction; }, | 1034 | (s) => { return s.m_params[0].avatarFriction; }, |
1163 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1035 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1164 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1165 | 10f, | ||
1166 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1167 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1168 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
1169 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | 1036 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |
1170 | 60f, | 1037 | 60f, |
1171 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | 1038 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, |
1172 | (s) => { return s.m_params[0].avatarDensity; }, | 1039 | (s) => { return s.m_params[0].avatarDensity; }, |
1173 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ), | 1040 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), |
1174 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | 1041 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", |
1175 | 0f, | 1042 | 0f, |
1176 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, | 1043 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, |
1177 | (s) => { return s.m_params[0].avatarRestitution; }, | 1044 | (s) => { return s.m_params[0].avatarRestitution; }, |
1178 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), | 1045 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), |
1179 | new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", | 1046 | new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", |
1180 | 0.37f, | 1047 | 0.37f, |
1181 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, | 1048 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, |
1182 | (s) => { return s.m_params[0].avatarCapsuleRadius; }, | 1049 | (s) => { return s.m_params[0].avatarCapsuleRadius; }, |
1183 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), | 1050 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), |
1184 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | 1051 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", |
1185 | 1.5f, | 1052 | 1.5f, |
1186 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, | 1053 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, |
1187 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, | 1054 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, |
1188 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), | 1055 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), |
1189 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 1056 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |
1190 | 0.1f, | 1057 | 0.1f, |
1191 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, | 1058 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, |
1192 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | 1059 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, |
1193 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | 1060 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), |
1194 | 1061 | ||
1195 | 1062 | ||
1196 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 1063 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
1197 | 0f, | 1064 | 0f, // zero to disable |
1198 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | 1065 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, |
1199 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, | 1066 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, |
1200 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), | 1067 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), |
1201 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | 1068 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", |
1202 | 0f, | 1069 | 0f, // zero to disable |
1203 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | 1070 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, |
1204 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, | 1071 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, |
1205 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), | 1072 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), |
@@ -1214,12 +1081,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1214 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, | 1081 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, |
1215 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), | 1082 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), |
1216 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | 1083 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", |
1217 | ConfigurationParameters.numericTrue, | 1084 | ConfigurationParameters.numericFalse, |
1218 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1085 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
1219 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, | 1086 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, |
1220 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), | 1087 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), |
1221 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | 1088 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", |
1222 | ConfigurationParameters.numericTrue, | 1089 | ConfigurationParameters.numericFalse, |
1223 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1090 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
1224 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, | 1091 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, |
1225 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), | 1092 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), |
@@ -1234,11 +1101,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1234 | (s) => { return s.m_params[0].numberOfSolverIterations; }, | 1101 | (s) => { return s.m_params[0].numberOfSolverIterations; }, |
1235 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), | 1102 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), |
1236 | 1103 | ||
1237 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
1238 | (float)BSLinkset.LinksetImplementation.Compound, | ||
1239 | (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, | ||
1240 | (s) => { return s.m_params[0].linksetImplementation; }, | ||
1241 | (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), | ||
1242 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | 1104 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |
1243 | ConfigurationParameters.numericFalse, | 1105 | ConfigurationParameters.numericFalse, |
1244 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1106 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
@@ -1259,27 +1121,28 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1259 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | 1121 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, |
1260 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | 1122 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, |
1261 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | 1123 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), |
1262 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | 1124 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0", |
1263 | 0.1f, | 1125 | 0.0f, |
1264 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | 1126 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, |
1265 | (s) => { return s.m_params[0].linkConstraintCFM; }, | 1127 | (s) => { return s.m_params[0].linkConstraintCFM; }, |
1266 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | 1128 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), |
1267 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | 1129 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
1268 | 0.1f, | 1130 | 0.2f, |
1269 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | 1131 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, |
1270 | (s) => { return s.m_params[0].linkConstraintERP; }, | 1132 | (s) => { return s.m_params[0].linkConstraintERP; }, |
1271 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | 1133 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), |
1272 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
1273 | 40, | ||
1274 | (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
1275 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | ||
1276 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | ||
1277 | 1134 | ||
1278 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | 1135 | new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", |
1279 | 0f, | 1136 | 0f, |
1280 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | 1137 | (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, |
1281 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, | 1138 | (s) => { return (float)s.m_detailedStatsStep; }, |
1282 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), | 1139 | (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), |
1140 | new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements", | ||
1141 | ConfigurationParameters.numericFalse, | ||
1142 | (s,cf,p,v) => { s.ShouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1143 | (s) => { return s.NumericBool(s.ShouldDebugLog); }, | ||
1144 | (s,p,l,v) => { s.ShouldDebugLog = s.BoolNumeric(v); } ), | ||
1145 | |||
1283 | }; | 1146 | }; |
1284 | 1147 | ||
1285 | // Convert a boolean to our numeric true and false values | 1148 | // Convert a boolean to our numeric true and false values |
@@ -1337,12 +1200,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1337 | 1200 | ||
1338 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | 1201 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; |
1339 | 1202 | ||
1340 | // This creates an array in the correct format for returning the list of | ||
1341 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
1342 | private void BuildParameterTable() | 1203 | private void BuildParameterTable() |
1343 | { | 1204 | { |
1344 | if (SettableParameters.Length < ParameterDefinitions.Length) | 1205 | if (SettableParameters.Length < ParameterDefinitions.Length) |
1345 | { | 1206 | { |
1207 | |||
1346 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | 1208 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); |
1347 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | 1209 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) |
1348 | { | 1210 | { |
@@ -1387,54 +1249,60 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1387 | return ret; | 1249 | return ret; |
1388 | } | 1250 | } |
1389 | 1251 | ||
1252 | // check to see if we are updating a parameter for a particular or all of the prims | ||
1253 | protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) | ||
1254 | { | ||
1255 | List<uint> operateOn; | ||
1256 | lock (m_prims) operateOn = new List<uint>(m_prims.Keys); | ||
1257 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
1258 | } | ||
1259 | |||
1260 | // check to see if we are updating a parameter for a particular or all of the avatars | ||
1261 | protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val) | ||
1262 | { | ||
1263 | List<uint> operateOn; | ||
1264 | lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); | ||
1265 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
1266 | } | ||
1267 | |||
1390 | // update all the localIDs specified | 1268 | // update all the localIDs specified |
1391 | // If the local ID is APPLY_TO_NONE, just change the default value | 1269 | // If the local ID is APPLY_TO_NONE, just change the default value |
1392 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | 1270 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |
1393 | // If the localID is a specific object, apply the parameter change to only that object | 1271 | // If the localID is a specific object, apply the parameter change to only that object |
1394 | private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) | 1272 | protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) |
1395 | { | 1273 | { |
1396 | List<uint> objectIDs = new List<uint>(); | ||
1397 | switch (localID) | 1274 | switch (localID) |
1398 | { | 1275 | { |
1399 | case PhysParameterEntry.APPLY_TO_NONE: | 1276 | case PhysParameterEntry.APPLY_TO_NONE: |
1400 | defaultLoc = val; // setting only the default value | 1277 | defaultLoc = val; // setting only the default value |
1401 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
1402 | objectIDs.Add(TERRAIN_ID); | ||
1403 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1404 | break; | 1278 | break; |
1405 | case PhysParameterEntry.APPLY_TO_ALL: | 1279 | case PhysParameterEntry.APPLY_TO_ALL: |
1406 | defaultLoc = val; // setting ALL also sets the default value | 1280 | defaultLoc = val; // setting ALL also sets the default value |
1407 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | 1281 | List<uint> objectIDs = lIDs; |
1408 | TaintedUpdateParameter(parm, objectIDs, val); | 1282 | string xparm = parm.ToLower(); |
1283 | float xval = val; | ||
1284 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1285 | foreach (uint lID in objectIDs) | ||
1286 | { | ||
1287 | BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); | ||
1288 | } | ||
1289 | }); | ||
1409 | break; | 1290 | break; |
1410 | default: | 1291 | default: |
1411 | // setting only one localID | 1292 | // setting only one localID |
1412 | objectIDs.Add(localID); | 1293 | TaintedUpdateParameter(parm, localID, val); |
1413 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1414 | break; | 1294 | break; |
1415 | } | 1295 | } |
1416 | } | 1296 | } |
1417 | 1297 | ||
1418 | // schedule the actual updating of the paramter to when the phys engine is not busy | 1298 | // schedule the actual updating of the paramter to when the phys engine is not busy |
1419 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) | 1299 | protected void TaintedUpdateParameter(string parm, uint localID, float val) |
1420 | { | 1300 | { |
1301 | uint xlocalID = localID; | ||
1302 | string xparm = parm.ToLower(); | ||
1421 | float xval = val; | 1303 | float xval = val; |
1422 | List<uint> xlIDs = lIDs; | 1304 | TaintedObject("BSScene.TaintedUpdateParameter", delegate() { |
1423 | string xparm = parm; | 1305 | BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); |
1424 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1425 | ParameterDefn thisParam; | ||
1426 | if (TryGetParameter(xparm, out thisParam)) | ||
1427 | { | ||
1428 | if (thisParam.onObject != null) | ||
1429 | { | ||
1430 | foreach (uint lID in xlIDs) | ||
1431 | { | ||
1432 | BSPhysObject theObject = null; | ||
1433 | PhysObjects.TryGetValue(lID, out theObject); | ||
1434 | thisParam.onObject(this, theObject, xval); | ||
1435 | } | ||
1436 | } | ||
1437 | } | ||
1438 | }); | 1306 | }); |
1439 | } | 1307 | } |
1440 | 1308 | ||
@@ -1458,24 +1326,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1458 | 1326 | ||
1459 | #endregion Runtime settable parameters | 1327 | #endregion Runtime settable parameters |
1460 | 1328 | ||
1461 | // Debugging routine for dumping detailed physical information for vehicle prims | ||
1462 | private void DumpVehicles() | ||
1463 | { | ||
1464 | foreach (BSPrim prim in m_vehicles) | ||
1465 | { | ||
1466 | BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); | ||
1467 | BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); | ||
1468 | } | ||
1469 | } | ||
1470 | |||
1471 | // Invoke the detailed logger and output something if it's enabled. | 1329 | // Invoke the detailed logger and output something if it's enabled. |
1472 | public void DetailLog(string msg, params Object[] args) | 1330 | public void DetailLog(string msg, params Object[] args) |
1473 | { | 1331 | { |
1474 | PhysicsLogging.Write(msg, args); | 1332 | PhysicsLogging.Write(msg, args); |
1475 | // Add the Flush() if debugging crashes. Gets all the messages written out. | ||
1476 | PhysicsLogging.Flush(); | ||
1477 | } | 1333 | } |
1478 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1334 | // used to fill in the LocalID when there isn't one |
1479 | public const string DetailLogZero = "0000000000"; | 1335 | public const string DetailLogZero = "0000000000"; |
1480 | 1336 | ||
1481 | } | 1337 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs deleted file mode 100755 index 29a23c0..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ /dev/null | |||
@@ -1,1000 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OMV = OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Physics.Manager; | ||
33 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public sealed class BSShapeCollection : IDisposable | ||
38 | { | ||
39 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; | ||
40 | |||
41 | private BSScene PhysicsScene { get; set; } | ||
42 | |||
43 | private Object m_collectionActivityLock = new Object(); | ||
44 | |||
45 | // Description of a Mesh | ||
46 | private struct MeshDesc | ||
47 | { | ||
48 | public IntPtr ptr; | ||
49 | public int referenceCount; | ||
50 | public DateTime lastReferenced; | ||
51 | public UInt64 shapeKey; | ||
52 | } | ||
53 | |||
54 | // Description of a hull. | ||
55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. | ||
56 | private struct HullDesc | ||
57 | { | ||
58 | public IntPtr ptr; | ||
59 | public int referenceCount; | ||
60 | public DateTime lastReferenced; | ||
61 | public UInt64 shapeKey; | ||
62 | } | ||
63 | |||
64 | // The sharable set of meshes and hulls. Indexed by their shape hash. | ||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | ||
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | ||
67 | |||
68 | public BSShapeCollection(BSScene physScene) | ||
69 | { | ||
70 | PhysicsScene = physScene; | ||
71 | } | ||
72 | |||
73 | public void Dispose() | ||
74 | { | ||
75 | // TODO!!!!!!!!! | ||
76 | } | ||
77 | |||
78 | // Callbacks called just before either the body or shape is destroyed. | ||
79 | // Mostly used for changing bodies out from under Linksets. | ||
80 | // Useful for other cases where parameters need saving. | ||
81 | // Passing 'null' says no callback. | ||
82 | public delegate void ShapeDestructionCallback(BulletShape shape); | ||
83 | public delegate void BodyDestructionCallback(BulletBody body); | ||
84 | |||
85 | // Called to update/change the body and shape for an object. | ||
86 | // First checks the shape and updates that if necessary then makes | ||
87 | // sure the body is of the right type. | ||
88 | // Return 'true' if either the body or the shape changed. | ||
89 | // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before | ||
90 | // the current shape or body is destroyed. This allows the caller to remove any | ||
91 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | ||
92 | // remove the physical constraints before the body is destroyed. | ||
93 | // Called at taint-time!! | ||
94 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, | ||
95 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | ||
96 | { | ||
97 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | ||
98 | |||
99 | bool ret = false; | ||
100 | |||
101 | // This lock could probably be pushed down lower but building shouldn't take long | ||
102 | lock (m_collectionActivityLock) | ||
103 | { | ||
104 | // Do we have the correct geometry for this type of object? | ||
105 | // Updates prim.BSShape with information/pointers to shape. | ||
106 | // Returns 'true' of BSShape is changed to a new shape. | ||
107 | bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); | ||
108 | // If we had to select a new shape geometry for the object, | ||
109 | // rebuild the body around it. | ||
110 | // Updates prim.BSBody with information/pointers to requested body | ||
111 | // Returns 'true' if BSBody was changed. | ||
112 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, | ||
113 | prim.PhysShape, bodyCallback); | ||
114 | ret = newGeom || newBody; | ||
115 | } | ||
116 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", | ||
117 | prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | // Track another user of a body. | ||
123 | // We presume the caller has allocated the body. | ||
124 | // Bodies only have one user so the body is just put into the world if not already there. | ||
125 | public void ReferenceBody(BulletBody body, bool inTaintTime) | ||
126 | { | ||
127 | lock (m_collectionActivityLock) | ||
128 | { | ||
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | ||
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | ||
131 | { | ||
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | ||
133 | { | ||
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | ||
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
136 | } | ||
137 | }); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | // Release the usage of a body. | ||
142 | // Called when releasing use of a BSBody. BSShape is handled separately. | ||
143 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | ||
144 | { | ||
145 | if (body.ptr == IntPtr.Zero) | ||
146 | return; | ||
147 | |||
148 | lock (m_collectionActivityLock) | ||
149 | { | ||
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | ||
151 | { | ||
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | ||
153 | body.ID, body, inTaintTime); | ||
154 | // If the caller needs to know the old body is going away, pass the event up. | ||
155 | if (bodyCallback != null) bodyCallback(body); | ||
156 | |||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | ||
158 | { | ||
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | ||
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | ||
161 | } | ||
162 | |||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
164 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | ||
165 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | ||
166 | }); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | // Track the datastructures and use count for a shape. | ||
171 | // When creating a hull, this is called first to reference the mesh | ||
172 | // and then again to reference the hull. | ||
173 | // Meshes and hulls for the same shape have the same hash key. | ||
174 | // NOTE that native shapes are not added to the mesh list or removed. | ||
175 | // Returns 'true' if this is the initial reference to the shape. Otherwise reused. | ||
176 | public bool ReferenceShape(BulletShape shape) | ||
177 | { | ||
178 | bool ret = false; | ||
179 | switch (shape.type) | ||
180 | { | ||
181 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
182 | MeshDesc meshDesc; | ||
183 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
184 | { | ||
185 | // There is an existing instance of this mesh. | ||
186 | meshDesc.referenceCount++; | ||
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | ||
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | // This is a new reference to a mesh | ||
193 | meshDesc.ptr = shape.ptr; | ||
194 | meshDesc.shapeKey = shape.shapeKey; | ||
195 | // We keep a reference to the underlying IMesh data so a hull can be built | ||
196 | meshDesc.referenceCount = 1; | ||
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | ||
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
199 | ret = true; | ||
200 | } | ||
201 | meshDesc.lastReferenced = System.DateTime.Now; | ||
202 | Meshes[shape.shapeKey] = meshDesc; | ||
203 | break; | ||
204 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | ||
205 | HullDesc hullDesc; | ||
206 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
207 | { | ||
208 | // There is an existing instance of this hull. | ||
209 | hullDesc.referenceCount++; | ||
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | ||
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | // This is a new reference to a hull | ||
216 | hullDesc.ptr = shape.ptr; | ||
217 | hullDesc.shapeKey = shape.shapeKey; | ||
218 | hullDesc.referenceCount = 1; | ||
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | ||
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
221 | ret = true; | ||
222 | |||
223 | } | ||
224 | hullDesc.lastReferenced = System.DateTime.Now; | ||
225 | Hulls[shape.shapeKey] = hullDesc; | ||
226 | break; | ||
227 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
228 | break; | ||
229 | default: | ||
230 | // Native shapes are not tracked and they don't go into any list | ||
231 | break; | ||
232 | } | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | // Release the usage of a shape. | ||
237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | ||
238 | { | ||
239 | if (shape.ptr == IntPtr.Zero) | ||
240 | return; | ||
241 | |||
242 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | ||
243 | { | ||
244 | if (shape.ptr != IntPtr.Zero) | ||
245 | { | ||
246 | if (shape.isNativeShape) | ||
247 | { | ||
248 | // Native shapes are not tracked and are released immediately | ||
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | ||
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | ||
251 | if (shapeCallback != null) shapeCallback(shape); | ||
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | switch (shape.type) | ||
257 | { | ||
258 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | ||
259 | DereferenceHull(shape, shapeCallback); | ||
260 | break; | ||
261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
262 | DereferenceMesh(shape, shapeCallback); | ||
263 | break; | ||
264 | case ShapeData.PhysicsShapeType.SHAPE_COMPOUND: | ||
265 | DereferenceCompound(shape, shapeCallback); | ||
266 | break; | ||
267 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
268 | break; | ||
269 | default: | ||
270 | break; | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | }); | ||
275 | } | ||
276 | |||
277 | // Count down the reference count for a mesh shape | ||
278 | // Called at taint-time. | ||
279 | private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
280 | { | ||
281 | MeshDesc meshDesc; | ||
282 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
283 | { | ||
284 | meshDesc.referenceCount--; | ||
285 | // TODO: release the Bullet storage | ||
286 | if (shapeCallback != null) shapeCallback(shape); | ||
287 | meshDesc.lastReferenced = System.DateTime.Now; | ||
288 | Meshes[shape.shapeKey] = meshDesc; | ||
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | ||
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | ||
291 | |||
292 | } | ||
293 | } | ||
294 | |||
295 | // Count down the reference count for a hull shape | ||
296 | // Called at taint-time. | ||
297 | private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
298 | { | ||
299 | HullDesc hullDesc; | ||
300 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
301 | { | ||
302 | hullDesc.referenceCount--; | ||
303 | // TODO: release the Bullet storage (aging old entries?) | ||
304 | |||
305 | // Tell upper layers that, if they have dependencies on this shape, this link is going away | ||
306 | if (shapeCallback != null) shapeCallback(shape); | ||
307 | |||
308 | hullDesc.lastReferenced = System.DateTime.Now; | ||
309 | Hulls[shape.shapeKey] = hullDesc; | ||
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | ||
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | ||
312 | } | ||
313 | } | ||
314 | |||
315 | // Remove a reference to a compound shape. | ||
316 | // Taking a compound shape apart is a little tricky because if you just delete the | ||
317 | // physical shape, it will free all the underlying children. We can't do that because | ||
318 | // they could be shared. So, this removes each of the children from the compound and | ||
319 | // dereferences them separately before destroying the compound collision object itself. | ||
320 | // Called at taint-time. | ||
321 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
322 | { | ||
323 | if (!BulletSimAPI.IsCompound2(shape.ptr)) | ||
324 | { | ||
325 | // Failed the sanity check!! | ||
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
327 | LogHeader, shape.type, shape.ptr.ToString("X")); | ||
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | ||
330 | return; | ||
331 | } | ||
332 | |||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | ||
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | ||
335 | |||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
337 | { | ||
338 | IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); | ||
339 | DereferenceAnonCollisionShape(childShape); | ||
340 | } | ||
341 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
342 | } | ||
343 | |||
344 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
345 | // Figure out type and call the correct dereference routine. | ||
346 | // Called at taint-time. | ||
347 | private void DereferenceAnonCollisionShape(IntPtr cShape) | ||
348 | { | ||
349 | MeshDesc meshDesc; | ||
350 | HullDesc hullDesc; | ||
351 | |||
352 | BulletShape shapeInfo = new BulletShape(cShape); | ||
353 | if (TryGetMeshByPtr(cShape, out meshDesc)) | ||
354 | { | ||
355 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_MESH; | ||
356 | shapeInfo.shapeKey = meshDesc.shapeKey; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | if (TryGetHullByPtr(cShape, out hullDesc)) | ||
361 | { | ||
362 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL; | ||
363 | shapeInfo.shapeKey = hullDesc.shapeKey; | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | if (BulletSimAPI.IsCompound2(cShape)) | ||
368 | { | ||
369 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | if (BulletSimAPI.IsNativeShape2(cShape)) | ||
374 | { | ||
375 | shapeInfo.isNativeShape = true; | ||
376 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | |||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | ||
383 | |||
384 | if (shapeInfo.type != ShapeData.PhysicsShapeType.SHAPE_UNKNOWN) | ||
385 | { | ||
386 | DereferenceShape(shapeInfo, true, null); | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | ||
391 | LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | // Create the geometry information in Bullet for later use. | ||
396 | // The objects needs a hull if it's physical otherwise a mesh is enough. | ||
397 | // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, | ||
398 | // shared geometries will be used. If the parameters of the existing shape are the same | ||
399 | // as this request, the shape is not rebuilt. | ||
400 | // Info in prim.BSShape is updated to the new shape. | ||
401 | // Returns 'true' if the geometry was rebuilt. | ||
402 | // Called at taint-time! | ||
403 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
404 | { | ||
405 | bool ret = false; | ||
406 | bool haveShape = false; | ||
407 | |||
408 | if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | ||
409 | { | ||
410 | // an avatar capsule is close to a native shape (it is not shared) | ||
411 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, | ||
412 | ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); | ||
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | ||
414 | ret = true; | ||
415 | haveShape = true; | ||
416 | } | ||
417 | |||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
419 | // This isn't too great a hardship since most of the child shapes will already been created. | ||
420 | if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND) | ||
421 | { | ||
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | ||
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | ||
424 | haveShape = true; | ||
425 | } | ||
426 | |||
427 | if (!haveShape) | ||
428 | { | ||
429 | ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); | ||
430 | } | ||
431 | |||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | ||
436 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
437 | { | ||
438 | bool ret = false; | ||
439 | bool haveShape = false; | ||
440 | bool nativeShapePossible = true; | ||
441 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
442 | |||
443 | // If the prim attributes are simple, this could be a simple Bullet native shape | ||
444 | if (!haveShape | ||
445 | && pbs != null | ||
446 | && nativeShapePossible | ||
447 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | ||
448 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
449 | && pbs.ProfileHollow == 0 | ||
450 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
451 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
452 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | ||
455 | { | ||
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | ||
457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | ||
458 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | ||
459 | { | ||
460 | haveShape = true; | ||
461 | if (forceRebuild | ||
462 | || prim.Scale != prim.Size | ||
463 | || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE | ||
464 | ) | ||
465 | { | ||
466 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE, | ||
467 | ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); | ||
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | ||
469 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
470 | } | ||
471 | } | ||
472 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
473 | { | ||
474 | haveShape = true; | ||
475 | if (forceRebuild | ||
476 | || prim.Scale != prim.Size | ||
477 | || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX | ||
478 | ) | ||
479 | { | ||
480 | ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX, | ||
481 | ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); | ||
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | ||
483 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
484 | } | ||
485 | } | ||
486 | } | ||
487 | |||
488 | // If a simple shape is not happening, create a mesh and possibly a hull. | ||
489 | if (!haveShape && pbs != null) | ||
490 | { | ||
491 | ret = CreateGeomMeshOrHull(prim, shapeCallback); | ||
492 | } | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
498 | { | ||
499 | |||
500 | bool ret = false; | ||
501 | // Note that if it's a native shape, the check for physical/non-physical is not | ||
502 | // made. Native shapes work in either case. | ||
503 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) | ||
504 | { | ||
505 | // Update prim.BSShape to reference a hull of this shape. | ||
506 | ret = GetReferenceToHull(prim,shapeCallback); | ||
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | ||
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
509 | } | ||
510 | else | ||
511 | { | ||
512 | ret = GetReferenceToMesh(prim, shapeCallback); | ||
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | ||
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
515 | } | ||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | // Creates a native shape and assignes it to prim.BSShape. | ||
520 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). | ||
521 | private bool GetReferenceToNativeShape(BSPhysObject prim, | ||
522 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, | ||
523 | ShapeDestructionCallback shapeCallback) | ||
524 | { | ||
525 | // release any previous shape | ||
526 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
527 | |||
528 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
529 | prim.Scale = prim.Size; | ||
530 | |||
531 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | ||
532 | |||
533 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | ||
534 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | ||
535 | prim.LocalID, newShape, prim.Scale); | ||
536 | |||
537 | prim.PhysShape = newShape; | ||
538 | return true; | ||
539 | } | ||
540 | |||
541 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType, | ||
542 | ShapeData.FixedShapeKey shapeKey) | ||
543 | { | ||
544 | BulletShape newShape; | ||
545 | // Need to make sure the passed shape information is for the native type. | ||
546 | ShapeData nativeShapeData = new ShapeData(); | ||
547 | nativeShapeData.Type = shapeType; | ||
548 | nativeShapeData.ID = prim.LocalID; | ||
549 | nativeShapeData.Scale = prim.Scale; | ||
550 | nativeShapeData.Size = prim.Scale; | ||
551 | nativeShapeData.MeshKey = (ulong)shapeKey; | ||
552 | nativeShapeData.HullKey = (ulong)shapeKey; | ||
553 | |||
554 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | ||
555 | { | ||
556 | newShape = new BulletShape( | ||
557 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | ||
558 | , shapeType); | ||
559 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | ||
564 | } | ||
565 | if (newShape.ptr == IntPtr.Zero) | ||
566 | { | ||
567 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | ||
568 | LogHeader, prim.LocalID, shapeType); | ||
569 | } | ||
570 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
571 | newShape.isNativeShape = true; | ||
572 | |||
573 | return newShape; | ||
574 | } | ||
575 | |||
576 | // Builds a mesh shape in the physical world and updates prim.BSShape. | ||
577 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | ||
578 | // Returns 'true' of a mesh was actually built. Otherwise . | ||
579 | // Called at taint-time! | ||
580 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
581 | { | ||
582 | BulletShape newShape = new BulletShape(IntPtr.Zero); | ||
583 | |||
584 | float lod; | ||
585 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
586 | |||
587 | // if this new shape is the same as last time, don't recreate the mesh | ||
588 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) | ||
589 | return false; | ||
590 | |||
591 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | ||
592 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | ||
593 | |||
594 | // Since we're recreating new, get rid of the reference to the previous shape | ||
595 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
596 | |||
597 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
598 | // Take evasive action if the mesh was not constructed. | ||
599 | newShape = VerifyMeshCreated(newShape, prim); | ||
600 | |||
601 | ReferenceShape(newShape); | ||
602 | |||
603 | // meshes are already scaled by the meshmerizer | ||
604 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
605 | prim.PhysShape = newShape; | ||
606 | |||
607 | return true; // 'true' means a new shape has been added to this prim | ||
608 | } | ||
609 | |||
610 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
611 | { | ||
612 | IMesh meshData = null; | ||
613 | IntPtr meshPtr = IntPtr.Zero; | ||
614 | MeshDesc meshDesc; | ||
615 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | ||
616 | { | ||
617 | // If the mesh has already been built just use it. | ||
618 | meshPtr = meshDesc.ptr; | ||
619 | } | ||
620 | else | ||
621 | { | ||
622 | // 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, false); | ||
624 | |||
625 | if (meshData != null) | ||
626 | { | ||
627 | int[] indices = meshData.getIndexListAsInt(); | ||
628 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
629 | |||
630 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
631 | int vi = 0; | ||
632 | foreach (OMV.Vector3 vv in vertices) | ||
633 | { | ||
634 | verticesAsFloats[vi++] = vv.X; | ||
635 | verticesAsFloats[vi++] = vv.Y; | ||
636 | verticesAsFloats[vi++] = vv.Z; | ||
637 | } | ||
638 | |||
639 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
640 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | ||
641 | |||
642 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | ||
643 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | ||
644 | } | ||
645 | } | ||
646 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | ||
647 | newShape.shapeKey = newMeshKey; | ||
648 | |||
649 | return newShape; | ||
650 | } | ||
651 | |||
652 | // See that hull shape exists in the physical world and update prim.BSShape. | ||
653 | // We could be creating the hull because scale changed or whatever. | ||
654 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
655 | { | ||
656 | BulletShape newShape; | ||
657 | |||
658 | float lod; | ||
659 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
660 | |||
661 | // if the hull hasn't changed, don't rebuild it | ||
662 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) | ||
663 | return false; | ||
664 | |||
665 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | ||
666 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | ||
667 | |||
668 | // Remove usage of the previous shape. | ||
669 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
670 | |||
671 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | ||
672 | newShape = VerifyMeshCreated(newShape, prim); | ||
673 | |||
674 | ReferenceShape(newShape); | ||
675 | |||
676 | // hulls are already scaled by the meshmerizer | ||
677 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
678 | prim.PhysShape = newShape; | ||
679 | return true; // 'true' means a new shape has been added to this prim | ||
680 | } | ||
681 | |||
682 | List<ConvexResult> m_hulls; | ||
683 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
684 | { | ||
685 | |||
686 | IntPtr hullPtr = IntPtr.Zero; | ||
687 | HullDesc hullDesc; | ||
688 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | ||
689 | { | ||
690 | // If the hull shape already is created, just use it. | ||
691 | hullPtr = hullDesc.ptr; | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | // Build a new hull in the physical world | ||
696 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | ||
697 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | ||
698 | if (meshData != null) | ||
699 | { | ||
700 | |||
701 | int[] indices = meshData.getIndexListAsInt(); | ||
702 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
703 | |||
704 | //format conversion from IMesh format to DecompDesc format | ||
705 | List<int> convIndices = new List<int>(); | ||
706 | List<float3> convVertices = new List<float3>(); | ||
707 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
708 | { | ||
709 | convIndices.Add(indices[ii]); | ||
710 | } | ||
711 | foreach (OMV.Vector3 vv in vertices) | ||
712 | { | ||
713 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
714 | } | ||
715 | |||
716 | // setup and do convex hull conversion | ||
717 | m_hulls = new List<ConvexResult>(); | ||
718 | DecompDesc dcomp = new DecompDesc(); | ||
719 | dcomp.mIndices = convIndices; | ||
720 | dcomp.mVertices = convVertices; | ||
721 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
722 | // create the hull into the _hulls variable | ||
723 | convexBuilder.process(dcomp); | ||
724 | |||
725 | // Convert the vertices and indices for passing to unmanaged. | ||
726 | // The hull information is passed as a large floating point array. | ||
727 | // The format is: | ||
728 | // convHulls[0] = number of hulls | ||
729 | // convHulls[1] = number of vertices in first hull | ||
730 | // convHulls[2] = hull centroid X coordinate | ||
731 | // convHulls[3] = hull centroid Y coordinate | ||
732 | // convHulls[4] = hull centroid Z coordinate | ||
733 | // convHulls[5] = first hull vertex X | ||
734 | // convHulls[6] = first hull vertex Y | ||
735 | // convHulls[7] = first hull vertex Z | ||
736 | // convHulls[8] = second hull vertex X | ||
737 | // ... | ||
738 | // convHulls[n] = number of vertices in second hull | ||
739 | // convHulls[n+1] = second hull centroid X coordinate | ||
740 | // ... | ||
741 | // | ||
742 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
743 | // data structures that do not need to be converted in order to pass to Bullet. | ||
744 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
745 | int hullCount = m_hulls.Count; | ||
746 | int totalVertices = 1; // include one for the count of the hulls | ||
747 | foreach (ConvexResult cr in m_hulls) | ||
748 | { | ||
749 | totalVertices += 4; // add four for the vertex count and centroid | ||
750 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
751 | } | ||
752 | float[] convHulls = new float[totalVertices]; | ||
753 | |||
754 | convHulls[0] = (float)hullCount; | ||
755 | int jj = 1; | ||
756 | foreach (ConvexResult cr in m_hulls) | ||
757 | { | ||
758 | // copy vertices for index access | ||
759 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
760 | int kk = 0; | ||
761 | foreach (float3 ff in cr.HullVertices) | ||
762 | { | ||
763 | verts[kk++] = ff; | ||
764 | } | ||
765 | |||
766 | // add to the array one hull's worth of data | ||
767 | convHulls[jj++] = cr.HullIndices.Count; | ||
768 | convHulls[jj++] = 0f; // centroid x,y,z | ||
769 | convHulls[jj++] = 0f; | ||
770 | convHulls[jj++] = 0f; | ||
771 | foreach (int ind in cr.HullIndices) | ||
772 | { | ||
773 | convHulls[jj++] = verts[ind].x; | ||
774 | convHulls[jj++] = verts[ind].y; | ||
775 | convHulls[jj++] = verts[ind].z; | ||
776 | } | ||
777 | } | ||
778 | // create the hull data structure in Bullet | ||
779 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
780 | } | ||
781 | } | ||
782 | |||
783 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | ||
784 | newShape.shapeKey = newHullKey; | ||
785 | |||
786 | return newShape; // 'true' means a new shape has been added to this prim | ||
787 | } | ||
788 | |||
789 | // Callback from convex hull creater with a newly created hull. | ||
790 | // Just add it to our collection of hulls for this shape. | ||
791 | private void HullReturn(ConvexResult result) | ||
792 | { | ||
793 | m_hulls.Add(result); | ||
794 | return; | ||
795 | } | ||
796 | |||
797 | // Compound shapes are always built from scratch. | ||
798 | // This shouldn't be to bad since most of the parts will be meshes that had been built previously. | ||
799 | private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
800 | { | ||
801 | // Remove reference to the old shape | ||
802 | // Don't need to do this as the shape is freed when the new root shape is created below. | ||
803 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
804 | |||
805 | BulletShape cShape = new BulletShape( | ||
806 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND); | ||
807 | |||
808 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | ||
809 | CreateGeomMeshOrHull(prim, shapeCallback); | ||
810 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | ||
811 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | ||
812 | prim.LocalID, cShape, prim.PhysShape); | ||
813 | |||
814 | prim.PhysShape = cShape; | ||
815 | |||
816 | return true; | ||
817 | } | ||
818 | |||
819 | // Create a hash of all the shape parameters to be used as a key | ||
820 | // for this particular shape. | ||
821 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
822 | { | ||
823 | // level of detail based on size and type of the object | ||
824 | float lod = PhysicsScene.MeshLOD; | ||
825 | if (pbs.SculptEntry) | ||
826 | lod = PhysicsScene.SculptLOD; | ||
827 | |||
828 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
829 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
830 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | ||
831 | lod = PhysicsScene.MeshMegaPrimLOD; | ||
832 | |||
833 | retLod = lod; | ||
834 | return pbs.GetMeshKey(size, lod); | ||
835 | } | ||
836 | // For those who don't want the LOD | ||
837 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) | ||
838 | { | ||
839 | float lod; | ||
840 | return ComputeShapeKey(size, pbs, out lod); | ||
841 | } | ||
842 | |||
843 | // The creation of a mesh or hull can fail if an underlying asset is not available. | ||
844 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
845 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
846 | // The first case causes the asset to be fetched. The second case requires | ||
847 | // us to not loop forever. | ||
848 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
849 | // just return. | ||
850 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | ||
851 | { | ||
852 | // If the shape was successfully created, nothing more to do | ||
853 | if (newShape.ptr != IntPtr.Zero) | ||
854 | return newShape; | ||
855 | |||
856 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
857 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) | ||
858 | { | ||
859 | prim.LastAssetBuildFailed = true; | ||
860 | BSPhysObject xprim = prim; | ||
861 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", | ||
862 | LogHeader, prim.LocalID, prim.LastAssetBuildFailed); | ||
863 | Util.FireAndForget(delegate | ||
864 | { | ||
865 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
866 | if (assetProvider != null) | ||
867 | { | ||
868 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
869 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
870 | { | ||
871 | if (!yprim.BaseShape.SculptEntry) | ||
872 | return; | ||
873 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
874 | return; | ||
875 | |||
876 | yprim.BaseShape.SculptData = asset.Data; | ||
877 | // This will cause the prim to see that the filler shape is not the right | ||
878 | // one and try again to build the object. | ||
879 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
880 | yprim.ForceBodyShapeRebuild(false); | ||
881 | |||
882 | }); | ||
883 | } | ||
884 | }); | ||
885 | } | ||
886 | else | ||
887 | { | ||
888 | if (prim.LastAssetBuildFailed) | ||
889 | { | ||
890 | PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", | ||
891 | LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); | ||
892 | } | ||
893 | } | ||
894 | |||
895 | // While we figure out the real problem, stick a simple native shape on the object. | ||
896 | BulletShape fillinShape = | ||
897 | BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX); | ||
898 | |||
899 | return fillinShape; | ||
900 | } | ||
901 | |||
902 | // Create a body object in Bullet. | ||
903 | // Updates prim.BSBody with the information about the new body if one is created. | ||
904 | // Returns 'true' if an object was actually created. | ||
905 | // Called at taint-time. | ||
906 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, | ||
907 | BodyDestructionCallback bodyCallback) | ||
908 | { | ||
909 | bool ret = false; | ||
910 | |||
911 | // the mesh, hull or native shape must have already been created in Bullet | ||
912 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); | ||
913 | |||
914 | // If there is an existing body, verify it's of an acceptable type. | ||
915 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | ||
916 | if (!mustRebuild) | ||
917 | { | ||
918 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); | ||
919 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | ||
920 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | ||
921 | { | ||
922 | // If the collisionObject is not the correct type for solidness, rebuild what's there | ||
923 | mustRebuild = true; | ||
924 | } | ||
925 | } | ||
926 | |||
927 | if (mustRebuild || forceRebuild) | ||
928 | { | ||
929 | // Free any old body | ||
930 | DereferenceBody(prim.PhysBody, true, bodyCallback); | ||
931 | |||
932 | BulletBody aBody; | ||
933 | IntPtr bodyPtr = IntPtr.Zero; | ||
934 | if (prim.IsSolid) | ||
935 | { | ||
936 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | ||
937 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
938 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
939 | } | ||
940 | else | ||
941 | { | ||
942 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | ||
943 | prim.LocalID, prim.ForcePosition, prim.ForceOrientation); | ||
944 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
945 | } | ||
946 | aBody = new BulletBody(prim.LocalID, bodyPtr); | ||
947 | |||
948 | ReferenceBody(aBody, true); | ||
949 | |||
950 | prim.PhysBody = aBody; | ||
951 | |||
952 | ret = true; | ||
953 | } | ||
954 | |||
955 | return ret; | ||
956 | } | ||
957 | |||
958 | private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) | ||
959 | { | ||
960 | bool ret = false; | ||
961 | MeshDesc foundDesc = new MeshDesc(); | ||
962 | foreach (MeshDesc md in Meshes.Values) | ||
963 | { | ||
964 | if (md.ptr == addr) | ||
965 | { | ||
966 | foundDesc = md; | ||
967 | ret = true; | ||
968 | break; | ||
969 | } | ||
970 | |||
971 | } | ||
972 | outDesc = foundDesc; | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) | ||
977 | { | ||
978 | bool ret = false; | ||
979 | HullDesc foundDesc = new HullDesc(); | ||
980 | foreach (HullDesc hd in Hulls.Values) | ||
981 | { | ||
982 | if (hd.ptr == addr) | ||
983 | { | ||
984 | foundDesc = hd; | ||
985 | ret = true; | ||
986 | break; | ||
987 | } | ||
988 | |||
989 | } | ||
990 | outDesc = foundDesc; | ||
991 | return ret; | ||
992 | } | ||
993 | |||
994 | private void DetailLog(string msg, params Object[] args) | ||
995 | { | ||
996 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
997 | PhysicsScene.DetailLog(msg, args); | ||
998 | } | ||
999 | } | ||
1000 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs deleted file mode 100755 index 7c34af2..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ /dev/null | |||
@@ -1,479 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework; | ||
33 | using OpenSim.Region.CoreModules; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using Nini.Config; | ||
37 | using log4net; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | public sealed class BSTerrainManager | ||
44 | { | ||
45 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | ||
46 | |||
47 | // These height values are fractional so the odd values will be | ||
48 | // noticable when debugging. | ||
49 | public const float HEIGHT_INITIALIZATION = 24.987f; | ||
50 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | ||
51 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | ||
52 | |||
53 | // If the min and max height are equal, we reduce the min by this | ||
54 | // amount to make sure that a bounding box is built for the terrain. | ||
55 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | ||
56 | |||
57 | public const float TERRAIN_COLLISION_MARGIN = 0.0f; | ||
58 | |||
59 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | ||
60 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
61 | |||
62 | // The scene that I am part of | ||
63 | private BSScene PhysicsScene { get; set; } | ||
64 | |||
65 | // The ground plane created to keep thing from falling to infinity. | ||
66 | private BulletBody m_groundPlane; | ||
67 | |||
68 | // If doing mega-regions, if we're region zero we will be managing multiple | ||
69 | // region terrains since region zero does the physics for the whole mega-region. | ||
70 | private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; | ||
71 | |||
72 | // True of the terrain has been modified. | ||
73 | // Used to force recalculation of terrain height after terrain has been modified | ||
74 | private bool m_terrainModified; | ||
75 | |||
76 | // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. | ||
77 | // This is incremented before assigning to new region so it is the last ID allocated. | ||
78 | private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; | ||
79 | public uint HighestTerrainID { get {return m_terrainCount; } } | ||
80 | |||
81 | // If doing mega-regions, this holds our offset from region zero of | ||
82 | // the mega-regions. "parentScene" points to the PhysicsScene of region zero. | ||
83 | private Vector3 m_worldOffset; | ||
84 | // If the parent region (region 0), this is the extent of the combined regions | ||
85 | // relative to the origin of region zero | ||
86 | private Vector3 m_worldMax; | ||
87 | private PhysicsScene MegaRegionParentPhysicsScene { get; set; } | ||
88 | |||
89 | public BSTerrainManager(BSScene physicsScene) | ||
90 | { | ||
91 | PhysicsScene = physicsScene; | ||
92 | m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); | ||
93 | m_terrainModified = false; | ||
94 | |||
95 | // Assume one region of default size | ||
96 | m_worldOffset = Vector3.Zero; | ||
97 | m_worldMax = new Vector3(DefaultRegionSize); | ||
98 | MegaRegionParentPhysicsScene = null; | ||
99 | } | ||
100 | |||
101 | // Create the initial instance of terrain and the underlying ground plane. | ||
102 | // The objects are allocated in the unmanaged space and the pointers are tracked | ||
103 | // by the managed code. | ||
104 | // The terrains and the groundPlane are not added to the list of PhysObjects. | ||
105 | // This is called from the initialization routine so we presume it is | ||
106 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | ||
107 | public void CreateInitialGroundPlaneAndTerrain() | ||
108 | { | ||
109 | // The ground plane is here to catch things that are trying to drop to negative infinity | ||
110 | BulletShape groundPlaneShape = new BulletShape( | ||
111 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | ||
112 | ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE); | ||
113 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | ||
114 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | ||
115 | Vector3.Zero, Quaternion.Identity)); | ||
116 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
117 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
118 | // Ground plane does not move | ||
119 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | ||
120 | // Everything collides with the ground plane. | ||
121 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | ||
122 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | ||
123 | |||
124 | Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); | ||
125 | Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); | ||
126 | int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; | ||
127 | float[] initialMap = new float[totalHeights]; | ||
128 | for (int ii = 0; ii < totalHeights; ii++) | ||
129 | { | ||
130 | initialMap[ii] = HEIGHT_INITIALIZATION; | ||
131 | } | ||
132 | UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true); | ||
133 | } | ||
134 | |||
135 | // Release all the terrain structures we might have allocated | ||
136 | public void ReleaseGroundPlaneAndTerrain() | ||
137 | { | ||
138 | if (m_groundPlane.ptr != IntPtr.Zero) | ||
139 | { | ||
140 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) | ||
141 | { | ||
142 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
143 | } | ||
144 | m_groundPlane.ptr = IntPtr.Zero; | ||
145 | } | ||
146 | |||
147 | ReleaseTerrain(); | ||
148 | } | ||
149 | |||
150 | // Release all the terrain we have allocated | ||
151 | public void ReleaseTerrain() | ||
152 | { | ||
153 | foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) | ||
154 | { | ||
155 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr)) | ||
156 | { | ||
157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr); | ||
158 | BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr); | ||
159 | } | ||
160 | } | ||
161 | m_heightMaps.Clear(); | ||
162 | } | ||
163 | |||
164 | // The simulator wants to set a new heightmap for the terrain. | ||
165 | public void SetTerrain(float[] heightMap) { | ||
166 | float[] localHeightMap = heightMap; | ||
167 | PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() | ||
168 | { | ||
169 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | ||
170 | { | ||
171 | // If a child of a mega-region, we shouldn't have any terrain allocated for us | ||
172 | ReleaseGroundPlaneAndTerrain(); | ||
173 | // If doing the mega-prim stuff and we are the child of the zero region, | ||
174 | // the terrain is added to our parent | ||
175 | if (MegaRegionParentPhysicsScene is BSScene) | ||
176 | { | ||
177 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", | ||
178 | BSScene.DetailLogZero, m_worldOffset, m_worldMax); | ||
179 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, | ||
180 | localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
181 | } | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | // If not doing the mega-prim thing, just change the terrain | ||
186 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | ||
187 | |||
188 | UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, | ||
189 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
190 | } | ||
191 | }); | ||
192 | } | ||
193 | |||
194 | // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain | ||
195 | // based on the passed information. The 'id' should be either the terrain id or | ||
196 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | ||
197 | // The latter feature is for creating child terrains for mega-regions. | ||
198 | // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0) | ||
199 | // then a new body and shape is created and the mapInfo is filled. | ||
200 | // This call is used for doing the initial terrain creation. | ||
201 | // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new | ||
202 | // terrain shape is created and added to the body. | ||
203 | // This call is most often used to update the heightMap and parameters of the terrain. | ||
204 | // (The above does suggest that some simplification/refactoring is in order.) | ||
205 | private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | ||
206 | { | ||
207 | DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", | ||
208 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); | ||
209 | |||
210 | float minZ = float.MaxValue; | ||
211 | float maxZ = float.MinValue; | ||
212 | Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y); | ||
213 | |||
214 | int heightMapSize = heightMap.Length; | ||
215 | for (int ii = 0; ii < heightMapSize; ii++) | ||
216 | { | ||
217 | float height = heightMap[ii]; | ||
218 | if (height < minZ) minZ = height; | ||
219 | if (height > maxZ) maxZ = height; | ||
220 | } | ||
221 | |||
222 | // The shape of the terrain is from its base to its extents. | ||
223 | minCoords.Z = minZ; | ||
224 | maxCoords.Z = maxZ; | ||
225 | |||
226 | BulletHeightMapInfo mapInfo; | ||
227 | if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) | ||
228 | { | ||
229 | // If this is terrain we know about, it's easy to update | ||
230 | |||
231 | mapInfo.heightMap = heightMap; | ||
232 | mapInfo.minCoords = minCoords; | ||
233 | mapInfo.maxCoords = maxCoords; | ||
234 | mapInfo.minZ = minZ; | ||
235 | mapInfo.maxZ = maxZ; | ||
236 | mapInfo.sizeX = maxCoords.X - minCoords.X; | ||
237 | mapInfo.sizeY = maxCoords.Y - minCoords.Y; | ||
238 | DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", | ||
239 | BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); | ||
240 | |||
241 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate() | ||
242 | { | ||
243 | if (MegaRegionParentPhysicsScene != null) | ||
244 | { | ||
245 | // It's possible that Combine() was called after this code was queued. | ||
246 | // If we are a child of combined regions, we don't create any terrain for us. | ||
247 | DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); | ||
248 | |||
249 | // Get rid of any terrain that may have been allocated for us. | ||
250 | ReleaseGroundPlaneAndTerrain(); | ||
251 | |||
252 | // I hate doing this, but just bail | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | if (mapInfo.terrainBody.ptr != IntPtr.Zero) | ||
257 | { | ||
258 | // Updating an existing terrain. | ||
259 | DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", | ||
260 | BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); | ||
261 | |||
262 | // Remove from the dynamics world because we're going to mangle this object | ||
263 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
264 | |||
265 | // Get rid of the old terrain | ||
266 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
267 | BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr); | ||
268 | mapInfo.Ptr = IntPtr.Zero; | ||
269 | |||
270 | /* | ||
271 | // NOTE: This routine is half here because I can't get the terrain shape replacement | ||
272 | // to work. In the short term, the above three lines completely delete the old | ||
273 | // terrain and the code below recreates one from scratch. | ||
274 | // Hopefully the Bullet community will help me out on this one. | ||
275 | |||
276 | // First, release the old collision shape (there is only one terrain) | ||
277 | BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr); | ||
278 | |||
279 | // Fill the existing height map info with the new location and size information | ||
280 | BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID, | ||
281 | mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); | ||
282 | |||
283 | // Create a terrain shape based on the new info | ||
284 | mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr)); | ||
285 | |||
286 | // Stuff the shape into the existing terrain body | ||
287 | BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr); | ||
288 | */ | ||
289 | } | ||
290 | // else | ||
291 | { | ||
292 | // Creating a new terrain. | ||
293 | DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}", | ||
294 | BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ); | ||
295 | |||
296 | mapInfo.ID = id; | ||
297 | mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, | ||
298 | mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); | ||
299 | |||
300 | // Create the terrain shape from the mapInfo | ||
301 | mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr), | ||
302 | ShapeData.PhysicsShapeType.SHAPE_TERRAIN); | ||
303 | |||
304 | // The terrain object initial position is at the center of the object | ||
305 | Vector3 centerPos; | ||
306 | centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); | ||
307 | centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); | ||
308 | centerPos.Z = minZ + ((maxZ - minZ) / 2f); | ||
309 | |||
310 | mapInfo.terrainBody = new BulletBody(mapInfo.ID, | ||
311 | BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, | ||
312 | id, centerPos, Quaternion.Identity)); | ||
313 | } | ||
314 | |||
315 | // Make sure the entry is in the heightmap table | ||
316 | m_heightMaps[terrainRegionBase] = mapInfo; | ||
317 | |||
318 | // Set current terrain attributes | ||
319 | BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); | ||
320 | BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
321 | BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | ||
322 | BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
323 | |||
324 | // Return the new terrain to the world of physical objects | ||
325 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
326 | |||
327 | // redo its bounding box now that it is in the world | ||
328 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
329 | |||
330 | BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr, | ||
331 | (uint)CollisionFilterGroups.TerrainFilter, | ||
332 | (uint)CollisionFilterGroups.TerrainMask); | ||
333 | |||
334 | // Make sure the new shape is processed. | ||
335 | // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); | ||
336 | // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
337 | BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
338 | |||
339 | m_terrainModified = true; | ||
340 | }); | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | // We don't know about this terrain so either we are creating a new terrain or | ||
345 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
346 | |||
347 | // if this is a child terrain, calculate a unique terrain id | ||
348 | uint newTerrainID = id; | ||
349 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
350 | newTerrainID = ++m_terrainCount; | ||
351 | |||
352 | float[] heightMapX = heightMap; | ||
353 | Vector3 minCoordsX = minCoords; | ||
354 | Vector3 maxCoordsX = maxCoords; | ||
355 | |||
356 | DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | ||
357 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | ||
358 | |||
359 | // Code that must happen at taint-time | ||
360 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate() | ||
361 | { | ||
362 | DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); | ||
363 | // Create a new mapInfo that will be filled with the new info | ||
364 | mapInfo = new BulletHeightMapInfo(id, heightMapX, | ||
365 | BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID, | ||
366 | minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN)); | ||
367 | // Put the unfilled heightmap info into the collection of same | ||
368 | m_heightMaps.Add(terrainRegionBase, mapInfo); | ||
369 | // Build the terrain | ||
370 | UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true); | ||
371 | |||
372 | m_terrainModified = true; | ||
373 | }); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | // Someday we will have complex terrain with caves and tunnels | ||
378 | public float GetTerrainHeightAtXYZ(Vector3 loc) | ||
379 | { | ||
380 | // For the moment, it's flat and convex | ||
381 | return GetTerrainHeightAtXY(loc.X, loc.Y); | ||
382 | } | ||
383 | |||
384 | // Given an X and Y, find the height of the terrain. | ||
385 | // Since we could be handling multiple terrains for a mega-region, | ||
386 | // the base of the region is calcuated assuming all regions are | ||
387 | // the same size and that is the default. | ||
388 | // Once the heightMapInfo is found, we have all the information to | ||
389 | // compute the offset into the array. | ||
390 | private float lastHeightTX = 999999f; | ||
391 | private float lastHeightTY = 999999f; | ||
392 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | ||
393 | private float GetTerrainHeightAtXY(float tX, float tY) | ||
394 | { | ||
395 | // You'd be surprized at the number of times this routine is called | ||
396 | // with the same parameters as last time. | ||
397 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | ||
398 | return lastHeight; | ||
399 | |||
400 | lastHeightTX = tX; | ||
401 | lastHeightTY = tY; | ||
402 | float ret = HEIGHT_GETHEIGHT_RET; | ||
403 | |||
404 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
405 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
406 | Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); | ||
407 | |||
408 | BulletHeightMapInfo mapInfo; | ||
409 | if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo)) | ||
410 | { | ||
411 | float regionX = tX - offsetX; | ||
412 | float regionY = tY - offsetY; | ||
413 | int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX; | ||
414 | try | ||
415 | { | ||
416 | ret = mapInfo.heightMap[mapIndex]; | ||
417 | } | ||
418 | catch | ||
419 | { | ||
420 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
421 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}", | ||
422 | LogHeader, terrainBaseXY, regionX, regionY); | ||
423 | ret = HEIGHT_GETHEIGHT_RET; | ||
424 | } | ||
425 | // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}", | ||
426 | // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret); | ||
427 | } | ||
428 | else | ||
429 | { | ||
430 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | ||
431 | LogHeader, PhysicsScene.RegionName, tX, tY); | ||
432 | } | ||
433 | m_terrainModified = false; | ||
434 | lastHeight = ret; | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | // Although no one seems to check this, I do support combining. | ||
439 | public bool SupportsCombining() | ||
440 | { | ||
441 | return true; | ||
442 | } | ||
443 | |||
444 | // This routine is called two ways: | ||
445 | // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum | ||
446 | // extent of the combined regions. This is to inform the parent of the size | ||
447 | // of the combined regions. | ||
448 | // and one with 'offset' as the offset of the child region to the base region, | ||
449 | // 'pScene' pointing to the parent and 'extents' of zero. This informs the | ||
450 | // child of its relative base and new parent. | ||
451 | public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
452 | { | ||
453 | m_worldOffset = offset; | ||
454 | m_worldMax = extents; | ||
455 | MegaRegionParentPhysicsScene = pScene; | ||
456 | if (pScene != null) | ||
457 | { | ||
458 | // We are a child. | ||
459 | // We want m_worldMax to be the highest coordinate of our piece of terrain. | ||
460 | m_worldMax = offset + DefaultRegionSize; | ||
461 | } | ||
462 | DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", | ||
463 | BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); | ||
464 | } | ||
465 | |||
466 | // Unhook all the combining that I know about. | ||
467 | public void UnCombine(PhysicsScene pScene) | ||
468 | { | ||
469 | // Just like ODE, for the moment a NOP | ||
470 | DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); | ||
471 | } | ||
472 | |||
473 | |||
474 | private void DetailLog(string msg, params Object[] args) | ||
475 | { | ||
476 | PhysicsScene.PhysicsLogging.Write(msg, args); | ||
477 | } | ||
478 | } | ||
479 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 702bd77..504bd3c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -33,153 +33,38 @@ using OpenMetaverse; | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | 33 | namespace OpenSim.Region.Physics.BulletSPlugin { |
34 | 34 | ||
35 | // Classes to allow some type checking for the API | 35 | // Classes to allow some type checking for the API |
36 | // These hold pointers to allocated objects in the unmanaged space. | ||
37 | |||
38 | // The physics engine controller class created at initialization | ||
39 | public struct BulletSim | 36 | public struct BulletSim |
40 | { | 37 | { |
41 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | 38 | public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } |
42 | { | 39 | public uint ID; |
43 | ptr = xx; | ||
44 | worldID = worldId; | ||
45 | physicsScene = bss; | ||
46 | } | ||
47 | public IntPtr ptr; | ||
48 | public uint worldID; | ||
49 | // The scene is only in here so very low level routines have a handle to print debug/error messages | 40 | // The scene is only in here so very low level routines have a handle to print debug/error messages |
50 | public BSScene physicsScene; | 41 | public BSScene scene; |
42 | public IntPtr Ptr; | ||
51 | } | 43 | } |
52 | 44 | ||
53 | // An allocated Bullet btRigidBody | ||
54 | public struct BulletBody | 45 | public struct BulletBody |
55 | { | 46 | { |
56 | public BulletBody(uint id, IntPtr xx) | 47 | public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } |
57 | { | 48 | public IntPtr Ptr; |
58 | ID = id; | ||
59 | ptr = xx; | ||
60 | collisionFilter = 0; | ||
61 | collisionMask = 0; | ||
62 | } | ||
63 | public IntPtr ptr; | ||
64 | public uint ID; | 49 | public uint ID; |
65 | public CollisionFilterGroups collisionFilter; | ||
66 | public CollisionFilterGroups collisionMask; | ||
67 | public override string ToString() | ||
68 | { | ||
69 | StringBuilder buff = new StringBuilder(); | ||
70 | buff.Append("<id="); | ||
71 | buff.Append(ID.ToString()); | ||
72 | buff.Append(",p="); | ||
73 | buff.Append(ptr.ToString("X")); | ||
74 | if (collisionFilter != 0 || collisionMask != 0) | ||
75 | { | ||
76 | buff.Append(",f="); | ||
77 | buff.Append(collisionFilter.ToString("X")); | ||
78 | buff.Append(",m="); | ||
79 | buff.Append(collisionMask.ToString("X")); | ||
80 | } | ||
81 | buff.Append(">"); | ||
82 | return buff.ToString(); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public struct BulletShape | ||
87 | { | ||
88 | public BulletShape(IntPtr xx) | ||
89 | { | ||
90 | ptr = xx; | ||
91 | type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
92 | shapeKey = 0; | ||
93 | isNativeShape = false; | ||
94 | } | ||
95 | public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ) | ||
96 | { | ||
97 | ptr = xx; | ||
98 | type = typ; | ||
99 | shapeKey = 0; | ||
100 | isNativeShape = false; | ||
101 | } | ||
102 | public IntPtr ptr; | ||
103 | public ShapeData.PhysicsShapeType type; | ||
104 | public System.UInt64 shapeKey; | ||
105 | public bool isNativeShape; | ||
106 | public override string ToString() | ||
107 | { | ||
108 | StringBuilder buff = new StringBuilder(); | ||
109 | buff.Append("<p="); | ||
110 | buff.Append(ptr.ToString("X")); | ||
111 | buff.Append(",s="); | ||
112 | buff.Append(type.ToString()); | ||
113 | buff.Append(",k="); | ||
114 | buff.Append(shapeKey.ToString("X")); | ||
115 | buff.Append(",n="); | ||
116 | buff.Append(isNativeShape.ToString()); | ||
117 | buff.Append(">"); | ||
118 | return buff.ToString(); | ||
119 | } | ||
120 | } | 50 | } |
121 | 51 | ||
122 | // Constraint type values as defined by Bullet | ||
123 | public enum ConstraintType : int | ||
124 | { | ||
125 | POINT2POINT_CONSTRAINT_TYPE = 3, | ||
126 | HINGE_CONSTRAINT_TYPE, | ||
127 | CONETWIST_CONSTRAINT_TYPE, | ||
128 | D6_CONSTRAINT_TYPE, | ||
129 | SLIDER_CONSTRAINT_TYPE, | ||
130 | CONTACT_CONSTRAINT_TYPE, | ||
131 | D6_SPRING_CONSTRAINT_TYPE, | ||
132 | MAX_CONSTRAINT_TYPE | ||
133 | } | ||
134 | |||
135 | // An allocated Bullet btConstraint | ||
136 | public struct BulletConstraint | 52 | public struct BulletConstraint |
137 | { | 53 | { |
138 | public BulletConstraint(IntPtr xx) | 54 | public BulletConstraint(IntPtr xx) { Ptr = xx; } |
139 | { | ||
140 | ptr = xx; | ||
141 | } | ||
142 | public IntPtr ptr; | ||
143 | } | ||
144 | |||
145 | // An allocated HeightMapThing which holds various heightmap info. | ||
146 | // Made a class rather than a struct so there would be only one | ||
147 | // instance of this and C# will pass around pointers rather | ||
148 | // than making copies. | ||
149 | public class BulletHeightMapInfo | ||
150 | { | ||
151 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
152 | ID = id; | ||
153 | Ptr = xx; | ||
154 | heightMap = hm; | ||
155 | terrainRegionBase = new Vector2(0f, 0f); | ||
156 | minCoords = new Vector3(100f, 100f, 25f); | ||
157 | maxCoords = new Vector3(101f, 101f, 26f); | ||
158 | minZ = maxZ = 0f; | ||
159 | sizeX = sizeY = 256f; | ||
160 | } | ||
161 | public uint ID; | ||
162 | public IntPtr Ptr; | 55 | public IntPtr Ptr; |
163 | public float[] heightMap; | ||
164 | public Vector2 terrainRegionBase; | ||
165 | public Vector3 minCoords; | ||
166 | public Vector3 maxCoords; | ||
167 | public float sizeX, sizeY; | ||
168 | public float minZ, maxZ; | ||
169 | public BulletShape terrainShape; | ||
170 | public BulletBody terrainBody; | ||
171 | } | 56 | } |
172 | 57 | ||
173 | // =============================================================================== | 58 | // =============================================================================== |
174 | [StructLayout(LayoutKind.Sequential)] | 59 | [StructLayout(LayoutKind.Sequential)] |
175 | public struct ConvexHull | 60 | public struct ConvexHull |
176 | { | 61 | { |
177 | Vector3 Offset; | 62 | Vector3 Offset; |
178 | int VertexCount; | 63 | int VertexCount; |
179 | Vector3[] Vertices; | 64 | Vector3[] Vertices; |
180 | } | 65 | } |
181 | [StructLayout(LayoutKind.Sequential)] | 66 | [StructLayout(LayoutKind.Sequential)] |
182 | public struct ShapeData | 67 | public struct ShapeData |
183 | { | 68 | { |
184 | public enum PhysicsShapeType | 69 | public enum PhysicsShapeType |
185 | { | 70 | { |
@@ -190,11 +75,7 @@ public struct ShapeData | |||
190 | SHAPE_CYLINDER = 4, | 75 | SHAPE_CYLINDER = 4, |
191 | SHAPE_SPHERE = 5, | 76 | SHAPE_SPHERE = 5, |
192 | SHAPE_MESH = 6, | 77 | SHAPE_MESH = 6, |
193 | SHAPE_HULL = 7, | 78 | SHAPE_HULL = 7 |
194 | // following defined by BulletSim | ||
195 | SHAPE_GROUNDPLANE = 20, | ||
196 | SHAPE_TERRAIN = 21, | ||
197 | SHAPE_COMPOUND = 22, | ||
198 | }; | 79 | }; |
199 | public uint ID; | 80 | public uint ID; |
200 | public PhysicsShapeType Type; | 81 | public PhysicsShapeType Type; |
@@ -210,25 +91,13 @@ public struct ShapeData | |||
210 | public float Restitution; | 91 | public float Restitution; |
211 | public float Collidable; // true of things bump into this | 92 | public float Collidable; // true of things bump into this |
212 | public float Static; // true if a static object. Otherwise gravity, etc. | 93 | public float Static; // true if a static object. Otherwise gravity, etc. |
213 | public float Solid; // true if object cannot be passed through | ||
214 | public Vector3 Size; | ||
215 | 94 | ||
216 | // note that bools are passed as floats since bool size changes by language and architecture | 95 | // note that bools are passed as floats since bool size changes by language and architecture |
217 | public const float numericTrue = 1f; | 96 | public const float numericTrue = 1f; |
218 | public const float numericFalse = 0f; | 97 | public const float numericFalse = 0f; |
219 | |||
220 | // The native shapes have predefined shape hash keys | ||
221 | public enum FixedShapeKey : ulong | ||
222 | { | ||
223 | KEY_BOX = 1, | ||
224 | KEY_SPHERE = 2, | ||
225 | KEY_CONE = 3, | ||
226 | KEY_CYLINDER = 4, | ||
227 | KEY_CAPSULE = 5, | ||
228 | } | ||
229 | } | 98 | } |
230 | [StructLayout(LayoutKind.Sequential)] | 99 | [StructLayout(LayoutKind.Sequential)] |
231 | public struct SweepHit | 100 | public struct SweepHit |
232 | { | 101 | { |
233 | public uint ID; | 102 | public uint ID; |
234 | public float Fraction; | 103 | public float Fraction; |
@@ -284,7 +153,6 @@ public struct ConfigurationParameters | |||
284 | public float terrainHitFraction; | 153 | public float terrainHitFraction; |
285 | public float terrainRestitution; | 154 | public float terrainRestitution; |
286 | public float avatarFriction; | 155 | public float avatarFriction; |
287 | public float avatarStandingFriction; | ||
288 | public float avatarDensity; | 156 | public float avatarDensity; |
289 | public float avatarRestitution; | 157 | public float avatarRestitution; |
290 | public float avatarCapsuleRadius; | 158 | public float avatarCapsuleRadius; |
@@ -300,45 +168,18 @@ public struct ConfigurationParameters | |||
300 | public float shouldEnableFrictionCaching; | 168 | public float shouldEnableFrictionCaching; |
301 | public float numberOfSolverIterations; | 169 | public float numberOfSolverIterations; |
302 | 170 | ||
303 | public float linksetImplementation; | ||
304 | public float linkConstraintUseFrameOffset; | 171 | public float linkConstraintUseFrameOffset; |
305 | public float linkConstraintEnableTransMotor; | 172 | public float linkConstraintEnableTransMotor; |
306 | public float linkConstraintTransMotorMaxVel; | 173 | public float linkConstraintTransMotorMaxVel; |
307 | public float linkConstraintTransMotorMaxForce; | 174 | public float linkConstraintTransMotorMaxForce; |
308 | public float linkConstraintERP; | 175 | public float linkConstraintERP; |
309 | public float linkConstraintCFM; | 176 | public float linkConstraintCFM; |
310 | public float linkConstraintSolverIterations; | ||
311 | |||
312 | public float physicsLoggingFrames; | ||
313 | 177 | ||
314 | public const float numericTrue = 1f; | 178 | public const float numericTrue = 1f; |
315 | public const float numericFalse = 0f; | 179 | public const float numericFalse = 0f; |
316 | } | 180 | } |
317 | 181 | ||
318 | 182 | // Values used by Bullet and BulletSim to control collisions | |
319 | // The states a bullet collision object can have | ||
320 | public enum ActivationState : uint | ||
321 | { | ||
322 | ACTIVE_TAG = 1, | ||
323 | ISLAND_SLEEPING, | ||
324 | WANTS_DEACTIVATION, | ||
325 | DISABLE_DEACTIVATION, | ||
326 | DISABLE_SIMULATION, | ||
327 | } | ||
328 | |||
329 | public enum CollisionObjectTypes : int | ||
330 | { | ||
331 | CO_COLLISION_OBJECT = 1 << 0, | ||
332 | CO_RIGID_BODY = 1 << 1, | ||
333 | CO_GHOST_OBJECT = 1 << 2, | ||
334 | CO_SOFT_BODY = 1 << 3, | ||
335 | CO_HF_FLUID = 1 << 4, | ||
336 | CO_USER_TYPE = 1 << 5, | ||
337 | } | ||
338 | |||
339 | // Values used by Bullet and BulletSim to control object properties. | ||
340 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
341 | // object (if collisions happen, if gravity effects it, ...). | ||
342 | public enum CollisionFlags : uint | 183 | public enum CollisionFlags : uint |
343 | { | 184 | { |
344 | CF_STATIC_OBJECT = 1 << 0, | 185 | CF_STATIC_OBJECT = 1 << 0, |
@@ -350,54 +191,9 @@ public enum CollisionFlags : uint | |||
350 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | 191 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, |
351 | // Following used by BulletSim to control collisions | 192 | // Following used by BulletSim to control collisions |
352 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | 193 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, |
353 | BS_FLOATS_ON_WATER = 1 << 11, | 194 | BS_VOLUME_DETECT_OBJECT = 1 << 11, |
354 | BS_NONE = 0, | 195 | BS_PHANTOM_OBJECT = 1 << 12, |
355 | BS_ALL = 0xFFFFFFFF, | 196 | BS_PHYSICAL_OBJECT = 1 << 13, |
356 | |||
357 | // These are the collision flags switched depending on physical state. | ||
358 | // The other flags are used for other things and should not be fooled with. | ||
359 | BS_ACTIVE = CF_STATIC_OBJECT | ||
360 | | CF_KINEMATIC_OBJECT | ||
361 | | CF_NO_CONTACT_RESPONSE | ||
362 | }; | ||
363 | |||
364 | // Values for collisions groups and masks | ||
365 | public enum CollisionFilterGroups : uint | ||
366 | { | ||
367 | // Don't use the bit definitions!! Define the use in a | ||
368 | // filter/mask definition below. This way collision interactions | ||
369 | // are more easily debugged. | ||
370 | BNoneFilter = 0, | ||
371 | BDefaultFilter = 1 << 0, | ||
372 | BStaticFilter = 1 << 1, | ||
373 | BKinematicFilter = 1 << 2, | ||
374 | BDebrisFilter = 1 << 3, | ||
375 | BSensorTrigger = 1 << 4, | ||
376 | BCharacterFilter = 1 << 5, | ||
377 | BAllFilter = 0xFFFFFFFF, | ||
378 | // Filter groups defined by BulletSim | ||
379 | BGroundPlaneFilter = 1 << 10, | ||
380 | BTerrainFilter = 1 << 11, | ||
381 | BRaycastFilter = 1 << 12, | ||
382 | BSolidFilter = 1 << 13, | ||
383 | BLinksetFilter = 1 << 14, | ||
384 | |||
385 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
386 | AvatarFilter = BCharacterFilter, | ||
387 | AvatarMask = BAllFilter, | ||
388 | ObjectFilter = BSolidFilter, | ||
389 | ObjectMask = BAllFilter, | ||
390 | StaticObjectFilter = BStaticFilter, | ||
391 | StaticObjectMask = BAllFilter, | ||
392 | LinksetFilter = BLinksetFilter, | ||
393 | LinksetMask = BAllFilter & ~BLinksetFilter, | ||
394 | VolumeDetectFilter = BSensorTrigger, | ||
395 | VolumeDetectMask = ~BSensorTrigger, | ||
396 | TerrainFilter = BTerrainFilter, | ||
397 | TerrainMask = BAllFilter & ~BStaticFilter, | ||
398 | GroundPlaneFilter = BGroundPlaneFilter, | ||
399 | GroundPlaneMask = BAllFilter | ||
400 | |||
401 | }; | 197 | }; |
402 | 198 | ||
403 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | 199 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 |
@@ -425,23 +221,14 @@ public enum ConstraintParamAxis : int | |||
425 | // =============================================================================== | 221 | // =============================================================================== |
426 | static class BulletSimAPI { | 222 | static class BulletSimAPI { |
427 | 223 | ||
428 | // Link back to the managed code for outputting log messages | ||
429 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
430 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
431 | |||
432 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 224 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
433 | [return: MarshalAs(UnmanagedType.LPStr)] | 225 | [return: MarshalAs(UnmanagedType.LPStr)] |
434 | public static extern string GetVersion(); | 226 | public static extern string GetVersion(); |
435 | 227 | ||
436 | /* Remove the linkage to the old api methods | ||
437 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 228 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
438 | public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, | 229 | public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, |
439 | int maxCollisions, IntPtr collisionArray, | 230 | int maxCollisions, IntPtr collisionArray, |
440 | int maxUpdates, IntPtr updateArray, | 231 | int maxUpdates, IntPtr updateArray); |
441 | DebugLogCallback logRoutine); | ||
442 | |||
443 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
444 | public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID); | ||
445 | 232 | ||
446 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 233 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
447 | public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); | 234 | public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); |
@@ -455,19 +242,19 @@ public static extern bool UpdateParameter(uint worldID, uint localID, | |||
455 | 242 | ||
456 | // =============================================================================== | 243 | // =============================================================================== |
457 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 244 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
458 | public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, | 245 | public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, |
459 | out int updatedEntityCount, | 246 | out int updatedEntityCount, |
460 | out IntPtr updatedEntitiesPtr, | 247 | out IntPtr updatedEntitiesPtr, |
461 | out int collidersCount, | 248 | out int collidersCount, |
462 | out IntPtr collidersPtr); | 249 | out IntPtr collidersPtr); |
463 | 250 | ||
464 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 251 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
465 | public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, | 252 | public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, |
466 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls | 253 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls |
467 | ); | 254 | ); |
468 | 255 | ||
469 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 256 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
470 | public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, | 257 | public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, |
471 | int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | 258 | int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, |
472 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices | 259 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices |
473 | ); | 260 | ); |
@@ -481,6 +268,23 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey); | |||
481 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 268 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
482 | public static extern bool CreateObject(uint worldID, ShapeData shapeData); | 269 | public static extern bool CreateObject(uint worldID, ShapeData shapeData); |
483 | 270 | ||
271 | /* Remove old functionality | ||
272 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
273 | public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); | ||
274 | |||
275 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
276 | public static extern void AddConstraint(uint worldID, uint id1, uint id2, | ||
277 | Vector3 frame1, Quaternion frame1rot, | ||
278 | Vector3 frame2, Quaternion frame2rot, | ||
279 | Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); | ||
280 | |||
281 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
282 | public static extern bool RemoveConstraintByID(uint worldID, uint id1); | ||
283 | |||
284 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
285 | public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); | ||
286 | */ | ||
287 | |||
484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 288 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
485 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); | 289 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); |
486 | 290 | ||
@@ -496,7 +300,6 @@ public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 veloc | |||
496 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 300 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
497 | public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); | 301 | public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); |
498 | 302 | ||
499 | // Set the current force acting on the object | ||
500 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 303 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
501 | public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); | 304 | public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); |
502 | 305 | ||
@@ -537,8 +340,10 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); | |||
537 | // =============================================================================== | 340 | // =============================================================================== |
538 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 341 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
539 | public static extern void DumpBulletStatistics(); | 342 | public static extern void DumpBulletStatistics(); |
540 | */ | 343 | |
541 | // Log a debug message | 344 | // Log a debug message |
345 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
346 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
542 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 347 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
543 | public static extern void SetDebugLogCallback(DebugLogCallback callback); | 348 | public static extern void SetDebugLogCallback(DebugLogCallback callback); |
544 | 349 | ||
@@ -553,7 +358,6 @@ public static extern void SetDebugLogCallback(DebugLogCallback callback); | |||
553 | // The names have a "2" tacked on. This will be removed as the C# code gets rebuilt | 358 | // The names have a "2" tacked on. This will be removed as the C# code gets rebuilt |
554 | // and the old code is removed. | 359 | // and the old code is removed. |
555 | 360 | ||
556 | // Functions use while converting from API1 to API2. Can be removed when totally converted. | ||
557 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 361 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
558 | public static extern IntPtr GetSimHandle2(uint worldID); | 362 | public static extern IntPtr GetSimHandle2(uint worldID); |
559 | 363 | ||
@@ -564,25 +368,23 @@ public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id); | |||
564 | public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); | 368 | public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); |
565 | 369 | ||
566 | // =============================================================================== | 370 | // =============================================================================== |
567 | // Initialization and simulation | ||
568 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 371 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
569 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | 372 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, |
570 | int maxCollisions, IntPtr collisionArray, | 373 | int maxCollisions, IntPtr collisionArray, |
571 | int maxUpdates, IntPtr updateArray, | 374 | int maxUpdates, IntPtr updateArray); |
572 | DebugLogCallback logRoutine); | ||
573 | 375 | ||
574 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 376 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
575 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | 377 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); |
576 | 378 | ||
577 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 379 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
578 | public static extern void SetHeightMap2(IntPtr world, float[] heightmap); | 380 | public static extern void SetHeightmap2(IntPtr world, float[] heightmap); |
579 | 381 | ||
580 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 382 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
581 | public static extern void Shutdown2(IntPtr sim); | 383 | public static extern void Shutdown2(IntPtr sim); |
582 | 384 | ||
583 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 385 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
584 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, | 386 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, |
585 | out int updatedEntityCount, | 387 | out int updatedEntityCount, |
586 | out IntPtr updatedEntitiesPtr, | 388 | out IntPtr updatedEntitiesPtr, |
587 | out int collidersCount, | 389 | out int collidersCount, |
588 | out IntPtr collidersPtr); | 390 | out IntPtr collidersPtr); |
@@ -590,98 +392,23 @@ public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSt | |||
590 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 392 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
591 | public static extern bool PushUpdate2(IntPtr obj); | 393 | public static extern bool PushUpdate2(IntPtr obj); |
592 | 394 | ||
593 | // ===================================================================================== | 395 | /* |
594 | // Mesh, hull, shape and body creation helper routines | ||
595 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
596 | public static extern IntPtr CreateMeshShape2(IntPtr world, | ||
597 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
598 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
599 | |||
600 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
601 | public static extern IntPtr CreateHullShape2(IntPtr world, | ||
602 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | ||
603 | |||
604 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
605 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
606 | |||
607 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
608 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | ||
609 | |||
610 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
611 | public static extern bool IsNativeShape2(IntPtr shape); | ||
612 | |||
613 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
614 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
615 | |||
616 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
617 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); | ||
618 | |||
619 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
620 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
621 | |||
622 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
623 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
624 | |||
625 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
626 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
627 | |||
628 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
629 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
630 | |||
631 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
632 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | ||
633 | |||
634 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
635 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | ||
636 | |||
637 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
638 | public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo); | ||
639 | |||
640 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
641 | public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); | ||
642 | |||
643 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
644 | public static extern int GetBodyType2(IntPtr obj); | ||
645 | |||
646 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
647 | public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
648 | |||
649 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
650 | public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
651 | |||
652 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
653 | public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
654 | |||
655 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
656 | public static extern IntPtr AllocateBodyInfo2(IntPtr obj); | ||
657 | |||
658 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
659 | public static extern void ReleaseBodyInfo2(IntPtr obj); | ||
660 | |||
661 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
662 | public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | ||
663 | |||
664 | // ===================================================================================== | ||
665 | // Terrain creation and helper routines | ||
666 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 396 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
667 | public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords, | 397 | public static extern IntPtr CreateMesh2(IntPtr world, int indicesCount, int* indices, int verticesCount, float* vertices ); |
668 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); | ||
669 | 398 | ||
670 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 399 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
671 | public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords, | 400 | public static extern bool BuildHull2(IntPtr world, IntPtr mesh); |
672 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); | ||
673 | 401 | ||
674 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 402 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
675 | public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo); | 403 | public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh); |
676 | 404 | ||
677 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 405 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
678 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | 406 | public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh); |
679 | 407 | ||
680 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 408 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
681 | public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo); | 409 | public static extern IntPtr CreateObject2(IntPtr world, ShapeData shapeData); |
410 | */ | ||
682 | 411 | ||
683 | // ===================================================================================== | ||
684 | // Constraint creation and helper routines | ||
685 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 412 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
686 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | 413 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, |
687 | Vector3 frame1loc, Quaternion frame1rot, | 414 | Vector3 frame1loc, Quaternion frame1rot, |
@@ -706,7 +433,7 @@ public static extern void SetConstraintEnable2(IntPtr constrain, float numericTr | |||
706 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); | 433 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); |
707 | 434 | ||
708 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 435 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
709 | public static extern bool SetFrames2(IntPtr constrain, | 436 | public static extern bool SetFrames2(IntPtr constrain, |
710 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | 437 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); |
711 | 438 | ||
712 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 439 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -733,108 +460,11 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams | |||
733 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 460 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
734 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); | 461 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); |
735 | 462 | ||
736 | // ===================================================================================== | ||
737 | // btCollisionWorld entries | ||
738 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 463 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
739 | public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); | 464 | public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); |
740 | 465 | ||
741 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 466 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
742 | public static extern void UpdateAabbs2(IntPtr world); | 467 | public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); |
743 | |||
744 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
745 | public static extern bool GetForceUpdateAllAabbs2(IntPtr world); | ||
746 | |||
747 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
748 | public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); | ||
749 | |||
750 | // ===================================================================================== | ||
751 | // btDynamicsWorld entries | ||
752 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
753 | public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); | ||
754 | |||
755 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
756 | public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); | ||
757 | |||
758 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
759 | public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); | ||
760 | |||
761 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
762 | public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); | ||
763 | // ===================================================================================== | ||
764 | // btCollisionObject entries | ||
765 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
766 | public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); | ||
767 | |||
768 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
769 | public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); | ||
770 | |||
771 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
772 | public static extern bool HasAnisotripicFriction2(IntPtr constrain); | ||
773 | |||
774 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
775 | public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); | ||
776 | |||
777 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
778 | public static extern float GetContactProcessingThreshold2(IntPtr obj); | ||
779 | |||
780 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
781 | public static extern bool IsStaticObject2(IntPtr obj); | ||
782 | |||
783 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
784 | public static extern bool IsKinematicObject2(IntPtr obj); | ||
785 | |||
786 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
787 | public static extern bool IsStaticOrKinematicObject2(IntPtr obj); | ||
788 | |||
789 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
790 | public static extern bool HasContactResponse2(IntPtr obj); | ||
791 | |||
792 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
793 | public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); | ||
794 | |||
795 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
796 | public static extern IntPtr GetCollisionShape2(IntPtr obj); | ||
797 | |||
798 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
799 | public static extern int GetActivationState2(IntPtr obj); | ||
800 | |||
801 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
802 | public static extern void SetActivationState2(IntPtr obj, int state); | ||
803 | |||
804 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
805 | public static extern void SetDeactivationTime2(IntPtr obj, float dtime); | ||
806 | |||
807 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
808 | public static extern float GetDeactivationTime2(IntPtr obj); | ||
809 | |||
810 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
811 | public static extern void ForceActivationState2(IntPtr obj, ActivationState state); | ||
812 | |||
813 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
814 | public static extern void Activate2(IntPtr obj, bool forceActivation); | ||
815 | |||
816 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
817 | public static extern bool IsActive2(IntPtr obj); | ||
818 | |||
819 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
820 | public static extern void SetRestitution2(IntPtr obj, float val); | ||
821 | |||
822 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
823 | public static extern float GetRestitution2(IntPtr obj); | ||
824 | |||
825 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
826 | public static extern void SetFriction2(IntPtr obj, float val); | ||
827 | |||
828 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
829 | public static extern float GetFriction2(IntPtr obj); | ||
830 | |||
831 | /* Haven't defined the type 'Transform' | ||
832 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
833 | public static extern Transform GetWorldTransform2(IntPtr obj); | ||
834 | |||
835 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
836 | public static extern void setWorldTransform2(IntPtr obj, Transform trans); | ||
837 | */ | ||
838 | 468 | ||
839 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 469 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
840 | public static extern Vector3 GetPosition2(IntPtr obj); | 470 | public static extern Vector3 GetPosition2(IntPtr obj); |
@@ -843,290 +473,85 @@ public static extern Vector3 GetPosition2(IntPtr obj); | |||
843 | public static extern Quaternion GetOrientation2(IntPtr obj); | 473 | public static extern Quaternion GetOrientation2(IntPtr obj); |
844 | 474 | ||
845 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 475 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
846 | public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); | 476 | public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); |
847 | |||
848 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
849 | public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); | ||
850 | |||
851 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
852 | public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); | ||
853 | |||
854 | /* | ||
855 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
856 | public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); | ||
857 | |||
858 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
859 | public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); | ||
860 | */ | ||
861 | |||
862 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
863 | public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); | ||
864 | |||
865 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
866 | public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); | ||
867 | |||
868 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
869 | public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); | ||
870 | |||
871 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
872 | public static extern float GetHitFraction2(IntPtr obj); | ||
873 | |||
874 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
875 | public static extern void SetHitFraction2(IntPtr obj, float val); | ||
876 | |||
877 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
878 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); | ||
879 | |||
880 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
881 | public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
882 | |||
883 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
884 | public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
885 | |||
886 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
887 | public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
888 | |||
889 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
890 | public static extern float GetCcdMotionThreshold2(IntPtr obj); | ||
891 | |||
892 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
893 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | ||
894 | |||
895 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
896 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); | ||
897 | |||
898 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
899 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); | ||
900 | |||
901 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
902 | public static extern IntPtr GetUserPointer2(IntPtr obj); | ||
903 | |||
904 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
905 | public static extern void SetUserPointer2(IntPtr obj, IntPtr val); | ||
906 | |||
907 | // ===================================================================================== | ||
908 | // btRigidBody entries | ||
909 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
910 | public static extern void ApplyGravity2(IntPtr obj); | ||
911 | |||
912 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
913 | public static extern void SetGravity2(IntPtr obj, Vector3 val); | ||
914 | |||
915 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
916 | public static extern Vector3 GetGravity2(IntPtr obj); | ||
917 | |||
918 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
919 | public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); | ||
920 | |||
921 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
922 | public static extern float GetLinearDamping2(IntPtr obj); | ||
923 | |||
924 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
925 | public static extern float GetAngularDamping2(IntPtr obj); | ||
926 | |||
927 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
928 | public static extern float GetLinearSleepingThreshold2(IntPtr obj); | ||
929 | |||
930 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
931 | public static extern float GetAngularSleepingThreshold2(IntPtr obj); | ||
932 | |||
933 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
934 | public static extern void ApplyDamping2(IntPtr obj, float timeStep); | ||
935 | |||
936 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
937 | public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); | ||
938 | |||
939 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
940 | public static extern Vector3 GetLinearFactor2(IntPtr obj); | ||
941 | |||
942 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
943 | public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); | ||
944 | |||
945 | /* | ||
946 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
947 | public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); | ||
948 | */ | ||
949 | |||
950 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
951 | public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); | ||
952 | |||
953 | // Add a force to the object as if its mass is one. | ||
954 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
955 | public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); | ||
956 | |||
957 | // Set the force being applied to the object as if its mass is one. | ||
958 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
959 | public static extern void SetObjectForce2(IntPtr obj, Vector3 force); | ||
960 | |||
961 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
962 | public static extern Vector3 GetTotalForce2(IntPtr obj); | ||
963 | |||
964 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
965 | public static extern Vector3 GetTotalTorque2(IntPtr obj); | ||
966 | |||
967 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
968 | public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); | ||
969 | |||
970 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
971 | public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); | ||
972 | |||
973 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
974 | public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); | ||
975 | |||
976 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
977 | public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); | ||
978 | 477 | ||
979 | // Apply force at the given point. Will add torque to the object. | ||
980 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
981 | public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); | 479 | public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity); |
982 | 480 | ||
983 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
984 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 481 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
985 | public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); | 482 | public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); |
986 | 483 | ||
987 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
988 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
989 | public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); | 485 | public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); |
990 | 486 | ||
991 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
992 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
993 | public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); | 488 | public static extern bool AddObjectForce2(IntPtr obj, Vector3 force); |
994 | 489 | ||
995 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 490 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
996 | public static extern void ClearForces2(IntPtr obj); | 491 | public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); |
997 | 492 | ||
998 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 493 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
999 | public static extern void ClearAllForces2(IntPtr obj); | 494 | public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val); |
1000 | 495 | ||
1001 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 496 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1002 | public static extern void UpdateInertiaTensor2(IntPtr obj); | 497 | public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping); |
1003 | 498 | ||
1004 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 499 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1005 | public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); | 500 | public static extern bool SetDeactivationTime2(IntPtr obj, float val); |
1006 | 501 | ||
1007 | /* | ||
1008 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 502 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1009 | public static extern Transform GetCenterOfMassTransform2(IntPtr obj); | 503 | public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); |
1010 | */ | ||
1011 | 504 | ||
1012 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 505 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1013 | public static extern Vector3 GetLinearVelocity2(IntPtr obj); | 506 | public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); |
1014 | 507 | ||
1015 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 508 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1016 | public static extern Vector3 GetAngularVelocity2(IntPtr obj); | 509 | public static extern bool SetFriction2(IntPtr obj, float val); |
1017 | 510 | ||
1018 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 511 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1019 | public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); | 512 | public static extern bool SetRestitution2(IntPtr obj, float val); |
1020 | 513 | ||
1021 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 514 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1022 | public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); | 515 | public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val); |
1023 | 516 | ||
1024 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 517 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1025 | public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); | 518 | public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); |
1026 | 519 | ||
1027 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 520 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1028 | public static extern void Translate2(IntPtr obj, Vector3 trans); | 521 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); |
1029 | |||
1030 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1031 | public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); | ||
1032 | |||
1033 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1034 | public static extern bool WantsSleeping2(IntPtr obj); | ||
1035 | |||
1036 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1037 | public static extern void SetAngularFactor2(IntPtr obj, float factor); | ||
1038 | |||
1039 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1040 | public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); | ||
1041 | |||
1042 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1043 | public static extern Vector3 GetAngularFactor2(IntPtr obj); | ||
1044 | |||
1045 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1046 | public static extern bool IsInWorld2(IntPtr obj); | ||
1047 | |||
1048 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1049 | public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); | ||
1050 | |||
1051 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1052 | public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); | ||
1053 | |||
1054 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1055 | public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | ||
1056 | |||
1057 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1058 | public static extern int GetNumConstraintRefs2(IntPtr obj); | ||
1059 | |||
1060 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1061 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | ||
1062 | |||
1063 | // ===================================================================================== | ||
1064 | // btCollisionShape entries | ||
1065 | |||
1066 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1067 | public static extern float GetAngularMotionDisc2(IntPtr shape); | ||
1068 | |||
1069 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1070 | public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); | ||
1071 | |||
1072 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1073 | public static extern bool IsPolyhedral2(IntPtr shape); | ||
1074 | |||
1075 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1076 | public static extern bool IsConvex2d2(IntPtr shape); | ||
1077 | |||
1078 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1079 | public static extern bool IsConvex2(IntPtr shape); | ||
1080 | |||
1081 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1082 | public static extern bool IsNonMoving2(IntPtr shape); | ||
1083 | |||
1084 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1085 | public static extern bool IsConcave2(IntPtr shape); | ||
1086 | |||
1087 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1088 | public static extern bool IsCompound2(IntPtr shape); | ||
1089 | |||
1090 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1091 | public static extern bool IsSoftBody2(IntPtr shape); | ||
1092 | |||
1093 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1094 | public static extern bool IsInfinite2(IntPtr shape); | ||
1095 | 522 | ||
1096 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 523 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1097 | public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); | 524 | public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags); |
1098 | 525 | ||
1099 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 526 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1100 | public static extern Vector3 GetLocalScaling2(IntPtr shape); | 527 | public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); |
1101 | 528 | ||
1102 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 529 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1103 | public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); | 530 | public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); |
1104 | 531 | ||
1105 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 532 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1106 | public static extern int GetShapeType2(IntPtr shape); | 533 | public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); |
1107 | 534 | ||
1108 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 535 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1109 | public static extern void SetMargin2(IntPtr shape, float val); | 536 | public static extern bool UpdateInertiaTensor2(IntPtr obj); |
1110 | 537 | ||
1111 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 538 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1112 | public static extern float GetMargin2(IntPtr shape); | 539 | public static extern bool SetGravity2(IntPtr obj, Vector3 val); |
1113 | 540 | ||
1114 | // ===================================================================================== | ||
1115 | // Debugging | ||
1116 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 541 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1117 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | 542 | public static extern IntPtr ClearForces2(IntPtr obj); |
1118 | 543 | ||
1119 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 544 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1120 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | 545 | public static extern IntPtr ClearAllForces2(IntPtr obj); |
1121 | 546 | ||
1122 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 547 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1123 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | 548 | public static extern bool SetMargin2(IntPtr obj, float val); |
1124 | 549 | ||
1125 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 550 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1126 | public static extern void DumpAllInfo2(IntPtr sim); | 551 | public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); |
1127 | 552 | ||
1128 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 553 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1129 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | 554 | public static extern bool DestroyObject2(IntPtr world, uint id); |
1130 | 555 | ||
1131 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 556 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1132 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | 557 | public static extern void DumpPhysicsStatistics2(IntPtr sim); |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 5af6373..14f65b8 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs | |||
@@ -340,12 +340,6 @@ namespace OpenSim.Region.Physics.Manager | |||
340 | /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, | 340 | /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, |
341 | /// time to accelerate and collisions. | 341 | /// time to accelerate and collisions. |
342 | /// </remarks> | 342 | /// </remarks> |
343 | public virtual Vector3 TargetVelocity | ||
344 | { | ||
345 | get { return Velocity; } | ||
346 | set { Velocity = value; } | ||
347 | } | ||
348 | |||
349 | public abstract Vector3 Velocity { get; set; } | 343 | public abstract Vector3 Velocity { get; set; } |
350 | 344 | ||
351 | public abstract Vector3 Torque { get; set; } | 345 | public abstract Vector3 Torque { get; set; } |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index c736557..f3b0630 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | |||
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
100 | private bool m_hackSentFly = false; | 100 | private bool m_hackSentFly = false; |
101 | private int m_requestedUpdateFrequency = 0; | 101 | private int m_requestedUpdateFrequency = 0; |
102 | private Vector3 m_taintPosition; | 102 | private Vector3 m_taintPosition; |
103 | internal bool m_avatarplanted = false; | 103 | |
104 | /// <summary> | 104 | /// <summary> |
105 | /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force | 105 | /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force |
106 | /// while calculatios are going on | 106 | /// while calculatios are going on |
@@ -413,7 +413,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
413 | set | 413 | set |
414 | { | 414 | { |
415 | m_iscollidingObj = value; | 415 | m_iscollidingObj = value; |
416 | if (value && !m_avatarplanted) | 416 | if (value) |
417 | m_pidControllerActive = false; | 417 | m_pidControllerActive = false; |
418 | else | 418 | else |
419 | m_pidControllerActive = true; | 419 | m_pidControllerActive = true; |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index a59f63f..2e78de5 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -67,14 +67,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
67 | private int m_expectedCollisionContacts = 0; | 67 | private int m_expectedCollisionContacts = 0; |
68 | 68 | ||
69 | /// <summary> | 69 | /// <summary> |
70 | /// Gets collide bits so that we can still perform land collisions if a mesh fails to load. | ||
71 | /// </summary> | ||
72 | private int BadMeshAssetCollideBits | ||
73 | { | ||
74 | get { return m_isphysical ? (int)CollisionCategories.Land : 0; } | ||
75 | } | ||
76 | |||
77 | /// <summary> | ||
78 | /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. | 70 | /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. |
79 | /// </summary> | 71 | /// </summary> |
80 | public override bool IsPhysical | 72 | public override bool IsPhysical |
@@ -164,7 +156,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
164 | 156 | ||
165 | private PrimitiveBaseShape _pbs; | 157 | private PrimitiveBaseShape _pbs; |
166 | private OdeScene _parent_scene; | 158 | private OdeScene _parent_scene; |
167 | 159 | ||
168 | /// <summary> | 160 | /// <summary> |
169 | /// The physics space which contains prim geometries | 161 | /// The physics space which contains prim geometries |
170 | /// </summary> | 162 | /// </summary> |
@@ -3341,6 +3333,7 @@ Console.WriteLine(" JointCreateFixed"); | |||
3341 | m_material = pMaterial; | 3333 | m_material = pMaterial; |
3342 | } | 3334 | } |
3343 | 3335 | ||
3336 | |||
3344 | private void CheckMeshAsset() | 3337 | private void CheckMeshAsset() |
3345 | { | 3338 | { |
3346 | if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero) | 3339 | if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero) |
@@ -3350,14 +3343,14 @@ Console.WriteLine(" JointCreateFixed"); | |||
3350 | { | 3343 | { |
3351 | RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod; | 3344 | RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod; |
3352 | if (assetProvider != null) | 3345 | if (assetProvider != null) |
3353 | assetProvider(_pbs.SculptTexture, MeshAssetReceived); | 3346 | assetProvider(_pbs.SculptTexture, MeshAssetReveived); |
3354 | }); | 3347 | }); |
3355 | } | 3348 | } |
3356 | } | 3349 | } |
3357 | 3350 | ||
3358 | private void MeshAssetReceived(AssetBase asset) | 3351 | void MeshAssetReveived(AssetBase asset) |
3359 | { | 3352 | { |
3360 | if (asset != null && asset.Data != null && asset.Data.Length > 0) | 3353 | if (asset.Data != null && asset.Data.Length > 0) |
3361 | { | 3354 | { |
3362 | if (!_pbs.SculptEntry) | 3355 | if (!_pbs.SculptEntry) |
3363 | return; | 3356 | return; |
@@ -3370,12 +3363,6 @@ Console.WriteLine(" JointCreateFixed"); | |||
3370 | m_taintshape = true; | 3363 | m_taintshape = true; |
3371 | _parent_scene.AddPhysicsActorTaint(this); | 3364 | _parent_scene.AddPhysicsActorTaint(this); |
3372 | } | 3365 | } |
3373 | else | ||
3374 | { | ||
3375 | m_log.WarnFormat( | ||
3376 | "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}", | ||
3377 | _pbs.SculptTexture, Name, _position, _parent_scene.Name); | ||
3378 | } | ||
3379 | } | 3366 | } |
3380 | } | 3367 | } |
3381 | } | 3368 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index d53bd90..7a50c4c 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs | |||
@@ -501,8 +501,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
501 | public int physics_logging_interval = 0; | 501 | public int physics_logging_interval = 0; |
502 | public bool physics_logging_append_existing_logfile = false; | 502 | public bool physics_logging_append_existing_logfile = false; |
503 | 503 | ||
504 | private bool avplanted = false; | ||
505 | private bool av_av_collisions_off = false; | ||
506 | 504 | ||
507 | public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); | 505 | public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); |
508 | public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); | 506 | public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); |
@@ -646,9 +644,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
646 | avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); | 644 | avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); |
647 | avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); | 645 | avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); |
648 | avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); | 646 | avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); |
649 | avplanted = physicsconfig.GetBoolean("av_planted", false); | ||
650 | av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false); | ||
651 | |||
652 | IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); | 647 | IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); |
653 | 648 | ||
654 | contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); | 649 | contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); |
@@ -668,8 +663,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
668 | meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); | 663 | meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); |
669 | MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); | 664 | MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); |
670 | m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); | 665 | m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); |
671 | |||
672 | |||
673 | 666 | ||
674 | if (Environment.OSVersion.Platform == PlatformID.Unix) | 667 | if (Environment.OSVersion.Platform == PlatformID.Unix) |
675 | { | 668 | { |
@@ -1316,10 +1309,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1316 | if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) | 1309 | if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) |
1317 | skipThisContact = true; // No collision on volume detect prims | 1310 | skipThisContact = true; // No collision on volume detect prims |
1318 | 1311 | ||
1319 | if (av_av_collisions_off) | ||
1320 | if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) | ||
1321 | skipThisContact = true; | ||
1322 | |||
1323 | if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) | 1312 | if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) |
1324 | skipThisContact = true; // No collision on volume detect prims | 1313 | skipThisContact = true; // No collision on volume detect prims |
1325 | 1314 | ||
@@ -1983,8 +1972,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1983 | 1972 | ||
1984 | newAv.Flying = isFlying; | 1973 | newAv.Flying = isFlying; |
1985 | newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; | 1974 | newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; |
1986 | newAv.m_avatarplanted = avplanted; | 1975 | |
1987 | |||
1988 | return newAv; | 1976 | return newAv; |
1989 | } | 1977 | } |
1990 | 1978 | ||
@@ -1999,7 +1987,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1999 | 1987 | ||
2000 | internal void AddCharacter(OdeCharacter chr) | 1988 | internal void AddCharacter(OdeCharacter chr) |
2001 | { | 1989 | { |
2002 | chr.m_avatarplanted = avplanted; | ||
2003 | if (!_characters.Contains(chr)) | 1990 | if (!_characters.Contains(chr)) |
2004 | { | 1991 | { |
2005 | _characters.Add(chr); | 1992 | _characters.Add(chr); |
@@ -4320,4 +4307,4 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
4320 | m_stats[ODEPrimUpdateFrameMsStatName] = 0; | 4307 | m_stats[ODEPrimUpdateFrameMsStatName] = 0; |
4321 | } | 4308 | } |
4322 | } | 4309 | } |
4323 | } | 4310 | } \ No newline at end of file |