aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs)67
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs689
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs51
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1051
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs)112
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs431
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs273
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs327
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs248
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1364
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs978
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs1000
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs479
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs739
16 files changed, 2350 insertions, 5467 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;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35public sealed class BSConstraint6Dof : BSConstraint 35public class BS6DofConstraint : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
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;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using log4net; 30using log4net;
31using OMV = OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public sealed class BSCharacter : BSPhysObject 37public 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
35public abstract class BSConstraint : IDisposable 35public 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;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 35
36public sealed class BSConstraintCollection : IDisposable 36public 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
53namespace OpenSim.Region.Physics.BulletSPlugin 53namespace 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 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35public sealed class BSConstraintHinge : BSConstraint 35class 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
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public abstract class BSLinkset 35public 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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public 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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public 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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37// Class to wrap all objects.
38// The rest of BulletSim doesn't need to keep checking for avatars or prims
39// unless the difference is significant.
40public abstract class BSPhysObject : PhysicsActor
41{
42 protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
43 {
44 PhysicsScene = parentScene;
45 LocalID = localID;
46 PhysObjectName = name;
47 TypeName = typeName;
48
49 Linkset = 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;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. 36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the 37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine. 38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. 39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
@@ -62,7 +62,7 @@ public class BSPlugin : IPhysicsPlugin
62 if (Util.IsWindows()) 62 if (Util.IsWindows())
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll"); 63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the 64 // If not Windows, loading is performed by the
65 // Mono loader as specified in 65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". 66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67 67
68 _mScene = new BSScene(sceneIdentifier); 68 _mScene = new BSScene(sceneIdentifier);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 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.
30using System; 27using System;
31using System.Reflection; 28using System.Reflection;
32using System.Collections.Generic; 29using System.Collections.Generic;
@@ -39,18 +36,32 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
39 36
40namespace OpenSim.Region.Physics.BulletSPlugin 37namespace OpenSim.Region.Physics.BulletSPlugin
41{ 38{
42
43 [Serializable] 39 [Serializable]
44public sealed class BSPrim : BSPhysObject 40public 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;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Test sculpties (verified that they don't work) 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//
63namespace OpenSim.Region.Physics.BulletSPlugin 69namespace OpenSim.Region.Physics.BulletSPlugin
64{ 70{
65public sealed class BSScene : PhysicsScene, IPhysicsParameters 71public 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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public 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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class 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;
33namespace OpenSim.Region.Physics.BulletSPlugin { 33namespace OpenSim.Region.Physics.BulletSPlugin {
34 34
35// Classes to allow some type checking for the API 35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
39public struct BulletSim 36public 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
54public struct BulletBody 45public 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
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = 0;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type;
104 public 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
123public 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
136public struct BulletConstraint 52public 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.
149public 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)]
175public struct ConvexHull 60public 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)]
182public struct ShapeData 67public 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)]
231public struct SweepHit 100public 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
320public enum ActivationState : uint
321{
322 ACTIVE_TAG = 1,
323 ISLAND_SLEEPING,
324 WANTS_DEACTIVATION,
325 DISABLE_DEACTIVATION,
326 DISABLE_SIMULATION,
327}
328
329public 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, ...).
342public enum CollisionFlags : uint 183public 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
365public 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// ===============================================================================
426static class BulletSimAPI { 222static class BulletSimAPI {
427 223
428// Link back to the managed code for outputting log messages
429[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
430public 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)]
434public static extern string GetVersion(); 226public 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]
438public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 229public 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]
444public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
445 232
446[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
447public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 234public 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]
458public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 245public 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]
465public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, 252public 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]
470public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, 257public 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]
482public static extern bool CreateObject(uint worldID, ShapeData shapeData); 269public static extern bool CreateObject(uint worldID, ShapeData shapeData);
483 270
271/* Remove old functionality
272[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
273public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
274
275[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
276public static extern void AddConstraint(uint worldID, uint id1, uint id2,
277 Vector3 frame1, Quaternion frame1rot,
278 Vector3 frame2, Quaternion frame2rot,
279 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
280
281[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
282public static extern bool RemoveConstraintByID(uint worldID, uint id1);
283
284[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
285public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
286 */
287
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 289public 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]
497public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); 301public 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]
501public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); 304public 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]
539public static extern void DumpBulletStatistics(); 342public static extern void DumpBulletStatistics();
540*/ 343
541// Log a debug message 344// Log a debug message
345[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
346public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
543public static extern void SetDebugLogCallback(DebugLogCallback callback); 348public 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]
558public static extern IntPtr GetSimHandle2(uint worldID); 362public static extern IntPtr GetSimHandle2(uint worldID);
559 363
@@ -564,25 +368,23 @@ public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
564public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); 368public 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]
569public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 372public 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]
575public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 377public 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]
578public static extern void SetHeightMap2(IntPtr world, float[] heightmap); 380public static extern void SetHeightmap2(IntPtr world, float[] heightmap);
579 381
580[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 382[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
581public static extern void Shutdown2(IntPtr sim); 383public static extern void Shutdown2(IntPtr sim);
582 384
583[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
584public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, 386public 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]
591public static extern bool PushUpdate2(IntPtr obj); 393public 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]
596public 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]
601public static extern IntPtr CreateHullShape2(IntPtr world,
602 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
603
604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
605public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
606
607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
608public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
609
610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
611public static extern bool IsNativeShape2(IntPtr shape);
612
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
614public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
615
616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
617public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
618
619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
620public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
621
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
624
625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
626public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
627
628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
629public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
630
631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
632public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
633
634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
635public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
636
637[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
638public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
639
640[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
641public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
642
643[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
644public static extern int GetBodyType2(IntPtr obj);
645
646[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
647public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
648
649[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
650public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
651
652[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
653public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
654
655[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
656public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
657
658[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
659public static extern void ReleaseBodyInfo2(IntPtr obj);
660
661[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
662public 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]
667public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords, 397public 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]
671public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords, 400public 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]
675public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo); 403public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh);
676 404
677[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 405[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
678public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 406public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh);
679 407
680[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 408[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
681public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo); 409public 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]
686public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 413public 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
706public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); 433public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
707 434
708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
709public static extern bool SetFrames2(IntPtr constrain, 436public 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]
734public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); 461public 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]
739public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); 464public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj);
740 465
741[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
742public static extern void UpdateAabbs2(IntPtr world); 467public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
743
744[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
745public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
746
747[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
748public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
749
750// =====================================================================================
751// btDynamicsWorld entries
752[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
753public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
754
755[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
756public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
757
758[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
759public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
760
761[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
762public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
763// =====================================================================================
764// btCollisionObject entries
765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
766public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
767
768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
769public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
770
771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
772public static extern bool HasAnisotripicFriction2(IntPtr constrain);
773
774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
775public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
776
777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
778public static extern float GetContactProcessingThreshold2(IntPtr obj);
779
780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
781public static extern bool IsStaticObject2(IntPtr obj);
782
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern bool IsKinematicObject2(IntPtr obj);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern bool HasContactResponse2(IntPtr obj);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern IntPtr GetCollisionShape2(IntPtr obj);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern int GetActivationState2(IntPtr obj);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern void SetActivationState2(IntPtr obj, int state);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern float GetDeactivationTime2(IntPtr obj);
809
810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
811public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
812
813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
814public static extern void Activate2(IntPtr obj, bool forceActivation);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern bool IsActive2(IntPtr obj);
818
819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
820public static extern void SetRestitution2(IntPtr obj, float val);
821
822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
823public static extern float GetRestitution2(IntPtr obj);
824
825[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
826public static extern void SetFriction2(IntPtr obj, float val);
827
828[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
829public static extern float GetFriction2(IntPtr obj);
830
831 /* Haven't defined the type 'Transform'
832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
833public static extern Transform GetWorldTransform2(IntPtr obj);
834
835[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
836public 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]
840public static extern Vector3 GetPosition2(IntPtr obj); 470public static extern Vector3 GetPosition2(IntPtr obj);
@@ -843,290 +473,85 @@ public static extern Vector3 GetPosition2(IntPtr obj);
843public static extern Quaternion GetOrientation2(IntPtr obj); 473public static extern Quaternion GetOrientation2(IntPtr obj);
844 474
845[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
846public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); 476public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
847
848[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
849public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
850
851[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
852public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
853
854 /*
855[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
856public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
857
858[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
859public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
860 */
861
862[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
863public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
864
865[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
866public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
867
868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
869public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
870
871[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
872public static extern float GetHitFraction2(IntPtr obj);
873
874[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
875public static extern void SetHitFraction2(IntPtr obj, float val);
876
877[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
878public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
879
880[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
881public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
882
883[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
884public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
885
886[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
887public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
888
889[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
890public static extern float GetCcdMotionThreshold2(IntPtr obj);
891
892[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
893public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
894
895[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
896public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
897
898[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
899public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
900
901[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
902public static extern IntPtr GetUserPointer2(IntPtr obj);
903
904[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
905public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
906
907// =====================================================================================
908// btRigidBody entries
909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
910public static extern void ApplyGravity2(IntPtr obj);
911
912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
913public static extern void SetGravity2(IntPtr obj, Vector3 val);
914
915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
916public static extern Vector3 GetGravity2(IntPtr obj);
917
918[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
919public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
920
921[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
922public static extern float GetLinearDamping2(IntPtr obj);
923
924[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
925public static extern float GetAngularDamping2(IntPtr obj);
926
927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
928public static extern float GetLinearSleepingThreshold2(IntPtr obj);
929
930[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
931public static extern float GetAngularSleepingThreshold2(IntPtr obj);
932
933[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
934public static extern void ApplyDamping2(IntPtr obj, float timeStep);
935
936[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
937public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
938
939[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
940public static extern Vector3 GetLinearFactor2(IntPtr obj);
941
942[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
943public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
944
945 /*
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
948 */
949
950[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
951public 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]
955public 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]
959public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
960
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern Vector3 GetTotalForce2(IntPtr obj);
963
964[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
965public static extern Vector3 GetTotalTorque2(IntPtr obj);
966
967[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
968public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
969
970[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
971public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
972
973[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
974public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
975
976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
977public 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]
981public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); 479public 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]
985public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); 482public 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]
989public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); 485public 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]
993public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); 488public static extern bool AddObjectForce2(IntPtr obj, Vector3 force);
994 489
995[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
996public static extern void ClearForces2(IntPtr obj); 491public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val);
997 492
998[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
999public static extern void ClearAllForces2(IntPtr obj); 494public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val);
1000 495
1001[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1002public static extern void UpdateInertiaTensor2(IntPtr obj); 497public 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]
1005public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); 500public 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]
1009public static extern Transform GetCenterOfMassTransform2(IntPtr obj); 503public 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]
1013public static extern Vector3 GetLinearVelocity2(IntPtr obj); 506public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
1014 507
1015[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1016public static extern Vector3 GetAngularVelocity2(IntPtr obj); 509public static extern bool SetFriction2(IntPtr obj, float val);
1017 510
1018[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1019public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); 512public static extern bool SetRestitution2(IntPtr obj, float val);
1020 513
1021[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1022public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); 515public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val);
1023 516
1024[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1025public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); 518public 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]
1028public static extern void Translate2(IntPtr obj, Vector3 trans); 521public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1029
1030[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1031public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1032
1033[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1034public static extern bool WantsSleeping2(IntPtr obj);
1035
1036[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1037public static extern void SetAngularFactor2(IntPtr obj, float factor);
1038
1039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1040public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1041
1042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1043public static extern Vector3 GetAngularFactor2(IntPtr obj);
1044
1045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1046public static extern bool IsInWorld2(IntPtr obj);
1047
1048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1049public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1050
1051[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1052public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1053
1054[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1055public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1056
1057[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1058public static extern int GetNumConstraintRefs2(IntPtr obj);
1059
1060[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1061public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1062
1063// =====================================================================================
1064// btCollisionShape entries
1065
1066[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1067public static extern float GetAngularMotionDisc2(IntPtr shape);
1068
1069[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1070public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1071
1072[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1073public static extern bool IsPolyhedral2(IntPtr shape);
1074
1075[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1076public static extern bool IsConvex2d2(IntPtr shape);
1077
1078[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1079public static extern bool IsConvex2(IntPtr shape);
1080
1081[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1082public static extern bool IsNonMoving2(IntPtr shape);
1083
1084[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1085public static extern bool IsConcave2(IntPtr shape);
1086
1087[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1088public static extern bool IsCompound2(IntPtr shape);
1089
1090[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1091public static extern bool IsSoftBody2(IntPtr shape);
1092
1093[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1094public static extern bool IsInfinite2(IntPtr shape);
1095 522
1096[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1097public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); 524public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1098 525
1099[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1100public static extern Vector3 GetLocalScaling2(IntPtr shape); 527public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1101 528
1102[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1103public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); 530public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1104 531
1105[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1106public static extern int GetShapeType2(IntPtr shape); 533public 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]
1109public static extern void SetMargin2(IntPtr shape, float val); 536public static extern bool UpdateInertiaTensor2(IntPtr obj);
1110 537
1111[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1112public static extern float GetMargin2(IntPtr shape); 539public 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]
1117public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); 542public static extern IntPtr ClearForces2(IntPtr obj);
1118 543
1119[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1120public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); 545public static extern IntPtr ClearAllForces2(IntPtr obj);
1121 546
1122[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 547[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1123public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); 548public static extern bool SetMargin2(IntPtr obj, float val);
1124 549
1125[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 550[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1126public static extern void DumpAllInfo2(IntPtr sim); 551public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
1127 552
1128[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 553[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1129public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); 554public static extern bool DestroyObject2(IntPtr world, uint id);
1130 555
1131[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 556[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1132public static extern void DumpPhysicsStatistics2(IntPtr sim); 557public static extern void DumpPhysicsStatistics2(IntPtr sim);