aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs69
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs125
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs184
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs187
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs352
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs614
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs828
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs272
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs5
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs15
10 files changed, 1968 insertions, 683 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index dc0c008..09e1f0c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -41,7 +41,7 @@ public class BSCharacter : PhysicsActor
41 41
42 private BSScene _scene; 42 private BSScene _scene;
43 private String _avName; 43 private String _avName;
44 private bool _stopped; 44 // private bool _stopped;
45 private Vector3 _size; 45 private Vector3 _size;
46 private Vector3 _scale; 46 private Vector3 _scale;
47 private PrimitiveBaseShape _pbs; 47 private PrimitiveBaseShape _pbs;
@@ -134,9 +134,9 @@ public class BSCharacter : PhysicsActor
134 { 134 {
135 base.RequestPhysicsterseUpdate(); 135 base.RequestPhysicsterseUpdate();
136 } 136 }
137 137 // No one calls this method so I don't know what it could possibly mean
138 public override bool Stopped { 138 public override bool Stopped {
139 get { return _stopped; } 139 get { return false; }
140 } 140 }
141 public override Vector3 Size { 141 public override Vector3 Size {
142 get { return _size; } 142 get { return _size; }
@@ -391,52 +391,47 @@ public class BSCharacter : PhysicsActor
391 _mass = _density * _avatarVolume; 391 _mass = _density * _avatarVolume;
392 } 392 }
393 393
394 // Set to 'true' if the individual changed items should be checked
395 // (someday RequestPhysicsTerseUpdate() will take a bitmap of changed properties)
396 const bool SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES = false;
397
398 // The physics engine says that properties have updated. Update same and inform 394 // The physics engine says that properties have updated. Update same and inform
399 // the world that things have changed. 395 // the world that things have changed.
400 public void UpdateProperties(EntityProperties entprop) 396 public void UpdateProperties(EntityProperties entprop)
401 { 397 {
398 /*
402 bool changed = false; 399 bool changed = false;
403 if (SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES) { 400 // we assign to the local variables so the normal set action does not happen
404 // we assign to the local variables so the normal set action does not happen 401 if (_position != entprop.Position) {
405 if (_position != entprop.Position) {
406 _position = entprop.Position;
407 changed = true;
408 }
409 if (_orientation != entprop.Rotation) {
410 _orientation = entprop.Rotation;
411 changed = true;
412 }
413 if (_velocity != entprop.Velocity) {
414 _velocity = entprop.Velocity;
415 changed = true;
416 }
417 if (_acceleration != entprop.Acceleration) {
418 _acceleration = entprop.Acceleration;
419 changed = true;
420 }
421 if (_rotationalVelocity != entprop.RotationalVelocity) {
422 _rotationalVelocity = entprop.RotationalVelocity;
423 changed = true;
424 }
425 if (changed) {
426 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
427 // Avatar movement is not done by generating this event. There is code in the heartbeat
428 // loop that updates avatars.
429 // base.RequestPhysicsterseUpdate();
430 }
431 }
432 else {
433 _position = entprop.Position; 402 _position = entprop.Position;
403 changed = true;
404 }
405 if (_orientation != entprop.Rotation) {
434 _orientation = entprop.Rotation; 406 _orientation = entprop.Rotation;
407 changed = true;
408 }
409 if (_velocity != entprop.Velocity) {
435 _velocity = entprop.Velocity; 410 _velocity = entprop.Velocity;
411 changed = true;
412 }
413 if (_acceleration != entprop.Acceleration) {
436 _acceleration = entprop.Acceleration; 414 _acceleration = entprop.Acceleration;
415 changed = true;
416 }
417 if (_rotationalVelocity != entprop.RotationalVelocity) {
437 _rotationalVelocity = entprop.RotationalVelocity; 418 _rotationalVelocity = entprop.RotationalVelocity;
419 changed = true;
420 }
421 if (changed) {
422 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
423 // Avatar movement is not done by generating this event. There is code in the heartbeat
424 // loop that updates avatars.
438 // base.RequestPhysicsterseUpdate(); 425 // base.RequestPhysicsterseUpdate();
439 } 426 }
427 */
428 _position = entprop.Position;
429 _orientation = entprop.Rotation;
430 _velocity = entprop.Velocity;
431 _acceleration = entprop.Acceleration;
432 _rotationalVelocity = entprop.RotationalVelocity;
433 // Avatars don't report theirr changes the usual way. Changes are checked for in the heartbeat loop.
434 // base.RequestPhysicsterseUpdate();
440 } 435 }
441 436
442 // Called by the scene when a collision with this object is reported 437 // Called by the scene when a collision with this object is reported
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
new file mode 100755
index 0000000..ea3093a
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -0,0 +1,125 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public class BSConstraint : IDisposable
36{
37 private BulletSim m_world;
38 private BulletBody m_body1;
39 private BulletBody m_body2;
40 private BulletConstraint m_constraint;
41 private bool m_enabled = false;
42
43 public BSConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
44 Vector3 frame1, Quaternion frame1rot,
45 Vector3 frame2, Quaternion frame2rot
46 )
47 {
48 m_world = world;
49 m_body1 = obj1;
50 m_body2 = obj2;
51 m_constraint = new BulletConstraint(BulletSimAPI.CreateConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
52 frame1, frame1rot,
53 frame2, frame2rot,
54 true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/));
55 m_enabled = true;
56 }
57
58 public void Dispose()
59 {
60 if (m_enabled)
61 {
62 // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
63 BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
64 m_enabled = false;
65 }
66 }
67
68 public BulletBody Body1 { get { return m_body1; } }
69 public BulletBody Body2 { get { return m_body2; } }
70
71 public bool SetLinearLimits(Vector3 low, Vector3 high)
72 {
73 bool ret = false;
74 if (m_enabled)
75 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high);
76 return ret;
77 }
78
79 public bool SetAngularLimits(Vector3 low, Vector3 high)
80 {
81 bool ret = false;
82 if (m_enabled)
83 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high);
84 return ret;
85 }
86
87 public bool SetCFMAndERP(float cfm, float erp)
88 {
89 bool ret = true;
90 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
91 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
92 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
93 return ret;
94 }
95
96 public bool UseFrameOffset(bool useOffset)
97 {
98 bool ret = false;
99 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
100 if (m_enabled)
101 ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
102 return ret;
103 }
104
105 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
106 {
107 bool ret = false;
108 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
109 if (m_enabled)
110 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
111 return ret;
112 }
113
114 public bool CalculateTransforms()
115 {
116 bool ret = false;
117 if (m_enabled)
118 {
119 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr);
120 ret = true;
121 }
122 return ret;
123 }
124}
125}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
new file mode 100755
index 0000000..c88e645
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -0,0 +1,184 @@
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 log4net;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public class BSConstraintCollection : IDisposable
37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
40
41 delegate bool ConstraintAction(BSConstraint constrain);
42
43 private List<BSConstraint> m_constraints;
44 private BulletSim m_world;
45
46 public BSConstraintCollection(BulletSim world)
47 {
48 m_world = world;
49 m_constraints = new List<BSConstraint>();
50 }
51
52 public void Dispose()
53 {
54 this.Clear();
55 }
56
57 public void Clear()
58 {
59 foreach (BSConstraint cons in m_constraints)
60 {
61 cons.Dispose();
62 }
63 m_constraints.Clear();
64 }
65
66 public BSConstraint CreateConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
67 Vector3 frame1, Quaternion frame1rot,
68 Vector3 frame2, Quaternion frame2rot)
69 {
70 BSConstraint constrain = new BSConstraint(world, obj1, obj2, frame1, frame1rot, frame2, frame2rot);
71
72 this.AddConstraint(constrain);
73 return constrain;
74 }
75
76 public bool AddConstraint(BSConstraint cons)
77 {
78 // There is only one constraint between any bodies. Remove any old just to make sure.
79 RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
80
81 m_constraints.Add(cons);
82
83 return true;
84 }
85
86 // Get the constraint between two bodies. There can be only one.
87 // Return 'true' if a constraint was found.
88 public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
89 {
90 bool found = false;
91 BSConstraint foundConstraint = null;
92
93 uint lookingID1 = body1.ID;
94 uint lookingID2 = body2.ID;
95 ForEachConstraint(delegate(BSConstraint constrain)
96 {
97 if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
98 || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
99 {
100 foundConstraint = constrain;
101 found = true;
102 }
103 return found;
104 });
105 returnConstraint = foundConstraint;
106 return found;
107 }
108
109 // Remove any constraint between the passed bodies.
110 // Presumed there is only one such constraint possible.
111 // Return 'true' if a constraint was found and destroyed.
112 public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
113 {
114 // return BulletSimAPI.RemoveConstraint(m_world.ID, obj1.ID, obj2.ID);
115
116 bool ret = false;
117 BSConstraint constrain;
118
119 if (this.TryGetConstraint(body1, body2, out constrain))
120 {
121 // remove the constraint from our collection
122 m_constraints.Remove(constrain);
123 // tell the engine that all its structures need to be freed
124 constrain.Dispose();
125 // we destroyed something
126 ret = true;
127 }
128
129 return ret;
130 }
131
132 // Remove all constraints that reference the passed body.
133 // Return 'true' if any constraints were destroyed.
134 public bool RemoveAndDestroyConstraint(BulletBody body1)
135 {
136 // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
137
138 List<BSConstraint> toRemove = new List<BSConstraint>();
139 uint lookingID = body1.ID;
140 ForEachConstraint(delegate(BSConstraint constrain)
141 {
142 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
143 {
144 toRemove.Add(constrain);
145 }
146 return false;
147 });
148 lock (m_constraints)
149 {
150 foreach (BSConstraint constrain in toRemove)
151 {
152 m_constraints.Remove(constrain);
153 constrain.Dispose();
154 }
155 }
156 return (toRemove.Count > 0);
157 }
158
159 public bool RecalculateAllConstraints()
160 {
161 foreach (BSConstraint constrain in m_constraints)
162 {
163 constrain.CalculateTransforms();
164 }
165 return true;
166 }
167
168 // Lock the constraint list and loop through it.
169 // The constraint action returns 'true' if it wants the loop aborted.
170 private void ForEachConstraint(ConstraintAction action)
171 {
172 lock (m_constraints)
173 {
174 foreach (BSConstraint constrain in m_constraints)
175 {
176 if (action(constrain))
177 break;
178 }
179 }
180 }
181
182
183}
184}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index eb20eb3..c197e61 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -57,7 +57,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
57 private int frcount = 0; // Used to limit dynamics debug output to 57 private int frcount = 0; // Used to limit dynamics debug output to
58 // every 100th frame 58 // every 100th frame
59 59
60 // private BSScene m_parentScene = null;
61 private BSPrim m_prim; // the prim this dynamic controller belongs to 60 private BSPrim m_prim; // the prim this dynamic controller belongs to
62 61
63 // Vehicle properties 62 // Vehicle properties
@@ -131,8 +130,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
131 m_type = Vehicle.TYPE_NONE; 130 m_type = Vehicle.TYPE_NONE;
132 } 131 }
133 132
134 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep)
135 { 134 {
135 DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
136 switch (pParam) 136 switch (pParam)
137 { 137 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@@ -229,8 +229,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
229 } 229 }
230 }//end ProcessFloatVehicleParam 230 }//end ProcessFloatVehicleParam
231 231
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep)
233 { 233 {
234 DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
234 switch (pParam) 235 switch (pParam)
235 { 236 {
236 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 237 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@@ -265,6 +266,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
265 266
266 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
267 { 268 {
269 DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
268 switch (pParam) 270 switch (pParam)
269 { 271 {
270 case Vehicle.REFERENCE_FRAME: 272 case Vehicle.REFERENCE_FRAME:
@@ -278,6 +280,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
278 280
279 internal void ProcessVehicleFlags(int pParam, bool remove) 281 internal void ProcessVehicleFlags(int pParam, bool remove)
280 { 282 {
283 DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove);
281 if (remove) 284 if (remove)
282 { 285 {
283 if (pParam == -1) 286 if (pParam == -1)
@@ -434,6 +437,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
434 437
435 internal void ProcessTypeChange(Vehicle pType) 438 internal void ProcessTypeChange(Vehicle pType)
436 { 439 {
440 DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType);
437 // Set Defaults For Type 441 // Set Defaults For Type
438 m_type = pType; 442 m_type = pType;
439 switch (pType) 443 switch (pType)
@@ -594,11 +598,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
594 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 598 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
595 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); 599 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
596 break; 600 break;
597
598 } 601 }
599 }//end SetDefaultsForType 602 }//end SetDefaultsForType
600 603
601 internal void Step(float pTimestep, BSScene pParentScene) 604 internal void Step(float pTimestep)
602 { 605 {
603 if (m_type == Vehicle.TYPE_NONE) return; 606 if (m_type == Vehicle.TYPE_NONE) return;
604 607
@@ -606,21 +609,34 @@ namespace OpenSim.Region.Physics.BulletSPlugin
606 if (frcount > 100) 609 if (frcount > 100)
607 frcount = 0; 610 frcount = 0;
608 611
609 MoveLinear(pTimestep, pParentScene); 612 MoveLinear(pTimestep);
610 MoveAngular(pTimestep); 613 MoveAngular(pTimestep);
611 LimitRotation(pTimestep); 614 LimitRotation(pTimestep);
615
616 DetailLog("{0},Dynamics,done,pos={1},force={2},velocity={3},angvel={4}",
617 m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity);
612 }// end Step 618 }// end Step
613 619
614 private void MoveLinear(float pTimestep, BSScene _pParentScene) 620 private void MoveLinear(float pTimestep)
615 { 621 {
616 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant 622 // requested m_linearMotorDirection is significant
623 // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f))
624 if (m_linearMotorDirection.LengthSquared() > 0.0001f)
617 { 625 {
626 Vector3 origDir = m_linearMotorDirection;
627 Vector3 origVel = m_lastLinearVelocityVector;
628
618 // add drive to body 629 // add drive to body
619 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); 630 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
620 m_lastLinearVelocityVector += (addAmount*10); // 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;
621 636
622 // This will work temporarily, but we really need to compare speed on an axis 637 // This will work temporarily, but we really need to compare speed on an axis
623 // KF: Limit body velocity to applied velocity? 638 // KF: Limit body velocity to applied velocity?
639 // Limit the velocity vector to less than the last set linear motor direction
624 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 640 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
625 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 641 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
626 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) 642 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
@@ -630,76 +646,93 @@ namespace OpenSim.Region.Physics.BulletSPlugin
630 646
631 // decay applied velocity 647 // decay applied velocity
632 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); 648 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
633 //Console.WriteLine("decay: " + decayfraction);
634 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 649 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
635 //Console.WriteLine("actual: " + m_linearMotorDirection); 650
651 /*
652 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale;
653 m_lastLinearVelocityVector += addAmount;
654
655 float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale);
656 m_linearMotorDirection *= decayfraction;
657
658 */
659
660 DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}",
661 m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
636 } 662 }
637 else 663 else
638 { // requested is not significant 664 {
639 // if what remains of applied is small, zero it. 665 // if what remains of applied is small, zero it.
640 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) 666 // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
641 m_lastLinearVelocityVector = Vector3.Zero; 667 // m_lastLinearVelocityVector = Vector3.Zero;
668 m_linearMotorDirection = Vector3.Zero;
669 m_lastLinearVelocityVector = Vector3.Zero;
642 } 670 }
643 671
644 // convert requested object velocity to world-referenced vector 672 // convert requested object velocity to world-referenced vector
645 m_dir = m_lastLinearVelocityVector; 673 Quaternion rotq = m_prim.Orientation;
646 Quaternion rot = m_prim.Orientation; 674 m_dir = m_lastLinearVelocityVector * rotq;
647 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object 675
648 m_dir *= rotq; // apply obj rotation to velocity vector 676 // Add the various forces into m_dir which will be our new direction vector (velocity)
649 677
650 // add Gravity andBuoyancy 678 // add Gravity and Buoyancy
651 // KF: So far I have found no good method to combine a script-requested 679 // KF: So far I have found no good method to combine a script-requested
652 // .Z velocity and gravity. Therefore only 0g will used script-requested 680 // .Z velocity and gravity. Therefore only 0g will used script-requested
653 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. 681 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
654 Vector3 grav = Vector3.Zero; 682 Vector3 grav = Vector3.Zero;
655 // There is some gravity, make a gravity force vector 683 // There is some gravity, make a gravity force vector that is applied after object velocity.
656 // that is applied after object velocity.
657 float objMass = m_prim.Mass;
658 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 684 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
659 grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy); 685 grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy);
660 // Preserve the current Z velocity 686 // Preserve the current Z velocity
661 Vector3 vel_now = m_prim.Velocity; 687 Vector3 vel_now = m_prim.Velocity;
662 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 688 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
663 689
664 Vector3 pos = m_prim.Position; 690 Vector3 pos = m_prim.Position;
691 Vector3 posChange = pos;
665// 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);
666 Vector3 posChange = new Vector3();
667 posChange.X = pos.X - m_lastPositionVector.X;
668 posChange.Y = pos.Y - m_lastPositionVector.Y;
669 posChange.Z = pos.Z - m_lastPositionVector.Z;
670 double Zchange = Math.Abs(posChange.Z); 693 double Zchange = Math.Abs(posChange.Z);
671 if (m_BlockingEndPoint != Vector3.Zero) 694 if (m_BlockingEndPoint != Vector3.Zero)
672 { 695 {
696 bool changed = false;
673 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 697 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
674 { 698 {
675 pos.X -= posChange.X + 1; 699 pos.X -= posChange.X + 1;
676 m_prim.Position = pos; 700 changed = true;
677 } 701 }
678 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) 702 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
679 { 703 {
680 pos.Y -= posChange.Y + 1; 704 pos.Y -= posChange.Y + 1;
681 m_prim.Position = pos; 705 changed = true;
682 } 706 }
683 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) 707 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
684 { 708 {
685 pos.Z -= posChange.Z + 1; 709 pos.Z -= posChange.Z + 1;
686 m_prim.Position = pos; 710 changed = true;
687 } 711 }
688 if (pos.X <= 0) 712 if (pos.X <= 0)
689 { 713 {
690 pos.X += posChange.X + 1; 714 pos.X += posChange.X + 1;
691 m_prim.Position = pos; 715 changed = true;
692 } 716 }
693 if (pos.Y <= 0) 717 if (pos.Y <= 0)
694 { 718 {
695 pos.Y += posChange.Y + 1; 719 pos.Y += posChange.Y + 1;
720 changed = true;
721 }
722 if (changed)
723 {
696 m_prim.Position = pos; 724 m_prim.Position = pos;
725 DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
726 m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
697 } 727 }
698 } 728 }
699 if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) 729
730 // If below the terrain, move us above the ground a little.
731 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos))
700 { 732 {
701 pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; 733 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2;
702 m_prim.Position = pos; 734 m_prim.Position = pos;
735 DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos);
703 } 736 }
704 737
705 // Check if hovering 738 // Check if hovering
@@ -708,11 +741,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
708 // We should hover, get the target height 741 // We should hover, get the target height
709 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) 742 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
710 { 743 {
711 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; 744 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight;
712 } 745 }
713 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 746 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
714 { 747 {
715 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 748 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
716 } 749 }
717 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 750 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
718 { 751 {
@@ -746,6 +779,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
746 } 779 }
747 } 780 }
748 781
782 DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight);
783
749// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped 784// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
750// m_VhoverTimescale = 0f; // time to acheive height 785// m_VhoverTimescale = 0f; // time to acheive height
751// pTimestep is time since last frame,in secs 786// pTimestep is time since last frame,in secs
@@ -774,12 +809,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
774 { 809 {
775 grav.Z = (float)(grav.Z * 1.125); 810 grav.Z = (float)(grav.Z * 1.125);
776 } 811 }
777 float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); 812 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
778 float postemp = (pos.Z - terraintemp); 813 float postemp = (pos.Z - terraintemp);
779 if (postemp > 2.5f) 814 if (postemp > 2.5f)
780 { 815 {
781 grav.Z = (float)(grav.Z * 1.037125); 816 grav.Z = (float)(grav.Z * 1.037125);
782 } 817 }
818 DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
783 //End Experimental Values 819 //End Experimental Values
784 } 820 }
785 if ((m_flags & (VehicleFlag.NO_X)) != 0) 821 if ((m_flags & (VehicleFlag.NO_X)) != 0)
@@ -800,32 +836,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
800 // Apply velocity 836 // Apply velocity
801 m_prim.Velocity = m_dir; 837 m_prim.Velocity = m_dir;
802 // apply gravity force 838 // apply gravity force
803 m_prim.Force = grav; 839 // Why is this set here? The physics engine already does gravity.
804 840 // m_prim.AddForce(grav, false);
841 // m_prim.Force = grav;
805 842
806 // apply friction 843 // Apply friction
807 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); 844 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
808 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; 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);
849
809 } // end MoveLinear() 850 } // end MoveLinear()
810 851
811 private void MoveAngular(float pTimestep) 852 private void MoveAngular(float pTimestep)
812 { 853 {
813 /* 854 // m_angularMotorDirection // angular velocity requested by LSL motor
814 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 855 // m_angularMotorApply // application frame counter
815 private int m_angularMotorApply = 0; // application frame counter 856 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
816 private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) 857 // m_angularMotorTimescale // motor angular velocity ramp up rate
817 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 858 // m_angularMotorDecayTimescale // motor angular velocity decay rate
818 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 859 // m_angularFrictionTimescale // body angular velocity decay rate
819 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 860 // m_lastAngularVelocity // what was last applied to body
820 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
821 */
822 861
823 // Get what the body is doing, this includes 'external' influences 862 // Get what the body is doing, this includes 'external' influences
824 Vector3 angularVelocity = m_prim.RotationalVelocity; 863 Vector3 angularVelocity = m_prim.RotationalVelocity;
825 // Vector3 angularVelocity = Vector3.Zero;
826 864
827 if (m_angularMotorApply > 0) 865 if (m_angularMotorApply > 0)
828 { 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;
829 // ramp up to new value 872 // ramp up to new value
830 // current velocity += error / (time to get there / step interval) 873 // current velocity += error / (time to get there / step interval)
831 // requested speed - last motor speed 874 // requested speed - last motor speed
@@ -833,23 +876,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
833 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 876 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
834 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); 877 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
835 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
836 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected 882 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
837 // velocity may still be acheived. 883 // velocity may still be acheived.
838 } 884 }
839 else 885 else
840 { 886 {
841 // no motor recently applied, keep the body velocity 887 // No motor recently applied, keep the body velocity
842 /* m_angularMotorVelocity.X = angularVelocity.X;
843 m_angularMotorVelocity.Y = angularVelocity.Y;
844 m_angularMotorVelocity.Z = angularVelocity.Z; */
845
846 // and decay the velocity 888 // and decay the velocity
847 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 889 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
848 } // end motor section 890 } // end motor section
849 891
850 // Vertical attractor section 892 // Vertical attractor section
851 Vector3 vertattr = Vector3.Zero; 893 Vector3 vertattr = Vector3.Zero;
852
853 if (m_verticalAttractionTimescale < 300) 894 if (m_verticalAttractionTimescale < 300)
854 { 895 {
855 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); 896 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
@@ -871,7 +912,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
871 // Error is 0 (no error) to +/- 2 (max error) 912 // Error is 0 (no error) to +/- 2 (max error)
872 // scale it by VAservo 913 // scale it by VAservo
873 verterr = verterr * VAservo; 914 verterr = verterr * VAservo;
874//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
875 915
876 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so 916 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
877 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. 917 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
@@ -884,11 +924,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
884 vertattr.X += bounce * angularVelocity.X; 924 vertattr.X += bounce * angularVelocity.X;
885 vertattr.Y += bounce * angularVelocity.Y; 925 vertattr.Y += bounce * angularVelocity.Y;
886 926
927 DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
928 m_prim.LocalID, verterr, bounce, vertattr);
929
887 } // else vertical attractor is off 930 } // else vertical attractor is off
888 931
889 // m_lastVertAttractor = vertattr; 932 // m_lastVertAttractor = vertattr;
890 933
891 // Bank section tba 934 // Bank section tba
935
892 // Deflection section tba 936 // Deflection section tba
893 937
894 // Sum velocities 938 // Sum velocities
@@ -898,11 +942,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
898 { 942 {
899 m_lastAngularVelocity.X = 0; 943 m_lastAngularVelocity.X = 0;
900 m_lastAngularVelocity.Y = 0; 944 m_lastAngularVelocity.Y = 0;
945 DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
901 } 946 }
902 947
903 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 948 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
904 { 949 {
905 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 950 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
951 DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
906 } 952 }
907 953
908 // apply friction 954 // apply friction
@@ -912,10 +958,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
912 // Apply to the body 958 // Apply to the body
913 m_prim.RotationalVelocity = m_lastAngularVelocity; 959 m_prim.RotationalVelocity = m_lastAngularVelocity;
914 960
961 DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity);
915 } //end MoveAngular 962 } //end MoveAngular
963
916 internal void LimitRotation(float timestep) 964 internal void LimitRotation(float timestep)
917 { 965 {
918 Quaternion rotq = m_prim.Orientation; // rotq = rotation of object 966 Quaternion rotq = m_prim.Orientation;
919 Quaternion m_rot = rotq; 967 Quaternion m_rot = rotq;
920 bool changed = false; 968 bool changed = false;
921 if (m_RollreferenceFrame != Quaternion.Identity) 969 if (m_RollreferenceFrame != Quaternion.Identity)
@@ -923,18 +971,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
923 if (rotq.X >= m_RollreferenceFrame.X) 971 if (rotq.X >= m_RollreferenceFrame.X)
924 { 972 {
925 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); 973 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
974 changed = true;
926 } 975 }
927 if (rotq.Y >= m_RollreferenceFrame.Y) 976 if (rotq.Y >= m_RollreferenceFrame.Y)
928 { 977 {
929 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); 978 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
979 changed = true;
930 } 980 }
931 if (rotq.X <= -m_RollreferenceFrame.X) 981 if (rotq.X <= -m_RollreferenceFrame.X)
932 { 982 {
933 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); 983 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
984 changed = true;
934 } 985 }
935 if (rotq.Y <= -m_RollreferenceFrame.Y) 986 if (rotq.Y <= -m_RollreferenceFrame.Y)
936 { 987 {
937 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); 988 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
989 changed = true;
938 } 990 }
939 changed = true; 991 changed = true;
940 } 992 }
@@ -944,8 +996,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
944 m_rot.Y = 0; 996 m_rot.Y = 0;
945 changed = true; 997 changed = true;
946 } 998 }
999 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1000 {
1001 m_rot.X = 0;
1002 m_rot.Y = 0;
1003 changed = true;
1004 }
947 if (changed) 1005 if (changed)
948 m_prim.Orientation = m_rot; 1006 m_prim.Orientation = m_rot;
1007
1008 DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
1009 }
1010
1011 // Invoke the detailed logger and output something if it's enabled.
1012 private void DetailLog(string msg, params Object[] args)
1013 {
1014 if (m_prim.Scene.VehicleLoggingEnabled)
1015 m_prim.Scene.PhysicsLogging.Write(msg, args);
949 } 1016 }
950 } 1017 }
951} 1018}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
new file mode 100755
index 0000000..6f8430c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -0,0 +1,352 @@
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 class BSLinkset
36{
37 private static string LogHeader = "[BULLETSIM LINKSET]";
38
39 private BSPrim m_linksetRoot;
40 public BSPrim Root { get { return m_linksetRoot; } }
41
42 private BSScene m_scene;
43
44 private List<BSPrim> m_children;
45
46 // We lock the diddling of linkset classes to prevent any badness.
47 // This locks the modification of the instances of this class. Changes
48 // to the physical representation is done via the tainting mechenism.
49 private object m_linksetActivityLock = new Object();
50
51 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
52 private float m_mass;
53 public float LinksetMass
54 {
55 get
56 {
57 m_mass = ComputeLinksetMass();
58 return m_mass;
59 }
60 }
61
62 public OMV.Vector3 CenterOfMass
63 {
64 get { return ComputeLinksetCenterOfMass(); }
65 }
66
67 public OMV.Vector3 GeometricCenter
68 {
69 get { return ComputeLinksetGeometricCenter(); }
70 }
71
72 public BSLinkset(BSScene scene, BSPrim parent)
73 {
74 // A simple linkset of one (no children)
75 m_scene = scene;
76 m_linksetRoot = parent;
77 m_children = new List<BSPrim>();
78 m_mass = parent.MassRaw;
79 }
80
81 // Link to a linkset where the child knows the parent.
82 // Parent changing should not happen so do some sanity checking.
83 // We return the parent's linkset so the child can track it's membership.
84 public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent)
85 {
86 lock (m_linksetActivityLock)
87 {
88 parent.Linkset.AddChildToLinkset(child);
89 }
90 return parent.Linkset;
91 }
92
93 public BSLinkset RemoveMeFromLinkset(BSPrim child)
94 {
95 lock (m_linksetActivityLock)
96 {
97 if (IsRoot(child))
98 {
99 // if root of linkset, take the linkset apart
100 while (m_children.Count > 0)
101 {
102 // Note that we don't do a foreach because the remove routine
103 // takes it out of the list.
104 RemoveChildFromLinkset(m_children[0]);
105 }
106 m_children.Clear(); // just to make sure
107 }
108 else
109 {
110 // Just removing a child from an existing linkset
111 RemoveChildFromLinkset(child);
112 }
113 }
114
115 // The child is down to a linkset of just itself
116 return new BSLinkset(m_scene, child);
117 }
118
119 // An existing linkset had one of its members rebuilt or something.
120 // Go through the linkset and rebuild the pointers to the bodies of the linkset members.
121 public BSLinkset RefreshLinkset(BSPrim requestor)
122 {
123 BSLinkset ret = requestor.Linkset;
124
125 lock (m_linksetActivityLock)
126 {
127 System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID);
128 if (aPtr == System.IntPtr.Zero)
129 {
130 // That's odd. We can't find the root of the linkset.
131 // The linkset is somehow dead. The requestor is now a member of a linkset of one.
132 DetailLog("{0},RefreshLinkset.RemoveRoot,child={1}", m_linksetRoot.LocalID, m_linksetRoot.LocalID);
133 ret = RemoveMeFromLinkset(m_linksetRoot);
134 }
135 else
136 {
137 // Reconstruct the pointer to the body of the linkset root.
138 DetailLog("{0},RefreshLinkset.RebuildRoot,rootID={1},ptr={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, aPtr);
139 m_linksetRoot.Body = new BulletBody(m_linksetRoot.LocalID, aPtr);
140
141 List<BSPrim> toRemove = new List<BSPrim>();
142 foreach (BSPrim bsp in m_children)
143 {
144 aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, bsp.LocalID);
145 if (aPtr == System.IntPtr.Zero)
146 {
147 toRemove.Add(bsp);
148 }
149 else
150 {
151 // Reconstruct the pointer to the body of the linkset root.
152 DetailLog("{0},RefreshLinkset.RebuildChild,rootID={1},ptr={2}", bsp.LocalID, m_linksetRoot.LocalID, aPtr);
153 bsp.Body = new BulletBody(bsp.LocalID, aPtr);
154 }
155 }
156 foreach (BSPrim bsp in toRemove)
157 {
158 RemoveChildFromLinkset(bsp);
159 }
160 }
161 }
162
163 return ret;
164 }
165
166
167 // Return 'true' if the passed object is the root object of this linkset
168 public bool IsRoot(BSPrim requestor)
169 {
170 return (requestor.LocalID == m_linksetRoot.LocalID);
171 }
172
173 // Return 'true' if this linkset has any children (more than the root member)
174 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
175
176 // Return 'true' if this child is in this linkset
177 public bool HasChild(BSPrim child)
178 {
179 bool ret = false;
180 foreach (BSPrim bp in m_children)
181 {
182 if (child.LocalID == bp.LocalID)
183 {
184 ret = true;
185 break;
186 }
187 }
188 return ret;
189 }
190
191 private float ComputeLinksetMass()
192 {
193 float mass = m_linksetRoot.MassRaw;
194 foreach (BSPrim bp in m_children)
195 {
196 mass += bp.MassRaw;
197 }
198 return mass;
199 }
200
201 private OMV.Vector3 ComputeLinksetCenterOfMass()
202 {
203 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
204 float totalMass = m_linksetRoot.MassRaw;
205
206 foreach (BSPrim bp in m_children)
207 {
208 com += bp.Position * bp.MassRaw;
209 totalMass += bp.MassRaw;
210 }
211 com /= totalMass;
212
213 return com;
214 }
215
216 private OMV.Vector3 ComputeLinksetGeometricCenter()
217 {
218 OMV.Vector3 com = m_linksetRoot.Position;
219
220 foreach (BSPrim bp in m_children)
221 {
222 com += bp.Position * bp.MassRaw;
223 }
224 com /= m_children.Count + 1;
225
226 return com;
227 }
228
229 // I am the root of a linkset and a new child is being added
230 public void AddChildToLinkset(BSPrim pchild)
231 {
232 BSPrim child = pchild;
233 if (!HasChild(child))
234 {
235 m_children.Add(child);
236
237 m_scene.TaintedObject(delegate()
238 {
239 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
240 DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
241 PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child
242 });
243 }
244 return;
245 }
246
247 // I am the root of a linkset and one of my children is being removed.
248 // Safe to call even if the child is not really in my linkset.
249 public void RemoveChildFromLinkset(BSPrim pchild)
250 {
251 BSPrim child = pchild;
252
253 if (m_children.Remove(child))
254 {
255 m_scene.TaintedObject(delegate()
256 {
257 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
258 DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
259
260 if (m_children.Count == 0)
261 {
262 // if the linkset is empty, make sure all linkages have been removed
263 PhysicallyUnlinkAllChildrenFromRoot();
264 }
265 else
266 {
267 PhysicallyUnlinkAChildFromRoot(pchild);
268 }
269 });
270 }
271 else
272 {
273 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
274 // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
275 }
276 return;
277 }
278
279 // Create a constraint between me (root of linkset) and the passed prim (the child).
280 // Called at taint time!
281 private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
282 {
283 // Zero motion for children so they don't interpolate
284 childPrim.ZeroMotion();
285
286 // relative position normalized to the root prim
287 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation);
288 OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation;
289
290 // relative rotation of the child to the parent
291 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
292
293 // create a constraint that allows no freedom of movement between the two objects
294 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
295 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
296 DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
297 BSConstraint constrain = m_scene.Constraints.CreateConstraint(
298 m_scene.World, m_linksetRoot.Body, childPrim.Body,
299 // childRelativePosition,
300 // childRelativeRotation,
301 OMV.Vector3.Zero,
302 OMV.Quaternion.Identity,
303 OMV.Vector3.Zero,
304 OMV.Quaternion.Identity
305 );
306 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
307 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
308
309 // tweek the constraint to increase stability
310 constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset));
311 constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor),
312 m_scene.Params.linkConstraintTransMotorMaxVel,
313 m_scene.Params.linkConstraintTransMotorMaxForce);
314 constrain.SetCFMAndERP(m_scene.Params.linkConstraintCFM, m_scene.Params.linkConstraintERP);
315
316 }
317
318 // Remove linkage between myself and a particular child
319 // Called at taint time!
320 private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim)
321 {
322 DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
323 LogHeader, m_linksetRoot.LocalID, childPrim.LocalID);
324 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
325 // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
326 m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body);
327 }
328
329 // Remove linkage between myself and any possible children I might have
330 // Called at taint time!
331 private void PhysicallyUnlinkAllChildrenFromRoot()
332 {
333 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
334 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID);
335 m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
336 // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
337 }
338
339 // Invoke the detailed logger and output something if it's enabled.
340 private void DebugLog(string msg, params Object[] args)
341 {
342 m_scene.Logger.DebugFormat(msg, args);
343 }
344
345 // Invoke the detailed logger and output something if it's enabled.
346 private void DetailLog(string msg, params Object[] args)
347 {
348 m_scene.PhysicsLogging.Write(msg, args);
349 }
350
351}
352}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 130f1ca..a4ab702 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -42,6 +42,8 @@ public sealed class BSPrim : PhysicsActor
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]"; 43 private static readonly string LogHeader = "[BULLETS PRIM]";
44 44
45 private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); }
46
45 private IMesh _mesh; 47 private IMesh _mesh;
46 private PrimitiveBaseShape _pbs; 48 private PrimitiveBaseShape _pbs;
47 private ShapeData.PhysicsShapeType _shapeType; 49 private ShapeData.PhysicsShapeType _shapeType;
@@ -50,6 +52,7 @@ public sealed class BSPrim : PhysicsActor
50 private List<ConvexResult> _hulls; 52 private List<ConvexResult> _hulls;
51 53
52 private BSScene _scene; 54 private BSScene _scene;
55 public BSScene Scene { get { return _scene; } }
53 private String _avName; 56 private String _avName;
54 private uint _localID = 0; 57 private uint _localID = 0;
55 58
@@ -63,7 +66,7 @@ public sealed class BSPrim : PhysicsActor
63 private bool _isSelected; 66 private bool _isSelected;
64 private bool _isVolumeDetect; 67 private bool _isVolumeDetect;
65 private OMV.Vector3 _position; 68 private OMV.Vector3 _position;
66 private float _mass; 69 private float _mass; // the mass of this object
67 private float _density; 70 private float _density;
68 private OMV.Vector3 _force; 71 private OMV.Vector3 _force;
69 private OMV.Vector3 _velocity; 72 private OMV.Vector3 _velocity;
@@ -86,14 +89,25 @@ public sealed class BSPrim : PhysicsActor
86 private bool _kinematic; 89 private bool _kinematic;
87 private float _buoyancy; 90 private float _buoyancy;
88 91
89 private List<BSPrim> _childrenPrims; 92 // Membership in a linkset is controlled by this class.
90 private BSPrim _parentPrim; 93 private BSLinkset _linkset;
94 public BSLinkset Linkset
95 {
96 get { return _linkset; }
97 set { _linkset = value; }
98 }
91 99
92 private int _subscribedEventsMs = 0; 100 private int _subscribedEventsMs = 0;
93 private int _nextCollisionOkTime = 0; 101 private int _nextCollisionOkTime = 0;
94 long _collidingStep; 102 long _collidingStep;
95 long _collidingGroundStep; 103 long _collidingGroundStep;
96 104
105 private BulletBody m_body;
106 public BulletBody Body {
107 get { return m_body; }
108 set { m_body = value; }
109 }
110
97 private BSDynamics _vehicle; 111 private BSDynamics _vehicle;
98 112
99 private OMV.Vector3 _PIDTarget; 113 private OMV.Vector3 _PIDTarget;
@@ -127,17 +141,18 @@ public sealed class BSPrim : PhysicsActor
127 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 141 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
128 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 142 _density = _scene.Params.defaultDensity; // TODO: compute based on object material
129 _restitution = _scene.Params.defaultRestitution; 143 _restitution = _scene.Params.defaultRestitution;
130 _parentPrim = null; // not a child or a parent 144 _linkset = new BSLinkset(_scene, this); // a linkset of one
131 _vehicle = new BSDynamics(this); // add vehicleness 145 _vehicle = new BSDynamics(this); // add vehicleness
132 _childrenPrims = new List<BSPrim>(); 146 _mass = CalculateMass();
133 if (_isPhysical)
134 _mass = CalculateMass();
135 else
136 _mass = 0f;
137 // do the actual object creation at taint time 147 // do the actual object creation at taint time
138 _scene.TaintedObject(delegate() 148 _scene.TaintedObject(delegate()
139 { 149 {
140 RecreateGeomAndObject(); 150 RecreateGeomAndObject();
151
152 // Get the pointer to the physical body for this object.
153 // At the moment, we're still letting BulletSim manage the creation and destruction
154 // of the object. Someday we'll move that into the C# code.
155 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
141 }); 156 });
142 } 157 }
143 158
@@ -145,13 +160,19 @@ public sealed class BSPrim : PhysicsActor
145 public void Destroy() 160 public void Destroy()
146 { 161 {
147 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 162 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
163 // DetailLog("{0},Destroy", LocalID);
164
148 // Undo any vehicle properties 165 // Undo any vehicle properties
149 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); 166 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
150 _scene.RemoveVehiclePrim(this); // just to make sure 167 _scene.RemoveVehiclePrim(this); // just to make sure
168
151 _scene.TaintedObject(delegate() 169 _scene.TaintedObject(delegate()
152 { 170 {
171 // Undo any links between me and any other object
172 _linkset = _linkset.RemoveMeFromLinkset(this);
173
153 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 174 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
154 BulletSimAPI.DestroyObject(_scene.WorldID, _localID); 175 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
155 }); 176 });
156 } 177 }
157 178
@@ -164,8 +185,9 @@ public sealed class BSPrim : PhysicsActor
164 _size = value; 185 _size = value;
165 _scene.TaintedObject(delegate() 186 _scene.TaintedObject(delegate()
166 { 187 {
167 if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass 188 _mass = CalculateMass(); // changing size changes the mass
168 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical); 189 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
190 DetailLog("{0}: setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
169 RecreateGeomAndObject(); 191 RecreateGeomAndObject();
170 }); 192 });
171 } 193 }
@@ -175,7 +197,7 @@ public sealed class BSPrim : PhysicsActor
175 _pbs = value; 197 _pbs = value;
176 _scene.TaintedObject(delegate() 198 _scene.TaintedObject(delegate()
177 { 199 {
178 if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass 200 _mass = CalculateMass(); // changing the shape changes the mass
179 RecreateGeomAndObject(); 201 RecreateGeomAndObject();
180 }); 202 });
181 } 203 }
@@ -202,33 +224,10 @@ public sealed class BSPrim : PhysicsActor
202 // link me to the specified parent 224 // link me to the specified parent
203 public override void link(PhysicsActor obj) { 225 public override void link(PhysicsActor obj) {
204 BSPrim parent = obj as BSPrim; 226 BSPrim parent = obj as BSPrim;
205 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); 227 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
206 // TODO: decide if this parent checking needs to happen at taint time 228 DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
207 if (_parentPrim == null) 229
208 { 230 _linkset = _linkset.AddMeToLinkset(this, parent);
209 if (parent != null)
210 {
211 // I don't have a parent so I am joining a linkset
212 parent.AddChildToLinkset(this);
213 }
214 }
215 else
216 {
217 // I already have a parent, is parenting changing?
218 if (parent != _parentPrim)
219 {
220 if (parent == null)
221 {
222 // we are being removed from a linkset
223 _parentPrim.RemoveChildFromLinkset(this);
224 }
225 else
226 {
227 // asking to reparent a prim should not happen
228 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
229 }
230 }
231 }
232 return; 231 return;
233 } 232 }
234 233
@@ -236,101 +235,92 @@ public sealed class BSPrim : PhysicsActor
236 public override void delink() { 235 public override void delink() {
237 // TODO: decide if this parent checking needs to happen at taint time 236 // TODO: decide if this parent checking needs to happen at taint time
238 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 237 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
239 // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID); 238 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
240 if (_parentPrim != null) 239 _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
241 { 240 DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
242 _parentPrim.RemoveChildFromLinkset(this);
243 }
244 return;
245 }
246
247 // I am the root of a linkset and a new child is being added
248 public void AddChildToLinkset(BSPrim pchild)
249 {
250 BSPrim child = pchild;
251 _scene.TaintedObject(delegate()
252 {
253 if (!_childrenPrims.Contains(child))
254 {
255 _childrenPrims.Add(child);
256 child.ParentPrim = this; // the child has gained a parent
257 RecreateGeomAndObject(); // rebuild my shape with the new child added
258 }
259 });
260 return;
261 }
262
263 // I am the root of a linkset and one of my children is being removed.
264 // Safe to call even if the child is not really in my linkset.
265 public void RemoveChildFromLinkset(BSPrim pchild)
266 {
267 BSPrim child = pchild;
268 _scene.TaintedObject(delegate()
269 {
270 if (_childrenPrims.Contains(child))
271 {
272 BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID);
273 _childrenPrims.Remove(child);
274 child.ParentPrim = null; // the child has lost its parent
275 RecreateGeomAndObject(); // rebuild my shape with the child removed
276 }
277 else
278 {
279 m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
280 }
281 });
282 return;
283 }
284
285 public BSPrim ParentPrim
286 {
287 set { _parentPrim = value; }
288 }
289 241
290 // return true if we are the root of a linkset (there are children to manage) 242 _linkset.RemoveMeFromLinkset(this);
291 public bool IsRootOfLinkset 243 return;
292 {
293 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
294 } 244 }
295 245
296 // Set motion values to zero. 246 // Set motion values to zero.
297 // Do it to the properties so the values get set in the physics engine. 247 // Do it to the properties so the values get set in the physics engine.
298 // Push the setting of the values to the viewer. 248 // Push the setting of the values to the viewer.
299 private void ZeroMotion() 249 // Called at taint time!
250 public void ZeroMotion()
300 { 251 {
301 Velocity = OMV.Vector3.Zero; 252 _velocity = OMV.Vector3.Zero;
302 _acceleration = OMV.Vector3.Zero; 253 _acceleration = OMV.Vector3.Zero;
303 RotationalVelocity = OMV.Vector3.Zero; 254 _rotationalVelocity = OMV.Vector3.Zero;
304 base.RequestPhysicsterseUpdate(); 255
256 // Zero some other properties directly into the physics engine
257 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero);
258 BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
259 BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
260 BulletSimAPI.ClearForces2(Body.Ptr);
305 } 261 }
306 262
307 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 263 public override void LockAngularMotion(OMV.Vector3 axis)
264 {
265 DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis);
266 return;
267 }
308 268
309 public override OMV.Vector3 Position { 269 public override OMV.Vector3 Position {
310 get { 270 get {
311 // don't do the following GetObjectPosition because this function is called a zillion times 271 if (!_linkset.IsRoot(this))
272 // child prims move around based on their parent. Need to get the latest location
273 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
274
275 // don't do the GetObjectPosition for root elements because this function is called a zillion times
312 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 276 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
313 return _position; 277 return _position;
314 } 278 }
315 set { 279 set {
316 _position = value; 280 _position = value;
281 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
317 _scene.TaintedObject(delegate() 282 _scene.TaintedObject(delegate()
318 { 283 {
284 DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
319 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 285 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
320 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
321 }); 286 });
322 } 287 }
323 } 288 }
324 public override float Mass { 289
325 get { return _mass; } 290 // Return the effective mass of the object.
291 // If there are multiple items in the linkset, add them together for the root
292 public override float Mass
293 {
294 get
295 {
296 return _linkset.LinksetMass;
297 }
298 }
299
300 // used when we only want this prim's mass and not the linkset thing
301 public float MassRaw { get { return _mass; } }
302
303 // Is this used?
304 public override OMV.Vector3 CenterOfMass
305 {
306 get { return _linkset.CenterOfMass; }
307 }
308
309 // Is this used?
310 public override OMV.Vector3 GeometricCenter
311 {
312 get { return _linkset.GeometricCenter; }
326 } 313 }
314
327 public override OMV.Vector3 Force { 315 public override OMV.Vector3 Force {
328 get { return _force; } 316 get { return _force; }
329 set { 317 set {
330 _force = value; 318 _force = value;
331 _scene.TaintedObject(delegate() 319 _scene.TaintedObject(delegate()
332 { 320 {
333 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 321 DetailLog("{0},SetForce,taint,force={1}", LocalID, _force);
322 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
323 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
334 }); 324 });
335 } 325 }
336 } 326 }
@@ -341,15 +331,22 @@ public sealed class BSPrim : PhysicsActor
341 } 331 }
342 set { 332 set {
343 Vehicle type = (Vehicle)value; 333 Vehicle type = (Vehicle)value;
344 _vehicle.ProcessTypeChange(type);
345 _scene.TaintedObject(delegate() 334 _scene.TaintedObject(delegate()
346 { 335 {
336 DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type);
337 _vehicle.ProcessTypeChange(type);
347 if (type == Vehicle.TYPE_NONE) 338 if (type == Vehicle.TYPE_NONE)
348 { 339 {
349 _scene.RemoveVehiclePrim(this); 340 _scene.RemoveVehiclePrim(this);
350 } 341 }
351 else 342 else
352 { 343 {
344 _scene.TaintedObject(delegate()
345 {
346 // Tell the physics engine to clear state
347 BulletSimAPI.ClearForces2(this.Body.Ptr);
348 });
349
353 // make it so the scene will call us each tick to do vehicle things 350 // make it so the scene will call us each tick to do vehicle things
354 _scene.AddVehiclePrim(this); 351 _scene.AddVehiclePrim(this);
355 } 352 }
@@ -359,47 +356,59 @@ public sealed class BSPrim : PhysicsActor
359 } 356 }
360 public override void VehicleFloatParam(int param, float value) 357 public override void VehicleFloatParam(int param, float value)
361 { 358 {
362 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 359 _scene.TaintedObject(delegate()
360 {
361 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
362 });
363 } 363 }
364 public override void VehicleVectorParam(int param, OMV.Vector3 value) 364 public override void VehicleVectorParam(int param, OMV.Vector3 value)
365 { 365 {
366 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 366 _scene.TaintedObject(delegate()
367 {
368 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
369 });
367 } 370 }
368 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 371 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
369 { 372 {
370 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 373 _scene.TaintedObject(delegate()
374 {
375 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
376 });
371 } 377 }
372 public override void VehicleFlags(int param, bool remove) 378 public override void VehicleFlags(int param, bool remove)
373 { 379 {
374 _vehicle.ProcessVehicleFlags(param, remove); 380 _scene.TaintedObject(delegate()
381 {
382 _vehicle.ProcessVehicleFlags(param, remove);
383 });
375 } 384 }
376 // Called each simulation step to advance vehicle characteristics 385
386 // Called each simulation step to advance vehicle characteristics.
387 // Called from Scene when doing simulation step so we're in taint processing time.
377 public void StepVehicle(float timeStep) 388 public void StepVehicle(float timeStep)
378 { 389 {
379 _vehicle.Step(timeStep, _scene); 390 if (IsPhysical)
391 _vehicle.Step(timeStep);
380 } 392 }
381 393
382 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 394 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
383 public override void SetVolumeDetect(int param) { 395 public override void SetVolumeDetect(int param) {
384 bool newValue = (param != 0); 396 bool newValue = (param != 0);
385 if (_isVolumeDetect != newValue) 397 _isVolumeDetect = newValue;
398 _scene.TaintedObject(delegate()
386 { 399 {
387 _isVolumeDetect = newValue; 400 SetObjectDynamic();
388 _scene.TaintedObject(delegate() 401 });
389 {
390 SetObjectDynamic();
391 });
392 }
393 return; 402 return;
394 } 403 }
395 404
396 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
397 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
398 public override OMV.Vector3 Velocity { 405 public override OMV.Vector3 Velocity {
399 get { return _velocity; } 406 get { return _velocity; }
400 set { _velocity = value; 407 set {
408 _velocity = value;
401 _scene.TaintedObject(delegate() 409 _scene.TaintedObject(delegate()
402 { 410 {
411 DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity);
403 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 412 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
404 }); 413 });
405 } 414 }
@@ -407,6 +416,7 @@ public sealed class BSPrim : PhysicsActor
407 public override OMV.Vector3 Torque { 416 public override OMV.Vector3 Torque {
408 get { return _torque; } 417 get { return _torque; }
409 set { _torque = value; 418 set { _torque = value;
419 DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque);
410 } 420 }
411 } 421 }
412 public override float CollisionScore { 422 public override float CollisionScore {
@@ -419,13 +429,21 @@ public sealed class BSPrim : PhysicsActor
419 set { _acceleration = value; } 429 set { _acceleration = value; }
420 } 430 }
421 public override OMV.Quaternion Orientation { 431 public override OMV.Quaternion Orientation {
422 get { return _orientation; } 432 get {
433 if (!_linkset.IsRoot(this))
434 {
435 // Children move around because tied to parent. Get a fresh value.
436 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
437 }
438 return _orientation;
439 }
423 set { 440 set {
424 _orientation = value; 441 _orientation = value;
425 // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); 442 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
426 _scene.TaintedObject(delegate() 443 _scene.TaintedObject(delegate()
427 { 444 {
428 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 445 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
446 DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
429 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 447 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
430 }); 448 });
431 } 449 }
@@ -458,25 +476,24 @@ public sealed class BSPrim : PhysicsActor
458 get { return !IsPhantom && !_isVolumeDetect; } 476 get { return !IsPhantom && !_isVolumeDetect; }
459 } 477 }
460 478
461 // make gravity work if the object is physical and not selected 479 // Make gravity work if the object is physical and not selected
462 // no locking here because only called when it is safe 480 // No locking here because only called when it is safe
481 // Only called at taint time so it is save to call into Bullet.
463 private void SetObjectDynamic() 482 private void SetObjectDynamic()
464 { 483 {
465 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); 484 // RA: remove this for the moment.
466 // non-physical things work best with a mass of zero 485 // The problem is that dynamic objects are hulls so if we are becoming physical
467 if (IsStatic) 486 // the shape has to be checked and possibly built.
468 { 487 // Maybe a VerifyCorrectPhysicalShape() routine?
469 _mass = 0f; 488 // RecreateGeomAndObject();
470 }
471 else
472 {
473 _mass = CalculateMass();
474 // If it's dynamic, make sure the hull has been created for it
475 // This shouldn't do much work if the object had previously been built
476 RecreateGeomAndObject();
477 489
478 } 490 float mass = _mass;
479 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); 491 // Bullet wants static objects have a mass of zero
492 if (IsStatic)
493 mass = 0f;
494
495 DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
496 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
480 } 497 }
481 498
482 // prims don't fly 499 // prims don't fly
@@ -516,11 +533,24 @@ public sealed class BSPrim : PhysicsActor
516 set { _floatOnWater = value; } 533 set { _floatOnWater = value; }
517 } 534 }
518 public override OMV.Vector3 RotationalVelocity { 535 public override OMV.Vector3 RotationalVelocity {
519 get { return _rotationalVelocity; } 536 get {
520 set { _rotationalVelocity = value; 537 /*
538 OMV.Vector3 pv = OMV.Vector3.Zero;
539 // if close to zero, report zero
540 // This is copied from ODE but I'm not sure why it returns zero but doesn't
541 // zero the property in the physics engine.
542 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
543 return pv;
544 */
545
546 return _rotationalVelocity;
547 }
548 set {
549 _rotationalVelocity = value;
521 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 550 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
522 _scene.TaintedObject(delegate() 551 _scene.TaintedObject(delegate()
523 { 552 {
553 DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
524 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 554 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
525 }); 555 });
526 } 556 }
@@ -533,11 +563,13 @@ public sealed class BSPrim : PhysicsActor
533 } 563 }
534 public override float Buoyancy { 564 public override float Buoyancy {
535 get { return _buoyancy; } 565 get { return _buoyancy; }
536 set { _buoyancy = value; 566 set {
537 _scene.TaintedObject(delegate() 567 _buoyancy = value;
538 { 568 _scene.TaintedObject(delegate()
539 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); 569 {
540 }); 570 DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
571 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
572 });
541 } 573 }
542 } 574 }
543 575
@@ -573,27 +605,45 @@ public sealed class BSPrim : PhysicsActor
573 public override float APIDStrength { set { return; } } 605 public override float APIDStrength { set { return; } }
574 public override float APIDDamping { set { return; } } 606 public override float APIDDamping { set { return; } }
575 607
608 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
576 public override void AddForce(OMV.Vector3 force, bool pushforce) { 609 public override void AddForce(OMV.Vector3 force, bool pushforce) {
577 if (force.IsFinite()) 610 if (force.IsFinite())
578 { 611 {
579 _force.X += force.X; 612 // _force += force;
580 _force.Y += force.Y; 613 lock (m_accumulatedForces)
581 _force.Z += force.Z; 614 m_accumulatedForces.Add(new OMV.Vector3(force));
582 } 615 }
583 else 616 else
584 { 617 {
585 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 618 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
619 return;
586 } 620 }
587 _scene.TaintedObject(delegate() 621 _scene.TaintedObject(delegate()
588 { 622 {
589 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 623 lock (m_accumulatedForces)
624 {
625 if (m_accumulatedForces.Count > 0)
626 {
627 OMV.Vector3 fSum = OMV.Vector3.Zero;
628 foreach (OMV.Vector3 v in m_accumulatedForces)
629 {
630 fSum += v;
631 }
632 m_accumulatedForces.Clear();
633
634 DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum);
635 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum);
636 }
637 }
590 }); 638 });
591 } 639 }
592 640
593 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 641 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
642 DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
594 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 643 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
595 } 644 }
596 public override void SetMomentum(OMV.Vector3 momentum) { 645 public override void SetMomentum(OMV.Vector3 momentum) {
646 DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum);
597 } 647 }
598 public override void SubscribeEvents(int ms) { 648 public override void SubscribeEvents(int ms) {
599 _subscribedEventsMs = ms; 649 _subscribedEventsMs = ms;
@@ -885,6 +935,9 @@ public sealed class BSPrim : PhysicsActor
885 935
886 returnMass = _density * volume; 936 returnMass = _density * volume;
887 937
938 /*
939 * This change means each object keeps its own mass and the Mass property
940 * will return the sum if we're part of a linkset.
888 if (IsRootOfLinkset) 941 if (IsRootOfLinkset)
889 { 942 {
890 foreach (BSPrim prim in _childrenPrims) 943 foreach (BSPrim prim in _childrenPrims)
@@ -892,6 +945,7 @@ public sealed class BSPrim : PhysicsActor
892 returnMass += prim.CalculateMass(); 945 returnMass += prim.CalculateMass();
893 } 946 }
894 } 947 }
948 */
895 949
896 if (returnMass <= 0) 950 if (returnMass <= 0)
897 returnMass = 0.0001f; 951 returnMass = 0.0001f;
@@ -907,9 +961,11 @@ public sealed class BSPrim : PhysicsActor
907 // The objects needs a hull if it's physical otherwise a mesh is enough 961 // The objects needs a hull if it's physical otherwise a mesh is enough
908 // No locking here because this is done when we know physics is not simulating 962 // No locking here because this is done when we know physics is not simulating
909 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used 963 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
910 private void CreateGeom(bool forceRebuild) 964 // Returns 'true' if the geometry was rebuilt
965 private bool CreateGeom(bool forceRebuild)
911 { 966 {
912 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. 967 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
968 bool ret = false;
913 if (!_scene.NeedsMeshing(_pbs)) 969 if (!_scene.NeedsMeshing(_pbs))
914 { 970 {
915 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) 971 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -917,16 +973,28 @@ public sealed class BSPrim : PhysicsActor
917 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) 973 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
918 { 974 {
919 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); 975 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
920 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; 976 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
921 // Bullet native objects are scaled by the Bullet engine so pass the size in 977 {
922 _scale = _size; 978 DetailLog("{0},CreateGeom,sphere", LocalID);
979 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
980 // Bullet native objects are scaled by the Bullet engine so pass the size in
981 _scale = _size;
982 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
983 ret = true;
984 }
923 } 985 }
924 } 986 }
925 else 987 else
926 { 988 {
927 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); 989 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
928 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; 990 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
929 _scale = _size; 991 {
992 DetailLog("{0},CreateGeom,box", LocalID);
993 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
994 _scale = _size;
995 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
996 ret = true;
997 }
930 } 998 }
931 } 999 }
932 else 1000 else
@@ -938,6 +1006,7 @@ public sealed class BSPrim : PhysicsActor
938 // physical objects require a hull for interaction. 1006 // physical objects require a hull for interaction.
939 // This will create the mesh if it doesn't already exist 1007 // This will create the mesh if it doesn't already exist
940 CreateGeomHull(); 1008 CreateGeomHull();
1009 ret = true;
941 } 1010 }
942 } 1011 }
943 else 1012 else
@@ -946,9 +1015,11 @@ public sealed class BSPrim : PhysicsActor
946 { 1015 {
947 // Static (non-physical) objects only need a mesh for bumping into 1016 // Static (non-physical) objects only need a mesh for bumping into
948 CreateGeomMesh(); 1017 CreateGeomMesh();
1018 ret = true;
949 } 1019 }
950 } 1020 }
951 } 1021 }
1022 return ret;
952 } 1023 }
953 1024
954 // No locking here because this is done when we know physics is not simulating 1025 // No locking here because this is done when we know physics is not simulating
@@ -961,10 +1032,12 @@ public sealed class BSPrim : PhysicsActor
961 // if this new shape is the same as last time, don't recreate the mesh 1032 // if this new shape is the same as last time, don't recreate the mesh
962 if (_meshKey == newMeshKey) return; 1033 if (_meshKey == newMeshKey) return;
963 1034
1035 DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey);
964 // Since we're recreating new, get rid of any previously generated shape 1036 // Since we're recreating new, get rid of any previously generated shape
965 if (_meshKey != 0) 1037 if (_meshKey != 0)
966 { 1038 {
967 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); 1039 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1040 DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
968 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1041 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
969 _mesh = null; 1042 _mesh = null;
970 _meshKey = 0; 1043 _meshKey = 0;
@@ -981,7 +1054,6 @@ public sealed class BSPrim : PhysicsActor
981 int vi = 0; 1054 int vi = 0;
982 foreach (OMV.Vector3 vv in vertices) 1055 foreach (OMV.Vector3 vv in vertices)
983 { 1056 {
984 // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z);
985 verticesAsFloats[vi++] = vv.X; 1057 verticesAsFloats[vi++] = vv.X;
986 verticesAsFloats[vi++] = vv.Y; 1058 verticesAsFloats[vi++] = vv.Y;
987 verticesAsFloats[vi++] = vv.Z; 1059 verticesAsFloats[vi++] = vv.Z;
@@ -995,6 +1067,7 @@ public sealed class BSPrim : PhysicsActor
995 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; 1067 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
996 // meshes are already scaled by the meshmerizer 1068 // meshes are already scaled by the meshmerizer
997 _scale = new OMV.Vector3(1f, 1f, 1f); 1069 _scale = new OMV.Vector3(1f, 1f, 1f);
1070 DetailLog("{0},CreateGeomMesh,done", LocalID);
998 return; 1071 return;
999 } 1072 }
1000 1073
@@ -1008,13 +1081,17 @@ public sealed class BSPrim : PhysicsActor
1008 // if the hull hasn't changed, don't rebuild it 1081 // if the hull hasn't changed, don't rebuild it
1009 if (newHullKey == _hullKey) return; 1082 if (newHullKey == _hullKey) return;
1010 1083
1084 DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey);
1085
1011 // Since we're recreating new, get rid of any previously generated shape 1086 // Since we're recreating new, get rid of any previously generated shape
1012 if (_hullKey != 0) 1087 if (_hullKey != 0)
1013 { 1088 {
1014 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); 1089 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1090 DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey);
1015 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); 1091 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1016 _hullKey = 0; 1092 _hullKey = 0;
1017 _hulls.Clear(); 1093 _hulls.Clear();
1094 DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey);
1018 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1095 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1019 _mesh = null; // the mesh cannot match either 1096 _mesh = null; // the mesh cannot match either
1020 _meshKey = 0; 1097 _meshKey = 0;
@@ -1111,6 +1188,7 @@ public sealed class BSPrim : PhysicsActor
1111 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; 1188 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1112 // meshes are already scaled by the meshmerizer 1189 // meshes are already scaled by the meshmerizer
1113 _scale = new OMV.Vector3(1f, 1f, 1f); 1190 _scale = new OMV.Vector3(1f, 1f, 1f);
1191 DetailLog("{0},CreateGeomHull,done", LocalID);
1114 return; 1192 return;
1115 } 1193 }
1116 1194
@@ -1124,47 +1202,21 @@ public sealed class BSPrim : PhysicsActor
1124 1202
1125 // Create an object in Bullet if it has not already been created 1203 // Create an object in Bullet if it has not already been created
1126 // No locking here because this is done when the physics engine is not simulating 1204 // No locking here because this is done when the physics engine is not simulating
1127 private void CreateObject() 1205 // Returns 'true' if an object was actually created.
1206 private bool CreateObject()
1128 { 1207 {
1129 if (IsRootOfLinkset) 1208 // this routine is called when objects are rebuilt.
1130 {
1131 // Create a linkset around this object
1132 // CreateLinksetWithCompoundHull();
1133 CreateLinksetWithConstraints();
1134 }
1135 else
1136 {
1137 // simple object
1138 // the mesh or hull must have already been created in Bullet
1139 ShapeData shape;
1140 FillShapeInfo(out shape);
1141 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1142 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1143 }
1144 }
1145 1209
1146 // Create a linkset by creating a compound hull at the root prim that consists of all 1210 // the mesh or hull must have already been created in Bullet
1147 // the children. 1211 ShapeData shape;
1148 // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution 1212 FillShapeInfo(out shape);
1149 void CreateLinksetWithCompoundHull() 1213 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1150 { 1214 bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
1151 // If I am the root prim of a linkset, replace my physical shape with all the 1215
1152 // pieces of the children. 1216 // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
1153 // All of the children should have called CreateGeom so they have a hull 1217 m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID);
1154 // in the physics engine already. Here we pull together all of those hulls 1218
1155 // into one shape. 1219 return ret;
1156 int totalPrimsInLinkset = _childrenPrims.Count + 1;
1157 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
1158 ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
1159 FillShapeInfo(out shapes[0]);
1160 int ii = 1;
1161 foreach (BSPrim prim in _childrenPrims)
1162 {
1163 // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
1164 prim.FillShapeInfo(out shapes[ii]);
1165 ii++;
1166 }
1167 BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
1168 } 1220 }
1169 1221
1170 // Copy prim's info into the BulletSim shape description structure 1222 // Copy prim's info into the BulletSim shape description structure
@@ -1186,44 +1238,6 @@ public sealed class BSPrim : PhysicsActor
1186 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1238 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1187 } 1239 }
1188 1240
1189 // Create the linkset by putting constraints between the objects of the set so they cannot move
1190 // relative to each other.
1191 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added
1192 void CreateLinksetWithConstraints()
1193 {
1194 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1195
1196 // remove any constraints that might be in place
1197 foreach (BSPrim prim in _childrenPrims)
1198 {
1199 // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1200 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1201 }
1202 // create constraints between the root prim and each of the children
1203 foreach (BSPrim prim in _childrenPrims)
1204 {
1205 // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1206
1207 // Zero motion for children so they don't interpolate
1208 prim.ZeroMotion();
1209
1210 // relative position normalized to the root prim
1211 OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation);
1212
1213 // relative rotation of the child to the parent
1214 OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation;
1215
1216 // this is a constraint that allows no freedom of movement between the two objects
1217 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1218 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID,
1219 childRelativePosition,
1220 relativeRotation,
1221 OMV.Vector3.Zero,
1222 OMV.Quaternion.Identity,
1223 OMV.Vector3.Zero, OMV.Vector3.Zero,
1224 OMV.Vector3.Zero, OMV.Vector3.Zero);
1225 }
1226 }
1227 1241
1228 // Rebuild the geometry and object. 1242 // Rebuild the geometry and object.
1229 // This is called when the shape changes so we need to recreate the mesh/hull. 1243 // This is called when the shape changes so we need to recreate the mesh/hull.
@@ -1231,8 +1245,8 @@ public sealed class BSPrim : PhysicsActor
1231 private void RecreateGeomAndObject() 1245 private void RecreateGeomAndObject()
1232 { 1246 {
1233 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); 1247 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID);
1234 CreateGeom(true); 1248 if (CreateGeom(true))
1235 CreateObject(); 1249 CreateObject();
1236 return; 1250 return;
1237 } 1251 }
1238 1252
@@ -1252,78 +1266,78 @@ public sealed class BSPrim : PhysicsActor
1252 const float POSITION_TOLERANCE = 0.05f; 1266 const float POSITION_TOLERANCE = 0.05f;
1253 const float ACCELERATION_TOLERANCE = 0.01f; 1267 const float ACCELERATION_TOLERANCE = 0.01f;
1254 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1268 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1255 const bool SHOULD_DAMP_UPDATES = false;
1256 1269
1257 public void UpdateProperties(EntityProperties entprop) 1270 public void UpdateProperties(EntityProperties entprop)
1258 { 1271 {
1272 /*
1259 UpdatedProperties changed = 0; 1273 UpdatedProperties changed = 0;
1260 if (SHOULD_DAMP_UPDATES) 1274 // assign to the local variables so the normal set action does not happen
1275 // if (_position != entprop.Position)
1276 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1261 { 1277 {
1262 // assign to the local variables so the normal set action does not happen 1278 _position = entprop.Position;
1263 // if (_position != entprop.Position) 1279 changed |= UpdatedProperties.Position;
1264 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1265 {
1266 _position = entprop.Position;
1267 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position);
1268 changed |= UpdatedProperties.Position;
1269 }
1270 // if (_orientation != entprop.Rotation)
1271 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1272 {
1273 _orientation = entprop.Rotation;
1274 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation);
1275 changed |= UpdatedProperties.Rotation;
1276 }
1277 // if (_velocity != entprop.Velocity)
1278 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1279 {
1280 _velocity = entprop.Velocity;
1281 // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
1282 changed |= UpdatedProperties.Velocity;
1283 }
1284 // if (_acceleration != entprop.Acceleration)
1285 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1286 {
1287 _acceleration = entprop.Acceleration;
1288 // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
1289 changed |= UpdatedProperties.Acceleration;
1290 }
1291 // if (_rotationalVelocity != entprop.RotationalVelocity)
1292 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1293 {
1294 _rotationalVelocity = entprop.RotationalVelocity;
1295 // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
1296 changed |= UpdatedProperties.RotationalVel;
1297 }
1298 if (changed != 0)
1299 {
1300 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1301 // Only update the position of single objects and linkset roots
1302 if (this._parentPrim == null)
1303 {
1304 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1305 base.RequestPhysicsterseUpdate();
1306 }
1307 }
1308 } 1280 }
1309 else 1281 // if (_orientation != entprop.Rotation)
1282 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1310 { 1283 {
1311 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1284 _orientation = entprop.Rotation;
1312 1285 changed |= UpdatedProperties.Rotation;
1313 // Only updates only for individual prims and for the root object of a linkset. 1286 }
1287 // if (_velocity != entprop.Velocity)
1288 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1289 {
1290 _velocity = entprop.Velocity;
1291 changed |= UpdatedProperties.Velocity;
1292 }
1293 // if (_acceleration != entprop.Acceleration)
1294 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1295 {
1296 _acceleration = entprop.Acceleration;
1297 changed |= UpdatedProperties.Acceleration;
1298 }
1299 // if (_rotationalVelocity != entprop.RotationalVelocity)
1300 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1301 {
1302 _rotationalVelocity = entprop.RotationalVelocity;
1303 changed |= UpdatedProperties.RotationalVel;
1304 }
1305 if (changed != 0)
1306 {
1307 // Only update the position of single objects and linkset roots
1314 if (this._parentPrim == null) 1308 if (this._parentPrim == null)
1315 { 1309 {
1316 // Assign to the local variables so the normal set action does not happen
1317 _position = entprop.Position;
1318 _orientation = entprop.Rotation;
1319 _velocity = entprop.Velocity;
1320 _acceleration = entprop.Acceleration;
1321 _rotationalVelocity = entprop.RotationalVelocity;
1322 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1323 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1324 base.RequestPhysicsterseUpdate(); 1310 base.RequestPhysicsterseUpdate();
1325 } 1311 }
1326 } 1312 }
1313 */
1314
1315 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1316
1317 // Updates only for individual prims and for the root object of a linkset.
1318 if (_linkset.IsRoot(this))
1319 {
1320 // Assign to the local variables so the normal set action does not happen
1321 _position = entprop.Position;
1322 _orientation = entprop.Rotation;
1323 _velocity = entprop.Velocity;
1324 _acceleration = entprop.Acceleration;
1325 _rotationalVelocity = entprop.RotationalVelocity;
1326
1327 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1328 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1329 DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1330 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1331
1332 base.RequestPhysicsterseUpdate();
1333 }
1334 else
1335 {
1336 // For debugging, we can also report the movement of children
1337 DetailLog("{0},UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1338 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1339 entprop.Acceleration, entprop.RotationalVelocity);
1340 }
1327 } 1341 }
1328 1342
1329 // I've collided with something 1343 // I've collided with something
@@ -1362,5 +1376,11 @@ public sealed class BSPrim : PhysicsActor
1362 collisionCollection.Clear(); 1376 collisionCollection.Clear();
1363 } 1377 }
1364 } 1378 }
1379
1380 // Invoke the detailed logger and output something if it's enabled.
1381 private void DetailLog(string msg, params Object[] args)
1382 {
1383 Scene.PhysicsLogging.Write(msg, args);
1384 }
1365} 1385}
1366} 1386}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f..28d5cb5 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -29,12 +29,14 @@ using System.Collections.Generic;
29using System.Runtime.InteropServices; 29using System.Runtime.InteropServices;
30using System.Text; 30using System.Text;
31using System.Threading; 31using System.Threading;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Framework;
34using OpenSim.Region.CoreModules;
35using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
35using OpenSim.Region.Physics.Manager; 36using OpenSim.Region.Physics.Manager;
37using Nini.Config;
38using log4net;
36using OpenMetaverse; 39using OpenMetaverse;
37using OpenSim.Region.Framework;
38 40
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Debug linkset 42// Debug linkset
@@ -44,15 +46,17 @@ using OpenSim.Region.Framework;
44// Compute physics FPS reasonably 46// Compute physics FPS reasonably
45// Based on material, set density and friction 47// Based on material, set density and friction
46// More efficient memory usage when passing hull information from BSPrim to BulletSim 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.
47// 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?
48// 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)
49// 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
50// 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
51// Check out llVolumeDetect. Must do something for that. 55// Check out llVolumeDetect. Must do something for that.
52// 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?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root.
53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
54// 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
55// Use collision masks for collision with terrain and phantom objects
56// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) 60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
57// Implement LockAngularMotion 61// Implement LockAngularMotion
58// 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)
@@ -60,9 +64,6 @@ using OpenSim.Region.Framework;
60// 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.
61// Add PID movement operations. What does ScenePresence.MoveToTarget do? 65// Add PID movement operations. What does ScenePresence.MoveToTarget do?
62// Check terrain size. 128 or 127? 66// Check terrain size. 128 or 127?
63// Multiple contact points on collision?
64// See code in ode::near... calls to collision_accounting_events()
65// (This might not be a problem. ODE collects all the collisions with one object in one tick.)
66// Raycast 67// Raycast
67// 68//
68namespace OpenSim.Region.Physics.BulletSPlugin 69namespace OpenSim.Region.Physics.BulletSPlugin
@@ -72,6 +73,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
72 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);
73 private static readonly string LogHeader = "[BULLETS SCENE]"; 74 private static readonly string LogHeader = "[BULLETS SCENE]";
74 75
76 public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
77
75 public string BulletSimVersion = "?"; 78 public string BulletSimVersion = "?";
76 79
77 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
@@ -84,6 +87,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
84 private uint m_worldID; 87 private uint m_worldID;
85 public uint WorldID { get { return m_worldID; } } 88 public uint WorldID { get { return m_worldID; } }
86 89
90 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } }
92
87 private bool m_initialized = false; 93 private bool m_initialized = false;
88 94
89 private int m_detailedStatsStep = 0; 95 private int m_detailedStatsStep = 0;
@@ -100,11 +106,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
100 get { return m_sculptLOD; } 106 get { return m_sculptLOD; }
101 } 107 }
102 108
109 private BulletSim m_worldSim;
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 }
119
103 private int m_maxSubSteps; 120 private int m_maxSubSteps;
104 private float m_fixedTimeStep; 121 private float m_fixedTimeStep;
105 private long m_simulationStep = 0; 122 private long m_simulationStep = 0;
106 public long SimulationStep { get { return m_simulationStep; } } 123 public long SimulationStep { get { return m_simulationStep; } }
107 124
125 public float LastSimulatedTimestep { get; private set; }
126
108 // 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
109 // 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
110 private int m_simulationNowTime; 129 private int m_simulationNowTime;
@@ -121,6 +140,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
121 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
122 private bool _forceSimplePrimMeshing = false; // 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
123 142
143 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional
145
124 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
125 public const uint GROUNDPLANE_ID = 1; 147 public const uint GROUNDPLANE_ID = 1;
126 148
@@ -147,8 +169,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
147 ConfigurationParameters[] m_params; 169 ConfigurationParameters[] m_params;
148 GCHandle m_paramsHandle; 170 GCHandle m_paramsHandle;
149 171
172 public bool shouldDebugLog { get; private set; }
173
150 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 174 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
151 175
176 // Sometimes you just have to log everything.
177 public Logging.LogWriter PhysicsLogging;
178 private bool m_physicsLoggingEnabled;
179 private string m_physicsLoggingDir;
180 private string m_physicsLoggingPrefix;
181 private int m_physicsLoggingFileMinutes;
182
183 private bool m_vehicleLoggingEnabled;
184 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
185
152 public BSScene(string identifier) 186 public BSScene(string identifier)
153 { 187 {
154 m_initialized = false; 188 m_initialized = false;
@@ -169,17 +203,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
169 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 203 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
170 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 204 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
171 205
206 // Enable very detailed logging.
207 // By creating an empty logger when not logging, the log message invocation code
208 // can be left in and every call doesn't have to check for null.
209 if (m_physicsLoggingEnabled)
210 {
211 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
212 }
213 else
214 {
215 PhysicsLogging = new Logging.LogWriter();
216 }
217
172 // Get the version of the DLL 218 // Get the version of the DLL
173 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 219 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
174 // BulletSimVersion = BulletSimAPI.GetVersion(); 220 // BulletSimVersion = BulletSimAPI.GetVersion();
175 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); 221 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
176 222
177 // if Debug, enable logging from the unmanaged code 223 // if Debug, enable logging from the unmanaged code
178 if (m_log.IsDebugEnabled) 224 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
179 { 225 {
180 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 226 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
181 // the handle is saved to it doesn't get freed after this call 227 if (PhysicsLogging.Enabled)
182 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 228 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
229 else
230 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
231 // the handle is saved in a variable to make sure it doesn't get freed after this call
183 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); 232 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
184 } 233 }
185 234
@@ -194,6 +243,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
194 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 243 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
195 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 244 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
196 245
246 // Initialization to support the transition to a new API which puts most of the logic
247 // into the C# code so it is easier to modify and add to.
248 m_worldSim = new BulletSim(m_worldID, BulletSimAPI.GetSimHandle2(m_worldID));
249 m_constraintCollection = new BSConstraintCollection(World);
250
197 m_initialized = true; 251 m_initialized = true;
198 } 252 }
199 253
@@ -202,110 +256,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
202 private void GetInitialParameterValues(IConfigSource config) 256 private void GetInitialParameterValues(IConfigSource config)
203 { 257 {
204 ConfigurationParameters parms = new ConfigurationParameters(); 258 ConfigurationParameters parms = new ConfigurationParameters();
259 m_params[0] = parms;
205 260
206 _meshSculptedPrim = true; // mesh sculpted prims 261 SetParameterDefaultValues();
207 _forceSimplePrimMeshing = false; // use complex meshing if called for
208
209 m_meshLOD = 8f;
210 m_sculptLOD = 32f;
211
212 m_detailedStatsStep = 0; // disabled
213
214 m_maxSubSteps = 10;
215 m_fixedTimeStep = 1f / 60f;
216 m_maxCollisionsPerFrame = 2048;
217 m_maxUpdatesPerFrame = 2048;
218 m_maximumObjectMass = 10000.01f;
219
220 parms.defaultFriction = 0.5f;
221 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
222 parms.defaultRestitution = 0f;
223 parms.collisionMargin = 0.0f;
224 parms.gravity = -9.80665f;
225
226 parms.linearDamping = 0.0f;
227 parms.angularDamping = 0.0f;
228 parms.deactivationTime = 0.2f;
229 parms.linearSleepingThreshold = 0.8f;
230 parms.angularSleepingThreshold = 1.0f;
231 parms.ccdMotionThreshold = 0.0f; // set to zero to disable
232 parms.ccdSweptSphereRadius = 0.0f;
233 parms.contactProcessingThreshold = 0.1f;
234
235 parms.terrainFriction = 0.5f;
236 parms.terrainHitFraction = 0.8f;
237 parms.terrainRestitution = 0f;
238 parms.avatarFriction = 0.5f;
239 parms.avatarRestitution = 0.0f;
240 parms.avatarDensity = 60f;
241 parms.avatarCapsuleRadius = 0.37f;
242 parms.avatarCapsuleHeight = 1.5f; // 2.140599f
243 parms.avatarContactProcessingThreshold = 0.1f;
244
245 parms.maxPersistantManifoldPoolSize = 0f;
246 parms.shouldDisableContactPoolDynamicAllocation = ConfigurationParameters.numericTrue;
247 parms.shouldForceUpdateAllAabbs = ConfigurationParameters.numericFalse;
248 parms.shouldRandomizeSolverOrder = ConfigurationParameters.numericFalse;
249 parms.shouldSplitSimulationIslands = ConfigurationParameters.numericFalse;
250 parms.shouldEnableFrictionCaching = ConfigurationParameters.numericFalse;
251 parms.numberOfSolverIterations = 0f; // means use default
252 262
253 if (config != null) 263 if (config != null)
254 { 264 {
255 // If there are specifications in the ini file, use those values 265 // If there are specifications in the ini file, use those values
256 // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini
257 // ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS.
258 IConfig pConfig = config.Configs["BulletSim"]; 266 IConfig pConfig = config.Configs["BulletSim"];
259 if (pConfig != null) 267 if (pConfig != null)
260 { 268 {
261 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); 269 SetParameterConfigurationValues(pConfig);
262 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); 270
263 271 // Very detailed logging for physics debugging
264 m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep); 272 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
265 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); 273 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
266 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); 274 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-");
267 275 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
268 m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps); 276 // Very detailed logging for vehicle debugging
269 m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep); 277 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
270 m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
271 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
272 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
273
274 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
275 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
276 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
277 parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
278 parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
279
280 parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
281 parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
282 parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
283 parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
284 parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
285 parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
286 parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
287 parms.contactProcessingThreshold = pConfig.GetFloat("ContactProcessingThreshold", parms.contactProcessingThreshold);
288
289 parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
290 parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
291 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
292 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
293 parms.avatarRestitution = pConfig.GetFloat("AvatarRestitution", parms.avatarRestitution);
294 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
295 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
296 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
297 parms.avatarContactProcessingThreshold = pConfig.GetFloat("AvatarContactProcessingThreshold", parms.avatarContactProcessingThreshold);
298
299 parms.maxPersistantManifoldPoolSize = pConfig.GetFloat("MaxPersistantManifoldPoolSize", parms.maxPersistantManifoldPoolSize);
300 parms.shouldDisableContactPoolDynamicAllocation = ParamBoolean(pConfig, "ShouldDisableContactPoolDynamicAllocation", parms.shouldDisableContactPoolDynamicAllocation);
301 parms.shouldForceUpdateAllAabbs = ParamBoolean(pConfig, "ShouldForceUpdateAllAabbs", parms.shouldForceUpdateAllAabbs);
302 parms.shouldRandomizeSolverOrder = ParamBoolean(pConfig, "ShouldRandomizeSolverOrder", parms.shouldRandomizeSolverOrder);
303 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
304 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
305 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
306 } 278 }
307 } 279 }
308 m_params[0] = parms;
309 } 280 }
310 281
311 // A helper function that handles a true/false parameter and returns the proper float number encoding 282 // A helper function that handles a true/false parameter and returns the proper float number encoding
@@ -323,12 +294,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
323 return ret; 294 return ret;
324 } 295 }
325 296
326
327 // Called directly from unmanaged code so don't do much 297 // Called directly from unmanaged code so don't do much
328 private void BulletLogger(string msg) 298 private void BulletLogger(string msg)
329 { 299 {
330 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 300 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
331 } 301 }
302
303 // Called directly from unmanaged code so don't do much
304 private void BulletLoggerPhysLog(string msg)
305 {
306 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
307 }
332 308
333 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 309 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
334 { 310 {
@@ -339,6 +315,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
339 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) 315 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
340 { 316 {
341 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); 317 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
318
319 if (!m_initialized) return null;
320
342 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 321 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
343 lock (m_avatars) m_avatars.Add(localID, actor); 322 lock (m_avatars) m_avatars.Add(localID, actor);
344 return actor; 323 return actor;
@@ -347,34 +326,47 @@ public class BSScene : PhysicsScene, IPhysicsParameters
347 public override void RemoveAvatar(PhysicsActor actor) 326 public override void RemoveAvatar(PhysicsActor actor)
348 { 327 {
349 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); 328 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
350 if (actor is BSCharacter) 329
351 { 330 if (!m_initialized) return;
352 ((BSCharacter)actor).Destroy(); 331
353 } 332 BSCharacter bsactor = actor as BSCharacter;
354 try 333 if (bsactor != null)
355 {
356 lock (m_avatars) m_avatars.Remove(actor.LocalID);
357 }
358 catch (Exception e)
359 { 334 {
360 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); 335 try
336 {
337 lock (m_avatars) m_avatars.Remove(actor.LocalID);
338 }
339 catch (Exception e)
340 {
341 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
342 }
343 bsactor.Destroy();
344 // bsactor.dispose();
361 } 345 }
362 } 346 }
363 347
364 public override void RemovePrim(PhysicsActor prim) 348 public override void RemovePrim(PhysicsActor prim)
365 { 349 {
366 // m_log.DebugFormat("{0}: RemovePrim", LogHeader); 350 if (!m_initialized) return;
367 if (prim is BSPrim) 351
368 { 352 BSPrim bsprim = prim as BSPrim;
369 ((BSPrim)prim).Destroy(); 353 if (bsprim != null)
370 }
371 try
372 { 354 {
373 lock (m_prims) m_prims.Remove(prim.LocalID); 355 m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
356 try
357 {
358 lock (m_prims) m_prims.Remove(bsprim.LocalID);
359 }
360 catch (Exception e)
361 {
362 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
363 }
364 bsprim.Destroy();
365 // bsprim.dispose();
374 } 366 }
375 catch (Exception e) 367 else
376 { 368 {
377 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); 369 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
378 } 370 }
379 } 371 }
380 372
@@ -382,6 +374,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
382 Vector3 size, Quaternion rotation, bool isPhysical, uint localID) 374 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
383 { 375 {
384 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); 376 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
377
378 if (!m_initialized) return null;
379
385 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 380 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
386 lock (m_prims) m_prims.Add(localID, prim); 381 lock (m_prims) m_prims.Add(localID, prim);
387 return prim; 382 return prim;
@@ -400,6 +395,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 int collidersCount; 395 int collidersCount;
401 IntPtr collidersPtr; 396 IntPtr collidersPtr;
402 397
398 LastSimulatedTimestep = timeStep;
399
403 // prevent simulation until we've been initialized 400 // prevent simulation until we've been initialized
404 if (!m_initialized) return 10.0f; 401 if (!m_initialized) return 10.0f;
405 402
@@ -459,7 +456,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
459 for (int ii = 0; ii < updatedEntityCount; ii++) 456 for (int ii = 0; ii < updatedEntityCount; ii++)
460 { 457 {
461 EntityProperties entprop = m_updateArray[ii]; 458 EntityProperties entprop = m_updateArray[ii];
462 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
463 BSPrim prim; 459 BSPrim prim;
464 if (m_prims.TryGetValue(entprop.ID, out prim)) 460 if (m_prims.TryGetValue(entprop.ID, out prim))
465 { 461 {
@@ -532,8 +528,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
532 }); 528 });
533 } 529 }
534 530
531 // Someday we will have complex terrain with caves and tunnels
532 // For the moment, it's flat and convex
533 public float GetTerrainHeightAtXYZ(Vector3 loc)
534 {
535 return GetTerrainHeightAtXY(loc.X, loc.Y);
536 }
537
535 public float GetTerrainHeightAtXY(float tX, float tY) 538 public float GetTerrainHeightAtXY(float tX, float tY)
536 { 539 {
540 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
541 return 30;
537 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; 542 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
538 } 543 }
539 544
@@ -555,6 +560,33 @@ public class BSScene : PhysicsScene, IPhysicsParameters
555 public override void Dispose() 560 public override void Dispose()
556 { 561 {
557 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 562 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
563
564 // make sure no stepping happens while we're deleting stuff
565 m_initialized = false;
566
567 if (m_constraintCollection != null)
568 {
569 m_constraintCollection.Dispose();
570 m_constraintCollection = null;
571 }
572
573 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
574 {
575 kvp.Value.Destroy();
576 }
577 m_avatars.Clear();
578
579 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
580 {
581 kvp.Value.Destroy();
582 }
583 m_prims.Clear();
584
585 // Anything left in the unmanaged code should be cleaned out
586 BulletSimAPI.Shutdown(WorldID);
587
588 // Not logging any more
589 PhysicsLogging.Close();
558 } 590 }
559 591
560 public override Dictionary<uint, float> GetTopColliders() 592 public override Dictionary<uint, float> GetTopColliders()
@@ -680,10 +712,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
680 } 712 }
681 713
682 // The calls to the PhysicsActors can't directly call into the physics engine 714 // The calls to the PhysicsActors can't directly call into the physics engine
683 // because it might be busy. We we delay changes to a known time. 715 // because it might be busy. We delay changes to a known time.
684 // We rely on C#'s closure to save and restore the context for the delegate. 716 // We rely on C#'s closure to save and restore the context for the delegate.
685 public void TaintedObject(TaintCallback callback) 717 public void TaintedObject(TaintCallback callback)
686 { 718 {
719 if (!m_initialized) return;
720
687 lock (_taintLock) 721 lock (_taintLock)
688 _taintedObjects.Add(callback); 722 _taintedObjects.Add(callback);
689 return; 723 return;
@@ -757,61 +791,392 @@ public class BSScene : PhysicsScene, IPhysicsParameters
757 } 791 }
758 #endregion Vehicles 792 #endregion Vehicles
759 793
760 #region Runtime settable parameters 794 #region Parameters
761 public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] 795
762 { 796 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
763 new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"), 797 delegate float ParamGet(BSScene scene);
764 new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), 798 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
765 new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), 799
766 new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), 800 private struct ParameterDefn
767 new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), 801 {
768 new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"), 802 public string name;
769 803 public string desc;
770 new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"), 804 public float defaultValue;
771 new PhysParameterEntry("DefaultDensity", "Density for new objects" ), 805 public ParamUser userParam;
772 new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ), 806 public ParamGet getter;
773 // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ), 807 public ParamSet setter;
774 new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ), 808 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
775 809 {
776 new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ), 810 name = n;
777 new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ), 811 desc = d;
778 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), 812 defaultValue = v;
779 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), 813 userParam = u;
780 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), 814 getter = g;
781 new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ), 815 setter = s;
782 new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ), 816 }
783 new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ), 817 }
784 // Can only change the following at initialization time. Change the INI file and reboot. 818
785 new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"), 819 // List of all of the externally visible parameters.
786 new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"), 820 // For each parameter, this table maps a text name to getter and setters.
787 new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"), 821 // To add a new externally referencable/settable parameter, add the paramter storage
788 new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"), 822 // location somewhere in the program and make an entry in this table with the
789 new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"), 823 // getters and setters.
790 new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"), 824 // To add a new variable, it is easiest to find an existing definition and copy it.
791 new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"), 825 // Parameter values are floats. Booleans are converted to a floating value.
792 826 //
793 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 827 // A ParameterDefn() takes the following parameters:
794 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 828 // -- the text name of the parameter. This is used for console input and ini file.
795 829 // -- a short text description of the parameter. This shows up in the console listing.
796 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 830 // -- a delegate for fetching the parameter from the ini file.
797 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 831 // Should handle fetching the right type from the ini file and converting it.
798 832 // -- a delegate for getting the value as a float
799 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), 833 // -- a delegate for setting the value from a float
800 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), 834 //
801 new PhysParameterEntry("TerrainRestitution", "Bouncyness" ), 835 // The single letter parameters for the delegates are:
802 new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ), 836 // s = BSScene
803 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), 837 // p = string parameter name
804 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), 838 // l = localID of referenced object
805 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), 839 // v = float value
806 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ), 840 // cf = parameter configuration class (for fetching values from ini file)
807 new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions") 841 private ParameterDefn[] ParameterDefinitions =
842 {
843 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
844 ConfigurationParameters.numericTrue,
845 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
846 (s) => { return s.NumericBool(s._meshSculptedPrim); },
847 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ),
848 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
849 ConfigurationParameters.numericFalse,
850 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
851 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); },
852 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ),
853
854 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
855 8f,
856 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
857 (s) => { return (float)s.m_meshLOD; },
858 (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
859 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
860 32,
861 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
862 (s) => { return (float)s.m_sculptLOD; },
863 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
864
865 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
866 10f,
867 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
868 (s) => { return (float)s.m_maxSubSteps; },
869 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
870 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
871 1f / 60f,
872 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
873 (s) => { return (float)s.m_fixedTimeStep; },
874 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
875 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
876 2048f,
877 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
878 (s) => { return (float)s.m_maxCollisionsPerFrame; },
879 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
880 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
881 8000f,
882 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
883 (s) => { return (float)s.m_maxUpdatesPerFrame; },
884 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
885 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
886 10000.01f,
887 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
888 (s) => { return (float)s.m_maximumObjectMass; },
889 (s,p,l,v) => { s.m_maximumObjectMass = v; } ),
890
891 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
892 2200f,
893 (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
894 (s) => { return (float)s.PID_D; },
895 (s,p,l,v) => { s.PID_D = v; } ),
896 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
897 900f,
898 (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
899 (s) => { return (float)s.PID_P; },
900 (s,p,l,v) => { s.PID_P = v; } ),
901
902 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
903 0.5f,
904 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
905 (s) => { return s.m_params[0].defaultFriction; },
906 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
907 new ParameterDefn("DefaultDensity", "Density for new objects" ,
908 10.000006836f, // Aluminum g/cm3
909 (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
910 (s) => { return s.m_params[0].defaultDensity; },
911 (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
912 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
913 0f,
914 (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
915 (s) => { return s.m_params[0].defaultRestitution; },
916 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
917 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
918 0f,
919 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
920 (s) => { return s.m_params[0].collisionMargin; },
921 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
922 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
923 -9.80665f,
924 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
925 (s) => { return s.m_params[0].gravity; },
926 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
927
928
929 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
930 0f,
931 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
932 (s) => { return s.m_params[0].linearDamping; },
933 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
934 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
935 0f,
936 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
937 (s) => { return s.m_params[0].angularDamping; },
938 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
939 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
940 0.2f,
941 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
942 (s) => { return s.m_params[0].deactivationTime; },
943 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
944 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
945 0.8f,
946 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
947 (s) => { return s.m_params[0].linearSleepingThreshold; },
948 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
949 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
950 1.0f,
951 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
952 (s) => { return s.m_params[0].angularSleepingThreshold; },
953 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
954 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
955 0f, // set to zero to disable
956 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
957 (s) => { return s.m_params[0].ccdMotionThreshold; },
958 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
959 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
960 0f,
961 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
962 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
963 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
964 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
965 0.1f,
966 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
967 (s) => { return s.m_params[0].contactProcessingThreshold; },
968 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
969
970 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
971 0.5f,
972 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
973 (s) => { return s.m_params[0].terrainFriction; },
974 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
975 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
976 0.8f,
977 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].terrainHitFraction; },
979 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
980 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
981 0f,
982 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].terrainRestitution; },
984 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
985 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
986 0.5f,
987 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].avatarFriction; },
989 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
990 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
991 60f,
992 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].avatarDensity; },
994 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
995 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
996 0f,
997 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].avatarRestitution; },
999 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1000 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1001 0.37f,
1002 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1004 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
1005 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1006 1.5f,
1007 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1009 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1010 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1011 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1015
1016
1017 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)",
1018 0f, // zero to disable
1019 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1020 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1021 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1022 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
1023 ConfigurationParameters.numericTrue,
1024 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1025 (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
1026 (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
1027 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
1028 ConfigurationParameters.numericFalse,
1029 (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1030 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1031 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1032 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1033 ConfigurationParameters.numericFalse,
1034 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1035 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1036 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1037 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1038 ConfigurationParameters.numericFalse,
1039 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1040 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1041 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
1042 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
1043 ConfigurationParameters.numericFalse,
1044 (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1045 (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
1046 (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
1047 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
1048 0f, // zero says use Bullet default
1049 (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
1050 (s) => { return s.m_params[0].numberOfSolverIterations; },
1051 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1052
1053 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1054 ConfigurationParameters.numericFalse,
1055 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1056 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1057 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
1058 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
1059 ConfigurationParameters.numericTrue,
1060 (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1061 (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
1062 (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
1063 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
1064 5.0f,
1065 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
1067 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
1068 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
1069 0.1f,
1070 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1072 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1073 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0",
1074 0.0f,
1075 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1076 (s) => { return s.m_params[0].linkConstraintCFM; },
1077 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1078 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1079 0.2f,
1080 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1081 (s) => { return s.m_params[0].linkConstraintERP; },
1082 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1083
1084 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1085 0f,
1086 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1087 (s) => { return (float)s.m_detailedStatsStep; },
1088 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
1089 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1090 ConfigurationParameters.numericFalse,
1091 (s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1092 (s) => { return s.NumericBool(s.shouldDebugLog); },
1093 (s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ),
808 1094
809 }; 1095 };
810 1096
1097 // Convert a boolean to our numeric true and false values
1098 public float NumericBool(bool b)
1099 {
1100 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
1101 }
1102
1103 // Convert numeric true and false values to a boolean
1104 public bool BoolNumeric(float b)
1105 {
1106 return (b == ConfigurationParameters.numericTrue ? true : false);
1107 }
1108
1109 // Search through the parameter definitions and return the matching
1110 // ParameterDefn structure.
1111 // Case does not matter as names are compared after converting to lower case.
1112 // Returns 'false' if the parameter is not found.
1113 private bool TryGetParameter(string paramName, out ParameterDefn defn)
1114 {
1115 bool ret = false;
1116 ParameterDefn foundDefn = new ParameterDefn();
1117 string pName = paramName.ToLower();
1118
1119 foreach (ParameterDefn parm in ParameterDefinitions)
1120 {
1121 if (pName == parm.name.ToLower())
1122 {
1123 foundDefn = parm;
1124 ret = true;
1125 break;
1126 }
1127 }
1128 defn = foundDefn;
1129 return ret;
1130 }
1131
1132 // Pass through the settable parameters and set the default values
1133 private void SetParameterDefaultValues()
1134 {
1135 foreach (ParameterDefn parm in ParameterDefinitions)
1136 {
1137 parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
1138 }
1139 }
1140
1141 // Get user set values out of the ini file.
1142 private void SetParameterConfigurationValues(IConfig cfg)
1143 {
1144 foreach (ParameterDefn parm in ParameterDefinitions)
1145 {
1146 parm.userParam(this, cfg, parm.name, parm.defaultValue);
1147 }
1148 }
1149
1150 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1151
1152 private void BuildParameterTable()
1153 {
1154 if (SettableParameters.Length < ParameterDefinitions.Length)
1155 {
1156
1157 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1158 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1159 {
1160 ParameterDefn pd = ParameterDefinitions[ii];
1161 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
1162 }
1163
1164 // make the list in alphabetical order for estetic reasons
1165 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
1166 {
1167 return ppe1.name.CompareTo(ppe2.name);
1168 });
1169
1170 SettableParameters = entries.ToArray();
1171 }
1172 }
1173
1174
811 #region IPhysicsParameters 1175 #region IPhysicsParameters
812 // Get the list of parameters this physics engine supports 1176 // Get the list of parameters this physics engine supports
813 public PhysParameterEntry[] GetParameterList() 1177 public PhysParameterEntry[] GetParameterList()
814 { 1178 {
1179 BuildParameterTable();
815 return SettableParameters; 1180 return SettableParameters;
816 } 1181 }
817 1182
@@ -823,63 +1188,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
823 // value activated ('terrainFriction' for instance). 1188 // value activated ('terrainFriction' for instance).
824 public bool SetPhysicsParameter(string parm, float val, uint localID) 1189 public bool SetPhysicsParameter(string parm, float val, uint localID)
825 { 1190 {
826 bool ret = true; 1191 bool ret = false;
827 string lparm = parm.ToLower(); 1192 ParameterDefn theParam;
828 switch (lparm) 1193 if (TryGetParameter(parm, out theParam))
829 { 1194 {
830 case "detailedstats": m_detailedStatsStep = (int)val; break; 1195 theParam.setter(this, parm, localID, val);
831 1196 ret = true;
832 case "meshlod": m_meshLOD = (int)val; break;
833 case "sculptlod": m_sculptLOD = (int)val; break;
834 case "maxsubstep": m_maxSubSteps = (int)val; break;
835 case "fixedtimestep": m_fixedTimeStep = val; break;
836 case "maxobjectmass": m_maximumObjectMass = val; break;
837
838 case "defaultfriction": m_params[0].defaultFriction = val; break;
839 case "defaultdensity": m_params[0].defaultDensity = val; break;
840 case "defaultrestitution": m_params[0].defaultRestitution = val; break;
841 case "collisionmargin": m_params[0].collisionMargin = val; break;
842 case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, localID, val); break;
843
844 case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
845 case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
846 case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break;
847 case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break;
848 case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
849 case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
850 case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
851 case "contactprocessingthreshold": UpdateParameterPrims(ref m_params[0].contactProcessingThreshold, lparm, localID, val); break;
852 // the following are used only at initialization time so setting them makes no sense
853 // case "maxPersistantmanifoldpoolSize": m_params[0].maxPersistantManifoldPoolSize = val; break;
854 // case "shoulddisablecontactpooldynamicallocation": m_params[0].shouldDisableContactPoolDynamicAllocation = val; break;
855 // case "shouldforceupdateallaabbs": m_params[0].shouldForceUpdateAllAabbs = val; break;
856 // case "shouldrandomizesolverorder": m_params[0].shouldRandomizeSolverOrder = val; break;
857 // case "shouldsplitsimulationislands": m_params[0].shouldSplitSimulationIslands = val; break;
858 // case "shouldenablefrictioncaching": m_params[0].shouldEnableFrictionCaching = val; break;
859 // case "numberofsolveriterations": m_params[0].numberOfSolverIterations = val; break;
860
861 case "friction": TaintedUpdateParameter(lparm, localID, val); break;
862 case "restitution": TaintedUpdateParameter(lparm, localID, val); break;
863
864 // set a terrain physical feature and cause terrain to be recalculated
865 case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
866 case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break;
867 case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break;
868 // set an avatar physical feature and cause avatar(s) to be recalculated
869 case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break;
870 case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break;
871 case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
872 case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
873 case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
874 case "avatarcontactprocessingthreshold": UpdateParameterAvatars(ref m_params[0].avatarContactProcessingThreshold, "avatar", localID, val); break;
875
876 default: ret = false; break;
877 } 1197 }
878 return ret; 1198 return ret;
879 } 1199 }
880 1200
881 // check to see if we are updating a parameter for a particular or all of the prims 1201 // check to see if we are updating a parameter for a particular or all of the prims
882 private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) 1202 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
883 { 1203 {
884 List<uint> operateOn; 1204 List<uint> operateOn;
885 lock (m_prims) operateOn = new List<uint>(m_prims.Keys); 1205 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
@@ -887,7 +1207,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
887 } 1207 }
888 1208
889 // check to see if we are updating a parameter for a particular or all of the avatars 1209 // check to see if we are updating a parameter for a particular or all of the avatars
890 private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val) 1210 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
891 { 1211 {
892 List<uint> operateOn; 1212 List<uint> operateOn;
893 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1213 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
@@ -898,7 +1218,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
898 // If the local ID is APPLY_TO_NONE, just change the default value 1218 // If the local ID is APPLY_TO_NONE, just change the default value
899 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1219 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
900 // If the localID is a specific object, apply the parameter change to only that object 1220 // If the localID is a specific object, apply the parameter change to only that object
901 private void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) 1221 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
902 { 1222 {
903 switch (localID) 1223 switch (localID)
904 { 1224 {
@@ -925,7 +1245,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
925 } 1245 }
926 1246
927 // schedule the actual updating of the paramter to when the phys engine is not busy 1247 // schedule the actual updating of the paramter to when the phys engine is not busy
928 private void TaintedUpdateParameter(string parm, uint localID, float val) 1248 protected void TaintedUpdateParameter(string parm, uint localID, float val)
929 { 1249 {
930 uint xlocalID = localID; 1250 uint xlocalID = localID;
931 string xparm = parm.ToLower(); 1251 string xparm = parm.ToLower();
@@ -940,50 +1260,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
940 public bool GetPhysicsParameter(string parm, out float value) 1260 public bool GetPhysicsParameter(string parm, out float value)
941 { 1261 {
942 float val = 0f; 1262 float val = 0f;
943 bool ret = true; 1263 bool ret = false;
944 switch (parm.ToLower()) 1264 ParameterDefn theParam;
945 { 1265 if (TryGetParameter(parm, out theParam))
946 case "detailedstats": val = (int)m_detailedStatsStep; break; 1266 {
947 case "meshlod": val = (float)m_meshLOD; break; 1267 val = theParam.getter(this);
948 case "sculptlod": val = (float)m_sculptLOD; break; 1268 ret = true;
949 case "maxsubstep": val = (float)m_maxSubSteps; break;
950 case "fixedtimestep": val = m_fixedTimeStep; break;
951 case "maxobjectmass": val = m_maximumObjectMass; break;
952
953 case "defaultfriction": val = m_params[0].defaultFriction; break;
954 case "defaultdensity": val = m_params[0].defaultDensity; break;
955 case "defaultrestitution": val = m_params[0].defaultRestitution; break;
956 case "collisionmargin": val = m_params[0].collisionMargin; break;
957 case "gravity": val = m_params[0].gravity; break;
958
959 case "lineardamping": val = m_params[0].linearDamping; break;
960 case "angulardamping": val = m_params[0].angularDamping; break;
961 case "deactivationtime": val = m_params[0].deactivationTime; break;
962 case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break;
963 case "angularsleepingthreshold": val = m_params[0].angularDamping; break;
964 case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
965 case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
966 case "contactprocessingthreshold": val = m_params[0].contactProcessingThreshold; break;
967 case "maxPersistantmanifoldpoolSize": val = m_params[0].maxPersistantManifoldPoolSize; break;
968 case "shoulddisablecontactpooldynamicallocation": val = m_params[0].shouldDisableContactPoolDynamicAllocation; break;
969 case "shouldforceupdateallaabbs": val = m_params[0].shouldForceUpdateAllAabbs; break;
970 case "shouldrandomizesolverorder": val = m_params[0].shouldRandomizeSolverOrder; break;
971 case "shouldsplitsimulationislands": val = m_params[0].shouldSplitSimulationIslands; break;
972 case "shouldenablefrictioncaching": val = m_params[0].shouldEnableFrictionCaching; break;
973 case "numberofsolveriterations": val = m_params[0].numberOfSolverIterations; break;
974
975 case "terrainfriction": val = m_params[0].terrainFriction; break;
976 case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
977 case "terrainrestitution": val = m_params[0].terrainRestitution; break;
978
979 case "avatarfriction": val = m_params[0].avatarFriction; break;
980 case "avatardensity": val = m_params[0].avatarDensity; break;
981 case "avatarrestitution": val = m_params[0].avatarRestitution; break;
982 case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
983 case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
984 case "avatarcontactprocessingthreshold": val = m_params[0].avatarContactProcessingThreshold; break;
985 default: ret = false; break;
986
987 } 1269 }
988 value = val; 1270 value = val;
989 return ret; 1271 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 086f0dc..0ffbc94 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -32,6 +32,28 @@ using OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin { 33namespace OpenSim.Region.Physics.BulletSPlugin {
34 34
35// Classes to allow some type checking for the API
36public struct BulletSim
37{
38 public BulletSim(uint id, IntPtr xx) { ID = id; Ptr = xx; }
39 public IntPtr Ptr;
40 public uint ID;
41}
42
43public struct BulletBody
44{
45 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
46 public IntPtr Ptr;
47 public uint ID;
48}
49
50public struct BulletConstraint
51{
52 public BulletConstraint(IntPtr xx) { Ptr = xx; }
53 public IntPtr Ptr;
54}
55
56// ===============================================================================
35[StructLayout(LayoutKind.Sequential)] 57[StructLayout(LayoutKind.Sequential)]
36public struct ConvexHull 58public struct ConvexHull
37{ 59{
@@ -44,13 +66,14 @@ public struct ShapeData
44{ 66{
45 public enum PhysicsShapeType 67 public enum PhysicsShapeType
46 { 68 {
47 SHAPE_AVATAR = 0, 69 SHAPE_UNKNOWN = 0,
48 SHAPE_BOX = 1, 70 SHAPE_AVATAR = 1,
49 SHAPE_CONE = 2, 71 SHAPE_BOX = 2,
50 SHAPE_CYLINDER = 3, 72 SHAPE_CONE = 3,
51 SHAPE_SPHERE = 4, 73 SHAPE_CYLINDER = 4,
52 SHAPE_MESH = 5, 74 SHAPE_SPHERE = 5,
53 SHAPE_HULL = 6 75 SHAPE_MESH = 6,
76 SHAPE_HULL = 7
54 }; 77 };
55 public uint ID; 78 public uint ID;
56 public PhysicsShapeType Type; 79 public PhysicsShapeType Type;
@@ -64,12 +87,12 @@ public struct ShapeData
64 public System.UInt64 MeshKey; 87 public System.UInt64 MeshKey;
65 public float Friction; 88 public float Friction;
66 public float Restitution; 89 public float Restitution;
67 public int Collidable; 90 public float Collidable; // true of things bump into this
68 public int Static; // true if a static object. Otherwise gravity, etc. 91 public float Static; // true if a static object. Otherwise gravity, etc.
69 92
70 // note that bools are passed as ints since bool size changes by language and architecture 93 // note that bools are passed as floats since bool size changes by language and architecture
71 public const int numericTrue = 1; 94 public const float numericTrue = 1f;
72 public const int numericFalse = 0; 95 public const float numericFalse = 0f;
73} 96}
74[StructLayout(LayoutKind.Sequential)] 97[StructLayout(LayoutKind.Sequential)]
75public struct SweepHit 98public struct SweepHit
@@ -142,10 +165,56 @@ public struct ConfigurationParameters
142 public float shouldEnableFrictionCaching; 165 public float shouldEnableFrictionCaching;
143 public float numberOfSolverIterations; 166 public float numberOfSolverIterations;
144 167
168 public float linkConstraintUseFrameOffset;
169 public float linkConstraintEnableTransMotor;
170 public float linkConstraintTransMotorMaxVel;
171 public float linkConstraintTransMotorMaxForce;
172 public float linkConstraintERP;
173 public float linkConstraintCFM;
174
145 public const float numericTrue = 1f; 175 public const float numericTrue = 1f;
146 public const float numericFalse = 0f; 176 public const float numericFalse = 0f;
147} 177}
148 178
179// Values used by Bullet and BulletSim to control collisions
180public enum CollisionFlags : uint
181{
182 STATIC_OBJECT = 1 << 0,
183 KINEMATIC_OBJECT = 1 << 1,
184 NO_CONTACT_RESPONSE = 1 << 2,
185 CUSTOM_MATERIAL_CALLBACK = 1 << 3,
186 CHARACTER_OBJECT = 1 << 4,
187 DISABLE_VISUALIZE_OBJECT = 1 << 5,
188 DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
189 // Following used by BulletSim to control collisions
190 VOLUME_DETECT_OBJECT = 1 << 10,
191 PHANTOM_OBJECT = 1 << 11,
192 PHYSICAL_OBJECT = 1 << 12,
193};
194
195// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
196// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
197public enum ConstraintParams : int
198{
199 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
200 BT_CONSTRAINT_STOP_ERP,
201 BT_CONSTRAINT_CFM,
202 BT_CONSTRAINT_STOP_CFM,
203};
204public enum ConstraintParamAxis : int
205{
206 AXIS_LINEAR_X = 0,
207 AXIS_LINEAR_Y,
208 AXIS_LINEAR_Z,
209 AXIS_ANGULAR_X,
210 AXIS_ANGULAR_Y,
211 AXIS_ANGULAR_Z,
212 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
213 AXIS_ANGULAR_ALL,
214 AXIS_ALL
215};
216
217// ===============================================================================
149static class BulletSimAPI { 218static class BulletSimAPI {
150 219
151[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 220[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -195,6 +264,7 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
195[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 264[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
196public static extern bool CreateObject(uint worldID, ShapeData shapeData); 265public static extern bool CreateObject(uint worldID, ShapeData shapeData);
197 266
267/* Remove old functionality
198[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 268[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
199public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); 269public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
200 270
@@ -209,11 +279,15 @@ public static extern bool RemoveConstraintByID(uint worldID, uint id1);
209 279
210[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 280[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
211public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); 281public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
282 */
212 283
213[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 284[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
214public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 285public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
215 286
216[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 287[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
288public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
289
290[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
217public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); 291public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
218 292
219[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 293[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -268,5 +342,179 @@ public static extern void DumpBulletStatistics();
268public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 342public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
269[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 343[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
270public static extern void SetDebugLogCallback(DebugLogCallback callback); 344public static extern void SetDebugLogCallback(DebugLogCallback callback);
345
346// ===============================================================================
347// ===============================================================================
348// ===============================================================================
349// A new version of the API that enables moving all the logic out of the C++ code and into
350// the C# code. This will make modifications easier for the next person.
351// This interface passes the actual pointers to the objects in the unmanaged
352// address space. All the management (calls for creation/destruction/lookup)
353// is done in the C# code.
354// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
355// and the old code is removed.
356
357[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
358public static extern IntPtr GetSimHandle2(uint worldID);
359
360[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
361public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
362
363[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
364public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id);
365
366// ===============================================================================
367[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
368public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
369 int maxCollisions, IntPtr collisionArray,
370 int maxUpdates, IntPtr updateArray);
371
372[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
373public static extern bool UpdateParameter2(IntPtr sim, uint localID, String parm, float value);
374
375[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
376public static extern void SetHeightmap2(IntPtr sim, float[] heightmap);
377
378[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
379public static extern void Shutdown2(IntPtr sim);
380
381[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
382public static extern int PhysicsStep2(IntPtr sim, float timeStep, int maxSubSteps, float fixedTimeStep,
383 out int updatedEntityCount,
384 out IntPtr updatedEntitiesPtr,
385 out int collidersCount,
386 out IntPtr collidersPtr);
387
388/*
389[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
390public static extern IntPtr CreateMesh2(IntPtr sim, int indicesCount, int* indices, int verticesCount, float* vertices );
391
392[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
393public static extern bool BuildHull2(IntPtr sim, IntPtr mesh);
394
395[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
396public static extern bool ReleaseHull2(IntPtr sim, IntPtr mesh);
397
398[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
399public static extern bool DestroyMesh2(IntPtr sim, IntPtr mesh);
400
401[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
402public static extern IntPtr CreateObject2(IntPtr sim, ShapeData shapeData);
403*/
404
405[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
406public static extern IntPtr CreateConstraint2(IntPtr sim, IntPtr obj1, IntPtr obj2,
407 Vector3 frame1loc, Quaternion frame1rot,
408 Vector3 frame2loc, Quaternion frame2rot,
409 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
410
411[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
412public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
413
414[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
415public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
416
417[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
418public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
419
420[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
421public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
422
423[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
424public static extern bool CalculateTransforms2(IntPtr constrain);
425
426[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
427public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
428
429[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
430public static extern bool DestroyConstraint2(IntPtr sim, IntPtr constrain);
431
432[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
433public static extern Vector3 GetPosition2(IntPtr obj);
434
435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
436public static extern Quaternion GetOrientation2(IntPtr obj);
437
438[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
439public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
440
441[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
442public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity);
443
444[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
445public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
446
447[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
448public static extern bool SetObjectForce2(IntPtr obj, Vector3 force);
449
450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
451public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val);
452
453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
454public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val);
455
456[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
457public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
458
459[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
460public static extern bool SetDeactivationTime2(IntPtr obj, float val);
461
462[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
463public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
464
465[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
466public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
467
468[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
469public static extern bool SetFriction2(IntPtr obj, float val);
470
471[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
472public static extern bool SetRestitution2(IntPtr obj, float val);
473
474[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
475public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val);
476
477[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
478public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang);
479
480[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
481public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags);
482
483[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
484public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags);
485
486[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
487public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags);
488
489[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
490public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
491
492[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
493public static extern bool UpdateInertiaTensor2(IntPtr obj);
494
495[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
496public static extern bool SetGravity2(IntPtr obj, Vector3 val);
497
498[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
499public static extern IntPtr ClearForces2(IntPtr obj);
500
501[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
502public static extern bool SetMargin2(IntPtr obj, float val);
503
504[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
505public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
506
507[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
508public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
509
510[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
511public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
512
513[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
514public static extern bool DestroyObject2(IntPtr world, uint id);
515
516[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
517public static extern void DumpPhysicsStatistics2(IntPtr sim);
518
271} 519}
272} 520}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index cfede55..5274f3b 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -71,6 +71,9 @@ namespace OpenSim.Region.Physics.Manager
71 All = 0x3f 71 All = 0x3f
72 } 72 }
73 73
74 public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
75 public delegate void AssetReceivedDelegate(AssetBase asset);
76
74 /// <summary> 77 /// <summary>
75 /// Contact result from a raycast. 78 /// Contact result from a raycast.
76 /// </summary> 79 /// </summary>
@@ -103,6 +106,8 @@ namespace OpenSim.Region.Physics.Manager
103 get { return new NullPhysicsScene(); } 106 get { return new NullPhysicsScene(); }
104 } 107 }
105 108
109 public RequestAssetDelegate RequestAssetMethod { private get; set; }
110
106 public virtual void TriggerPhysicsBasedRestart() 111 public virtual void TriggerPhysicsBasedRestart()
107 { 112 {
108 physicsCrash handler = OnPhysicsCrash; 113 physicsCrash handler = OnPhysicsCrash;
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 32e81e2..929b019 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -290,7 +290,6 @@ namespace OpenSim.Region.Physics.OdePlugin
290 290
291 private readonly IntPtr contactgroup; 291 private readonly IntPtr contactgroup;
292 292
293 internal IntPtr LandGeom;
294 internal IntPtr WaterGeom; 293 internal IntPtr WaterGeom;
295 294
296 private float nmTerrainContactFriction = 255.0f; 295 private float nmTerrainContactFriction = 255.0f;
@@ -489,6 +488,8 @@ namespace OpenSim.Region.Physics.OdePlugin
489 /// </summary> 488 /// </summary>
490 internal Object OdeLock = new Object(); 489 internal Object OdeLock = new Object();
491 490
491 private bool _worldInitialized = false;
492
492 public IMesher mesher; 493 public IMesher mesher;
493 494
494 private IConfigSource m_config; 495 private IConfigSource m_config;
@@ -875,6 +876,8 @@ namespace OpenSim.Region.Physics.OdePlugin
875 staticPrimspace[i, j] = IntPtr.Zero; 876 staticPrimspace[i, j] = IntPtr.Zero;
876 } 877 }
877 } 878 }
879
880 _worldInitialized = true;
878 } 881 }
879 882
880// internal void waitForSpaceUnlock(IntPtr space) 883// internal void waitForSpaceUnlock(IntPtr space)
@@ -1508,8 +1511,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1508 { 1511 {
1509 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) 1512 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
1510 && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) 1513 && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
1511 && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) 1514 && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1512 && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1513 { 1515 {
1514 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) 1516 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1515 { 1517 {
@@ -1538,7 +1540,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1538 //d.GeomGetAABB(contactGeom.g2, out aabb2); 1540 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1539 //d.GeomGetAABB(contactGeom.g1, out aabb1); 1541 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1540 //aabb1. 1542 //aabb1.
1541 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) 1543 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1542 { 1544 {
1543 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) 1545 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1544 { 1546 {
@@ -2896,6 +2898,8 @@ namespace OpenSim.Region.Physics.OdePlugin
2896 /// <returns>The number of frames simulated over that period.</returns> 2898 /// <returns>The number of frames simulated over that period.</returns>
2897 public override float Simulate(float timeStep) 2899 public override float Simulate(float timeStep)
2898 { 2900 {
2901 if (!_worldInitialized) return 11f;
2902
2899 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; 2903 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
2900 int tempTick = 0, tempTick2 = 0; 2904 int tempTick = 0, tempTick2 = 0;
2901 2905
@@ -4017,6 +4021,8 @@ namespace OpenSim.Region.Physics.OdePlugin
4017 4021
4018 public override void Dispose() 4022 public override void Dispose()
4019 { 4023 {
4024 _worldInitialized = false;
4025
4020 m_rayCastManager.Dispose(); 4026 m_rayCastManager.Dispose();
4021 m_rayCastManager = null; 4027 m_rayCastManager = null;
4022 4028
@@ -4037,6 +4043,7 @@ namespace OpenSim.Region.Physics.OdePlugin
4037 d.WorldDestroy(world); 4043 d.WorldDestroy(world);
4038 //d.CloseODE(); 4044 //d.CloseODE();
4039 } 4045 }
4046
4040 } 4047 }
4041 4048
4042 public override Dictionary<uint, float> GetTopColliders() 4049 public override Dictionary<uint, float> GetTopColliders()