aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs69
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs115
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs178
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs187
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs308
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs588
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs796
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs219
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs15
9 files changed, 1809 insertions, 666 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..fbb9e21
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -0,0 +1,115 @@
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 m_enabled = true;
55 }
56
57 public void Dispose()
58 {
59 if (m_enabled)
60 {
61 // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
62 BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
63 m_enabled = false;
64 }
65 }
66
67 public BulletBody Body1 { get { return m_body1; } }
68 public BulletBody Body2 { get { return m_body2; } }
69
70 public bool SetLinearLimits(Vector3 low, Vector3 high)
71 {
72 bool ret = false;
73 if (m_enabled)
74 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high);
75 return ret;
76 }
77
78 public bool SetAngularLimits(Vector3 low, Vector3 high)
79 {
80 bool ret = false;
81 if (m_enabled)
82 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high);
83 return ret;
84 }
85
86 public bool UseFrameOffset(bool useOffset)
87 {
88 bool ret = false;
89 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
90 if (m_enabled)
91 ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
92 return ret;
93 }
94
95 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
96 {
97 bool ret = false;
98 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
99 if (m_enabled)
100 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
101 return ret;
102 }
103
104 public bool CalculateTransforms()
105 {
106 bool ret = false;
107 if (m_enabled)
108 {
109 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr);
110 ret = true;
111 }
112 return ret;
113 }
114}
115}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
new file mode 100755
index 0000000..a2650fb
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -0,0 +1,178 @@
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 the way we're using them.
87 public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
88 {
89 bool found = false;
90 BSConstraint foundConstraint = null;
91
92 uint lookingID1 = body1.ID;
93 uint lookingID2 = body2.ID;
94 ForEachConstraint(delegate(BSConstraint constrain)
95 {
96 if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
97 || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
98 {
99 foundConstraint = constrain;
100 found = true;
101 }
102 return found;
103 });
104 returnConstraint = foundConstraint;
105 return found;
106 }
107
108 public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
109 {
110 // return BulletSimAPI.RemoveConstraint(m_world.ID, obj1.ID, obj2.ID);
111
112 bool ret = false;
113 BSConstraint constrain;
114
115 if (this.TryGetConstraint(body1, body2, out constrain))
116 {
117 // remove the constraint from our collection
118 m_constraints.Remove(constrain);
119 // tell the engine that all its structures need to be freed
120 constrain.Dispose();
121 // we destroyed something
122 ret = true;
123 }
124
125 return ret;
126 }
127
128 public bool RemoveAndDestroyConstraint(BulletBody body1)
129 {
130 // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
131
132 List<BSConstraint> toRemove = new List<BSConstraint>();
133 uint lookingID = body1.ID;
134 ForEachConstraint(delegate(BSConstraint constrain)
135 {
136 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
137 {
138 toRemove.Add(constrain);
139 }
140 return false;
141 });
142 lock (m_constraints)
143 {
144 foreach (BSConstraint constrain in toRemove)
145 {
146 m_constraints.Remove(constrain);
147 constrain.Dispose();
148 }
149 }
150 return (toRemove.Count > 0);
151 }
152
153 public bool RecalculateAllConstraints()
154 {
155 foreach (BSConstraint constrain in m_constraints)
156 {
157 constrain.CalculateTransforms();
158 }
159 return true;
160 }
161
162 // Lock the constraint list and loop through it.
163 // The constraint action returns 'true' if it wants the loop aborted.
164 private void ForEachConstraint(ConstraintAction action)
165 {
166 lock (m_constraints)
167 {
168 foreach (BSConstraint constrain in m_constraints)
169 {
170 if (action(constrain))
171 break;
172 }
173 }
174 }
175
176
177}
178}
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..3bc2100
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -0,0 +1,308 @@
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 // Undo all the physical linking and rebuild the physical linkset.
121 public bool RefreshLinkset(BSPrim requestor)
122 {
123 return true;
124 }
125
126
127 // Return 'true' if the passed object is the root object of this linkset
128 public bool IsRoot(BSPrim requestor)
129 {
130 return (requestor.LocalID == m_linksetRoot.LocalID);
131 }
132
133 // Return 'true' if this linkset has any children (more than the root member)
134 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
135
136 // Return 'true' if this child is in this linkset
137 public bool HasChild(BSPrim child)
138 {
139 bool ret = false;
140 foreach (BSPrim bp in m_children)
141 {
142 if (child.LocalID == bp.LocalID)
143 {
144 ret = true;
145 break;
146 }
147 }
148 return ret;
149 }
150
151 private float ComputeLinksetMass()
152 {
153 float mass = m_linksetRoot.MassRaw;
154 foreach (BSPrim bp in m_children)
155 {
156 mass += bp.MassRaw;
157 }
158 return mass;
159 }
160
161 private OMV.Vector3 ComputeLinksetCenterOfMass()
162 {
163 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
164 float totalMass = m_linksetRoot.MassRaw;
165
166 foreach (BSPrim bp in m_children)
167 {
168 com += bp.Position * bp.MassRaw;
169 totalMass += bp.MassRaw;
170 }
171 com /= totalMass;
172
173 return com;
174 }
175
176 private OMV.Vector3 ComputeLinksetGeometricCenter()
177 {
178 OMV.Vector3 com = m_linksetRoot.Position;
179
180 foreach (BSPrim bp in m_children)
181 {
182 com += bp.Position * bp.MassRaw;
183 }
184 com /= m_children.Count + 1;
185
186 return com;
187 }
188
189 // I am the root of a linkset and a new child is being added
190 public void AddChildToLinkset(BSPrim pchild)
191 {
192 BSPrim child = pchild;
193 if (!HasChild(child))
194 {
195 m_children.Add(child);
196
197 m_scene.TaintedObject(delegate()
198 {
199 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
200 DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
201 PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child
202 });
203 }
204 return;
205 }
206
207 // I am the root of a linkset and one of my children is being removed.
208 // Safe to call even if the child is not really in my linkset.
209 public void RemoveChildFromLinkset(BSPrim pchild)
210 {
211 BSPrim child = pchild;
212
213 if (m_children.Remove(child))
214 {
215 m_scene.TaintedObject(delegate()
216 {
217 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
218 DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
219
220 if (m_children.Count == 0)
221 {
222 // if the linkset is empty, make sure all linkages have been removed
223 PhysicallyUnlinkAllChildrenFromRoot();
224 }
225 else
226 {
227 PhysicallyUnlinkAChildFromRoot(pchild);
228 }
229 });
230 }
231 else
232 {
233 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
234 // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
235 }
236 return;
237 }
238
239 // Create a constraint between me (root of linkset) and the passed prim (the child).
240 // Called at taint time!
241 private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
242 {
243 // Zero motion for children so they don't interpolate
244 childPrim.ZeroMotion();
245
246 // relative position normalized to the root prim
247 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation);
248 OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation;
249
250 // relative rotation of the child to the parent
251 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
252
253 // create a constraint that allows no freedom of movement between the two objects
254 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
255 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
256 DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
257 BSConstraint constrain = m_scene.Constraints.CreateConstraint(
258 m_scene.World, m_linksetRoot.Body, childPrim.Body,
259 childRelativePosition,
260 childRelativeRotation,
261 OMV.Vector3.Zero,
262 OMV.Quaternion.Identity);
263 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
264 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
265
266 // tweek the constraint to increase stability
267 constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset));
268 constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor),
269 m_scene.Params.linkConstraintTransMotorMaxVel,
270 m_scene.Params.linkConstraintTransMotorMaxForce);
271
272 }
273
274 // Remove linkage between myself and a particular child
275 // Called at taint time!
276 private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim)
277 {
278 DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
279 LogHeader, m_linksetRoot.LocalID, childPrim.LocalID);
280 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
281 // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
282 m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body);
283 }
284
285 // Remove linkage between myself and any possible children I might have
286 // Called at taint time!
287 private void PhysicallyUnlinkAllChildrenFromRoot()
288 {
289 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
290 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID);
291 m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
292 // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
293 }
294
295 // Invoke the detailed logger and output something if it's enabled.
296 private void DebugLog(string msg, params Object[] args)
297 {
298 m_scene.Logger.DebugFormat(msg, args);
299 }
300
301 // Invoke the detailed logger and output something if it's enabled.
302 private void DetailLog(string msg, params Object[] args)
303 {
304 m_scene.PhysicsLogging.Write(msg, args);
305 }
306
307}
308}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 130f1ca..7590d93 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,22 @@ 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 { get { return m_body; } }
107
97 private BSDynamics _vehicle; 108 private BSDynamics _vehicle;
98 109
99 private OMV.Vector3 _PIDTarget; 110 private OMV.Vector3 _PIDTarget;
@@ -127,17 +138,18 @@ public sealed class BSPrim : PhysicsActor
127 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 138 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
128 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 139 _density = _scene.Params.defaultDensity; // TODO: compute based on object material
129 _restitution = _scene.Params.defaultRestitution; 140 _restitution = _scene.Params.defaultRestitution;
130 _parentPrim = null; // not a child or a parent 141 _linkset = new BSLinkset(_scene, this); // a linkset of one
131 _vehicle = new BSDynamics(this); // add vehicleness 142 _vehicle = new BSDynamics(this); // add vehicleness
132 _childrenPrims = new List<BSPrim>(); 143 _mass = CalculateMass();
133 if (_isPhysical)
134 _mass = CalculateMass();
135 else
136 _mass = 0f;
137 // do the actual object creation at taint time 144 // do the actual object creation at taint time
138 _scene.TaintedObject(delegate() 145 _scene.TaintedObject(delegate()
139 { 146 {
140 RecreateGeomAndObject(); 147 RecreateGeomAndObject();
148
149 // Get the pointer to the physical body for this object.
150 // At the moment, we're still letting BulletSim manage the creation and destruction
151 // of the object. Someday we'll move that into the C# code.
152 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
141 }); 153 });
142 } 154 }
143 155
@@ -145,13 +157,19 @@ public sealed class BSPrim : PhysicsActor
145 public void Destroy() 157 public void Destroy()
146 { 158 {
147 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 159 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
160 // DetailLog("{0},Destroy", LocalID);
161
148 // Undo any vehicle properties 162 // Undo any vehicle properties
149 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); 163 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
150 _scene.RemoveVehiclePrim(this); // just to make sure 164 _scene.RemoveVehiclePrim(this); // just to make sure
165
151 _scene.TaintedObject(delegate() 166 _scene.TaintedObject(delegate()
152 { 167 {
168 // Undo any links between me and any other object
169 _linkset = _linkset.RemoveMeFromLinkset(this);
170
153 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 171 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
154 BulletSimAPI.DestroyObject(_scene.WorldID, _localID); 172 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
155 }); 173 });
156 } 174 }
157 175
@@ -164,8 +182,8 @@ public sealed class BSPrim : PhysicsActor
164 _size = value; 182 _size = value;
165 _scene.TaintedObject(delegate() 183 _scene.TaintedObject(delegate()
166 { 184 {
167 if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass 185 _mass = CalculateMass(); // changing size changes the mass
168 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical); 186 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
169 RecreateGeomAndObject(); 187 RecreateGeomAndObject();
170 }); 188 });
171 } 189 }
@@ -175,7 +193,7 @@ public sealed class BSPrim : PhysicsActor
175 _pbs = value; 193 _pbs = value;
176 _scene.TaintedObject(delegate() 194 _scene.TaintedObject(delegate()
177 { 195 {
178 if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass 196 _mass = CalculateMass(); // changing the shape changes the mass
179 RecreateGeomAndObject(); 197 RecreateGeomAndObject();
180 }); 198 });
181 } 199 }
@@ -202,33 +220,10 @@ public sealed class BSPrim : PhysicsActor
202 // link me to the specified parent 220 // link me to the specified parent
203 public override void link(PhysicsActor obj) { 221 public override void link(PhysicsActor obj) {
204 BSPrim parent = obj as BSPrim; 222 BSPrim parent = obj as BSPrim;
205 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); 223 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 224 DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
207 if (_parentPrim == null) 225
208 { 226 _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; 227 return;
233 } 228 }
234 229
@@ -236,101 +231,92 @@ public sealed class BSPrim : PhysicsActor
236 public override void delink() { 231 public override void delink() {
237 // TODO: decide if this parent checking needs to happen at taint time 232 // 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 233 // 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); 234 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
240 if (_parentPrim != null) 235 _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
241 { 236 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 237
290 // return true if we are the root of a linkset (there are children to manage) 238 _linkset.RemoveMeFromLinkset(this);
291 public bool IsRootOfLinkset 239 return;
292 {
293 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
294 } 240 }
295 241
296 // Set motion values to zero. 242 // Set motion values to zero.
297 // Do it to the properties so the values get set in the physics engine. 243 // Do it to the properties so the values get set in the physics engine.
298 // Push the setting of the values to the viewer. 244 // Push the setting of the values to the viewer.
299 private void ZeroMotion() 245 // Called at taint time!
246 public void ZeroMotion()
300 { 247 {
301 Velocity = OMV.Vector3.Zero; 248 _velocity = OMV.Vector3.Zero;
302 _acceleration = OMV.Vector3.Zero; 249 _acceleration = OMV.Vector3.Zero;
303 RotationalVelocity = OMV.Vector3.Zero; 250 _rotationalVelocity = OMV.Vector3.Zero;
304 base.RequestPhysicsterseUpdate(); 251
252 // Zero some other properties directly into the physics engine
253 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero);
254 BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
255 BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
256 BulletSimAPI.ClearForces2(Body.Ptr);
305 } 257 }
306 258
307 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 259 public override void LockAngularMotion(OMV.Vector3 axis)
260 {
261 DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis);
262 return;
263 }
308 264
309 public override OMV.Vector3 Position { 265 public override OMV.Vector3 Position {
310 get { 266 get {
311 // don't do the following GetObjectPosition because this function is called a zillion times 267 if (!_linkset.IsRoot(this))
268 // child prims move around based on their parent. Need to get the latest location
269 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
270
271 // don't do the GetObjectPosition for root elements because this function is called a zillion times
312 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 272 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
313 return _position; 273 return _position;
314 } 274 }
315 set { 275 set {
316 _position = value; 276 _position = value;
277 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
317 _scene.TaintedObject(delegate() 278 _scene.TaintedObject(delegate()
318 { 279 {
280 DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
319 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 281 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
320 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
321 }); 282 });
322 } 283 }
323 } 284 }
324 public override float Mass { 285
325 get { return _mass; } 286 // Return the effective mass of the object.
287 // If there are multiple items in the linkset, add them together for the root
288 public override float Mass
289 {
290 get
291 {
292 return _linkset.LinksetMass;
293 }
294 }
295
296 // used when we only want this prim's mass and not the linkset thing
297 public float MassRaw { get { return _mass; } }
298
299 // Is this used?
300 public override OMV.Vector3 CenterOfMass
301 {
302 get { return _linkset.CenterOfMass; }
326 } 303 }
304
305 // Is this used?
306 public override OMV.Vector3 GeometricCenter
307 {
308 get { return _linkset.GeometricCenter; }
309 }
310
327 public override OMV.Vector3 Force { 311 public override OMV.Vector3 Force {
328 get { return _force; } 312 get { return _force; }
329 set { 313 set {
330 _force = value; 314 _force = value;
331 _scene.TaintedObject(delegate() 315 _scene.TaintedObject(delegate()
332 { 316 {
333 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 317 DetailLog("{0},SetForce,taint,force={1}", LocalID, _force);
318 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
319 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
334 }); 320 });
335 } 321 }
336 } 322 }
@@ -341,15 +327,22 @@ public sealed class BSPrim : PhysicsActor
341 } 327 }
342 set { 328 set {
343 Vehicle type = (Vehicle)value; 329 Vehicle type = (Vehicle)value;
344 _vehicle.ProcessTypeChange(type);
345 _scene.TaintedObject(delegate() 330 _scene.TaintedObject(delegate()
346 { 331 {
332 DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type);
333 _vehicle.ProcessTypeChange(type);
347 if (type == Vehicle.TYPE_NONE) 334 if (type == Vehicle.TYPE_NONE)
348 { 335 {
349 _scene.RemoveVehiclePrim(this); 336 _scene.RemoveVehiclePrim(this);
350 } 337 }
351 else 338 else
352 { 339 {
340 _scene.TaintedObject(delegate()
341 {
342 // Tell the physics engine to clear state
343 BulletSimAPI.ClearForces2(this.Body.Ptr);
344 });
345
353 // make it so the scene will call us each tick to do vehicle things 346 // make it so the scene will call us each tick to do vehicle things
354 _scene.AddVehiclePrim(this); 347 _scene.AddVehiclePrim(this);
355 } 348 }
@@ -359,47 +352,59 @@ public sealed class BSPrim : PhysicsActor
359 } 352 }
360 public override void VehicleFloatParam(int param, float value) 353 public override void VehicleFloatParam(int param, float value)
361 { 354 {
362 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 355 _scene.TaintedObject(delegate()
356 {
357 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
358 });
363 } 359 }
364 public override void VehicleVectorParam(int param, OMV.Vector3 value) 360 public override void VehicleVectorParam(int param, OMV.Vector3 value)
365 { 361 {
366 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 362 _scene.TaintedObject(delegate()
363 {
364 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
365 });
367 } 366 }
368 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 367 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
369 { 368 {
370 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 369 _scene.TaintedObject(delegate()
370 {
371 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
372 });
371 } 373 }
372 public override void VehicleFlags(int param, bool remove) 374 public override void VehicleFlags(int param, bool remove)
373 { 375 {
374 _vehicle.ProcessVehicleFlags(param, remove); 376 _scene.TaintedObject(delegate()
377 {
378 _vehicle.ProcessVehicleFlags(param, remove);
379 });
375 } 380 }
376 // Called each simulation step to advance vehicle characteristics 381
382 // Called each simulation step to advance vehicle characteristics.
383 // Called from Scene when doing simulation step so we're in taint processing time.
377 public void StepVehicle(float timeStep) 384 public void StepVehicle(float timeStep)
378 { 385 {
379 _vehicle.Step(timeStep, _scene); 386 if (IsPhysical)
387 _vehicle.Step(timeStep);
380 } 388 }
381 389
382 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 390 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
383 public override void SetVolumeDetect(int param) { 391 public override void SetVolumeDetect(int param) {
384 bool newValue = (param != 0); 392 bool newValue = (param != 0);
385 if (_isVolumeDetect != newValue) 393 _isVolumeDetect = newValue;
394 _scene.TaintedObject(delegate()
386 { 395 {
387 _isVolumeDetect = newValue; 396 SetObjectDynamic();
388 _scene.TaintedObject(delegate() 397 });
389 {
390 SetObjectDynamic();
391 });
392 }
393 return; 398 return;
394 } 399 }
395 400
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 { 401 public override OMV.Vector3 Velocity {
399 get { return _velocity; } 402 get { return _velocity; }
400 set { _velocity = value; 403 set {
404 _velocity = value;
401 _scene.TaintedObject(delegate() 405 _scene.TaintedObject(delegate()
402 { 406 {
407 DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity);
403 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 408 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
404 }); 409 });
405 } 410 }
@@ -407,6 +412,7 @@ public sealed class BSPrim : PhysicsActor
407 public override OMV.Vector3 Torque { 412 public override OMV.Vector3 Torque {
408 get { return _torque; } 413 get { return _torque; }
409 set { _torque = value; 414 set { _torque = value;
415 DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque);
410 } 416 }
411 } 417 }
412 public override float CollisionScore { 418 public override float CollisionScore {
@@ -419,13 +425,21 @@ public sealed class BSPrim : PhysicsActor
419 set { _acceleration = value; } 425 set { _acceleration = value; }
420 } 426 }
421 public override OMV.Quaternion Orientation { 427 public override OMV.Quaternion Orientation {
422 get { return _orientation; } 428 get {
429 if (!_linkset.IsRoot(this))
430 {
431 // Children move around because tied to parent. Get a fresh value.
432 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
433 }
434 return _orientation;
435 }
423 set { 436 set {
424 _orientation = value; 437 _orientation = value;
425 // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); 438 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
426 _scene.TaintedObject(delegate() 439 _scene.TaintedObject(delegate()
427 { 440 {
428 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 441 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
442 DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
429 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 443 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
430 }); 444 });
431 } 445 }
@@ -458,25 +472,22 @@ public sealed class BSPrim : PhysicsActor
458 get { return !IsPhantom && !_isVolumeDetect; } 472 get { return !IsPhantom && !_isVolumeDetect; }
459 } 473 }
460 474
461 // make gravity work if the object is physical and not selected 475 // Make gravity work if the object is physical and not selected
462 // no locking here because only called when it is safe 476 // No locking here because only called when it is safe
477 // Only called at taint time so it is save to call into Bullet.
463 private void SetObjectDynamic() 478 private void SetObjectDynamic()
464 { 479 {
465 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); 480 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
466 // non-physical things work best with a mass of zero
467 if (IsStatic)
468 {
469 _mass = 0f;
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 481
478 } 482 RecreateGeomAndObject();
479 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); 483
484 float mass = _mass;
485 // Bullet wants static objects have a mass of zero
486 if (IsStatic)
487 mass = 0f;
488
489 DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
490 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
480 } 491 }
481 492
482 // prims don't fly 493 // prims don't fly
@@ -516,11 +527,24 @@ public sealed class BSPrim : PhysicsActor
516 set { _floatOnWater = value; } 527 set { _floatOnWater = value; }
517 } 528 }
518 public override OMV.Vector3 RotationalVelocity { 529 public override OMV.Vector3 RotationalVelocity {
519 get { return _rotationalVelocity; } 530 get {
520 set { _rotationalVelocity = value; 531 /*
532 OMV.Vector3 pv = OMV.Vector3.Zero;
533 // if close to zero, report zero
534 // This is copied from ODE but I'm not sure why it returns zero but doesn't
535 // zero the property in the physics engine.
536 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
537 return pv;
538 */
539
540 return _rotationalVelocity;
541 }
542 set {
543 _rotationalVelocity = value;
521 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 544 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
522 _scene.TaintedObject(delegate() 545 _scene.TaintedObject(delegate()
523 { 546 {
547 DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
524 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 548 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
525 }); 549 });
526 } 550 }
@@ -533,11 +557,13 @@ public sealed class BSPrim : PhysicsActor
533 } 557 }
534 public override float Buoyancy { 558 public override float Buoyancy {
535 get { return _buoyancy; } 559 get { return _buoyancy; }
536 set { _buoyancy = value; 560 set {
537 _scene.TaintedObject(delegate() 561 _buoyancy = value;
538 { 562 _scene.TaintedObject(delegate()
539 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); 563 {
540 }); 564 DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
565 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
566 });
541 } 567 }
542 } 568 }
543 569
@@ -573,27 +599,45 @@ public sealed class BSPrim : PhysicsActor
573 public override float APIDStrength { set { return; } } 599 public override float APIDStrength { set { return; } }
574 public override float APIDDamping { set { return; } } 600 public override float APIDDamping { set { return; } }
575 601
602 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
576 public override void AddForce(OMV.Vector3 force, bool pushforce) { 603 public override void AddForce(OMV.Vector3 force, bool pushforce) {
577 if (force.IsFinite()) 604 if (force.IsFinite())
578 { 605 {
579 _force.X += force.X; 606 // _force += force;
580 _force.Y += force.Y; 607 lock (m_accumulatedForces)
581 _force.Z += force.Z; 608 m_accumulatedForces.Add(new OMV.Vector3(force));
582 } 609 }
583 else 610 else
584 { 611 {
585 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 612 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
613 return;
586 } 614 }
587 _scene.TaintedObject(delegate() 615 _scene.TaintedObject(delegate()
588 { 616 {
589 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 617 lock (m_accumulatedForces)
618 {
619 if (m_accumulatedForces.Count > 0)
620 {
621 OMV.Vector3 fSum = OMV.Vector3.Zero;
622 foreach (OMV.Vector3 v in m_accumulatedForces)
623 {
624 fSum += v;
625 }
626 m_accumulatedForces.Clear();
627
628 DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum);
629 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum);
630 }
631 }
590 }); 632 });
591 } 633 }
592 634
593 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 635 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
636 DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
594 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 637 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
595 } 638 }
596 public override void SetMomentum(OMV.Vector3 momentum) { 639 public override void SetMomentum(OMV.Vector3 momentum) {
640 DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum);
597 } 641 }
598 public override void SubscribeEvents(int ms) { 642 public override void SubscribeEvents(int ms) {
599 _subscribedEventsMs = ms; 643 _subscribedEventsMs = ms;
@@ -885,6 +929,9 @@ public sealed class BSPrim : PhysicsActor
885 929
886 returnMass = _density * volume; 930 returnMass = _density * volume;
887 931
932 /*
933 * This change means each object keeps its own mass and the Mass property
934 * will return the sum if we're part of a linkset.
888 if (IsRootOfLinkset) 935 if (IsRootOfLinkset)
889 { 936 {
890 foreach (BSPrim prim in _childrenPrims) 937 foreach (BSPrim prim in _childrenPrims)
@@ -892,6 +939,7 @@ public sealed class BSPrim : PhysicsActor
892 returnMass += prim.CalculateMass(); 939 returnMass += prim.CalculateMass();
893 } 940 }
894 } 941 }
942 */
895 943
896 if (returnMass <= 0) 944 if (returnMass <= 0)
897 returnMass = 0.0001f; 945 returnMass = 0.0001f;
@@ -907,9 +955,11 @@ public sealed class BSPrim : PhysicsActor
907 // The objects needs a hull if it's physical otherwise a mesh is enough 955 // 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 956 // 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 957 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
910 private void CreateGeom(bool forceRebuild) 958 // Returns 'true' if the geometry was rebuilt
959 private bool CreateGeom(bool forceRebuild)
911 { 960 {
912 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. 961 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
962 bool ret = false;
913 if (!_scene.NeedsMeshing(_pbs)) 963 if (!_scene.NeedsMeshing(_pbs))
914 { 964 {
915 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) 965 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -917,16 +967,26 @@ public sealed class BSPrim : PhysicsActor
917 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) 967 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
918 { 968 {
919 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); 969 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
920 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; 970 if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)
921 // Bullet native objects are scaled by the Bullet engine so pass the size in 971 {
922 _scale = _size; 972 DetailLog("{0},CreateGeom,sphere", LocalID);
973 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
974 ret = true;
975 // Bullet native objects are scaled by the Bullet engine so pass the size in
976 _scale = _size;
977 }
923 } 978 }
924 } 979 }
925 else 980 else
926 { 981 {
927 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); 982 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
928 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; 983 if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)
929 _scale = _size; 984 {
985 DetailLog("{0},CreateGeom,box", LocalID);
986 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
987 ret = true;
988 _scale = _size;
989 }
930 } 990 }
931 } 991 }
932 else 992 else
@@ -938,6 +998,7 @@ public sealed class BSPrim : PhysicsActor
938 // physical objects require a hull for interaction. 998 // physical objects require a hull for interaction.
939 // This will create the mesh if it doesn't already exist 999 // This will create the mesh if it doesn't already exist
940 CreateGeomHull(); 1000 CreateGeomHull();
1001 ret = true;
941 } 1002 }
942 } 1003 }
943 else 1004 else
@@ -946,9 +1007,11 @@ public sealed class BSPrim : PhysicsActor
946 { 1007 {
947 // Static (non-physical) objects only need a mesh for bumping into 1008 // Static (non-physical) objects only need a mesh for bumping into
948 CreateGeomMesh(); 1009 CreateGeomMesh();
1010 ret = true;
949 } 1011 }
950 } 1012 }
951 } 1013 }
1014 return ret;
952 } 1015 }
953 1016
954 // No locking here because this is done when we know physics is not simulating 1017 // No locking here because this is done when we know physics is not simulating
@@ -961,10 +1024,12 @@ public sealed class BSPrim : PhysicsActor
961 // if this new shape is the same as last time, don't recreate the mesh 1024 // if this new shape is the same as last time, don't recreate the mesh
962 if (_meshKey == newMeshKey) return; 1025 if (_meshKey == newMeshKey) return;
963 1026
1027 DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey);
964 // Since we're recreating new, get rid of any previously generated shape 1028 // Since we're recreating new, get rid of any previously generated shape
965 if (_meshKey != 0) 1029 if (_meshKey != 0)
966 { 1030 {
967 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); 1031 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1032 DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
968 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1033 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
969 _mesh = null; 1034 _mesh = null;
970 _meshKey = 0; 1035 _meshKey = 0;
@@ -981,7 +1046,6 @@ public sealed class BSPrim : PhysicsActor
981 int vi = 0; 1046 int vi = 0;
982 foreach (OMV.Vector3 vv in vertices) 1047 foreach (OMV.Vector3 vv in vertices)
983 { 1048 {
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; 1049 verticesAsFloats[vi++] = vv.X;
986 verticesAsFloats[vi++] = vv.Y; 1050 verticesAsFloats[vi++] = vv.Y;
987 verticesAsFloats[vi++] = vv.Z; 1051 verticesAsFloats[vi++] = vv.Z;
@@ -995,6 +1059,7 @@ public sealed class BSPrim : PhysicsActor
995 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; 1059 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
996 // meshes are already scaled by the meshmerizer 1060 // meshes are already scaled by the meshmerizer
997 _scale = new OMV.Vector3(1f, 1f, 1f); 1061 _scale = new OMV.Vector3(1f, 1f, 1f);
1062 DetailLog("{0},CreateGeomMesh,done", LocalID);
998 return; 1063 return;
999 } 1064 }
1000 1065
@@ -1008,13 +1073,17 @@ public sealed class BSPrim : PhysicsActor
1008 // if the hull hasn't changed, don't rebuild it 1073 // if the hull hasn't changed, don't rebuild it
1009 if (newHullKey == _hullKey) return; 1074 if (newHullKey == _hullKey) return;
1010 1075
1076 DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey);
1077
1011 // Since we're recreating new, get rid of any previously generated shape 1078 // Since we're recreating new, get rid of any previously generated shape
1012 if (_hullKey != 0) 1079 if (_hullKey != 0)
1013 { 1080 {
1014 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); 1081 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1082 DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey);
1015 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); 1083 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1016 _hullKey = 0; 1084 _hullKey = 0;
1017 _hulls.Clear(); 1085 _hulls.Clear();
1086 DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey);
1018 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1087 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1019 _mesh = null; // the mesh cannot match either 1088 _mesh = null; // the mesh cannot match either
1020 _meshKey = 0; 1089 _meshKey = 0;
@@ -1111,6 +1180,7 @@ public sealed class BSPrim : PhysicsActor
1111 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; 1180 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1112 // meshes are already scaled by the meshmerizer 1181 // meshes are already scaled by the meshmerizer
1113 _scale = new OMV.Vector3(1f, 1f, 1f); 1182 _scale = new OMV.Vector3(1f, 1f, 1f);
1183 DetailLog("{0},CreateGeomHull,done", LocalID);
1114 return; 1184 return;
1115 } 1185 }
1116 1186
@@ -1126,45 +1196,18 @@ public sealed class BSPrim : PhysicsActor
1126 // No locking here because this is done when the physics engine is not simulating 1196 // No locking here because this is done when the physics engine is not simulating
1127 private void CreateObject() 1197 private void CreateObject()
1128 { 1198 {
1129 if (IsRootOfLinkset) 1199 // 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 1200
1146 // Create a linkset by creating a compound hull at the root prim that consists of all 1201 // the mesh or hull must have already been created in Bullet
1147 // the children. 1202 ShapeData shape;
1148 // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution 1203 FillShapeInfo(out shape);
1149 void CreateLinksetWithCompoundHull() 1204 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1150 { 1205 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1151 // If I am the root prim of a linkset, replace my physical shape with all the 1206 // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
1152 // pieces of the children. 1207 m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID);
1153 // All of the children should have called CreateGeom so they have a hull 1208
1154 // in the physics engine already. Here we pull together all of those hulls 1209 // The root object could have been recreated. Make sure everything linksety is up to date.
1155 // into one shape. 1210 _linkset.RefreshLinkset(this);
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 } 1211 }
1169 1212
1170 // Copy prim's info into the BulletSim shape description structure 1213 // Copy prim's info into the BulletSim shape description structure
@@ -1186,44 +1229,6 @@ public sealed class BSPrim : PhysicsActor
1186 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1229 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1187 } 1230 }
1188 1231
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 1232
1228 // Rebuild the geometry and object. 1233 // Rebuild the geometry and object.
1229 // This is called when the shape changes so we need to recreate the mesh/hull. 1234 // This is called when the shape changes so we need to recreate the mesh/hull.
@@ -1252,78 +1257,71 @@ public sealed class BSPrim : PhysicsActor
1252 const float POSITION_TOLERANCE = 0.05f; 1257 const float POSITION_TOLERANCE = 0.05f;
1253 const float ACCELERATION_TOLERANCE = 0.01f; 1258 const float ACCELERATION_TOLERANCE = 0.01f;
1254 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1259 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1255 const bool SHOULD_DAMP_UPDATES = false;
1256 1260
1257 public void UpdateProperties(EntityProperties entprop) 1261 public void UpdateProperties(EntityProperties entprop)
1258 { 1262 {
1263 /*
1259 UpdatedProperties changed = 0; 1264 UpdatedProperties changed = 0;
1260 if (SHOULD_DAMP_UPDATES) 1265 // assign to the local variables so the normal set action does not happen
1266 // if (_position != entprop.Position)
1267 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1261 { 1268 {
1262 // assign to the local variables so the normal set action does not happen 1269 _position = entprop.Position;
1263 // if (_position != entprop.Position) 1270 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 } 1271 }
1309 else 1272 // if (_orientation != entprop.Rotation)
1273 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1310 { 1274 {
1311 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1275 _orientation = entprop.Rotation;
1312 1276 changed |= UpdatedProperties.Rotation;
1313 // Only updates only for individual prims and for the root object of a linkset. 1277 }
1278 // if (_velocity != entprop.Velocity)
1279 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1280 {
1281 _velocity = entprop.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 changed |= UpdatedProperties.Acceleration;
1289 }
1290 // if (_rotationalVelocity != entprop.RotationalVelocity)
1291 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1292 {
1293 _rotationalVelocity = entprop.RotationalVelocity;
1294 changed |= UpdatedProperties.RotationalVel;
1295 }
1296 if (changed != 0)
1297 {
1298 // Only update the position of single objects and linkset roots
1314 if (this._parentPrim == null) 1299 if (this._parentPrim == null)
1315 { 1300 {
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(); 1301 base.RequestPhysicsterseUpdate();
1325 } 1302 }
1326 } 1303 }
1304 */
1305
1306 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1307
1308 // Updates only for individual prims and for the root object of a linkset.
1309 if (_linkset.IsRoot(this))
1310 {
1311 // Assign to the local variables so the normal set action does not happen
1312 _position = entprop.Position;
1313 _orientation = entprop.Rotation;
1314 _velocity = entprop.Velocity;
1315 _acceleration = entprop.Acceleration;
1316 _rotationalVelocity = entprop.RotationalVelocity;
1317
1318 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1319 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1320 DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1321 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1322
1323 base.RequestPhysicsterseUpdate();
1324 }
1327 } 1325 }
1328 1326
1329 // I've collided with something 1327 // I've collided with something
@@ -1362,5 +1360,11 @@ public sealed class BSPrim : PhysicsActor
1362 collisionCollection.Clear(); 1360 collisionCollection.Clear();
1363 } 1361 }
1364 } 1362 }
1363
1364 // Invoke the detailed logger and output something if it's enabled.
1365 private void DetailLog(string msg, params Object[] args)
1366 {
1367 Scene.PhysicsLogging.Write(msg, args);
1368 }
1365} 1369}
1366} 1370}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f..c6d622b 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 {
@@ -347,34 +323,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
347 public override void RemoveAvatar(PhysicsActor actor) 323 public override void RemoveAvatar(PhysicsActor actor)
348 { 324 {
349 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); 325 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
350 if (actor is BSCharacter) 326 BSCharacter bsactor = actor as BSCharacter;
351 { 327 if (bsactor != null)
352 ((BSCharacter)actor).Destroy();
353 }
354 try
355 { 328 {
356 lock (m_avatars) m_avatars.Remove(actor.LocalID); 329 try
357 } 330 {
358 catch (Exception e) 331 lock (m_avatars) m_avatars.Remove(actor.LocalID);
359 { 332 }
360 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); 333 catch (Exception e)
334 {
335 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
336 }
337 bsactor.Destroy();
338 // bsactor.dispose();
361 } 339 }
362 } 340 }
363 341
364 public override void RemovePrim(PhysicsActor prim) 342 public override void RemovePrim(PhysicsActor prim)
365 { 343 {
366 // m_log.DebugFormat("{0}: RemovePrim", LogHeader); 344 BSPrim bsprim = prim as BSPrim;
367 if (prim is BSPrim) 345 if (bsprim != null)
368 { 346 {
369 ((BSPrim)prim).Destroy(); 347 m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
370 } 348 try
371 try 349 {
372 { 350 lock (m_prims) m_prims.Remove(bsprim.LocalID);
373 lock (m_prims) m_prims.Remove(prim.LocalID); 351 }
352 catch (Exception e)
353 {
354 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
355 }
356 bsprim.Destroy();
357 // bsprim.dispose();
374 } 358 }
375 catch (Exception e) 359 else
376 { 360 {
377 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); 361 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
378 } 362 }
379 } 363 }
380 364
@@ -400,6 +384,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 int collidersCount; 384 int collidersCount;
401 IntPtr collidersPtr; 385 IntPtr collidersPtr;
402 386
387 LastSimulatedTimestep = timeStep;
388
403 // prevent simulation until we've been initialized 389 // prevent simulation until we've been initialized
404 if (!m_initialized) return 10.0f; 390 if (!m_initialized) return 10.0f;
405 391
@@ -459,7 +445,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
459 for (int ii = 0; ii < updatedEntityCount; ii++) 445 for (int ii = 0; ii < updatedEntityCount; ii++)
460 { 446 {
461 EntityProperties entprop = m_updateArray[ii]; 447 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; 448 BSPrim prim;
464 if (m_prims.TryGetValue(entprop.ID, out prim)) 449 if (m_prims.TryGetValue(entprop.ID, out prim))
465 { 450 {
@@ -532,8 +517,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
532 }); 517 });
533 } 518 }
534 519
520 // Someday we will have complex terrain with caves and tunnels
521 // For the moment, it's flat and convex
522 public float GetTerrainHeightAtXYZ(Vector3 loc)
523 {
524 return GetTerrainHeightAtXY(loc.X, loc.Y);
525 }
526
535 public float GetTerrainHeightAtXY(float tX, float tY) 527 public float GetTerrainHeightAtXY(float tX, float tY)
536 { 528 {
529 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
530 return 30;
537 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; 531 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
538 } 532 }
539 533
@@ -555,6 +549,33 @@ public class BSScene : PhysicsScene, IPhysicsParameters
555 public override void Dispose() 549 public override void Dispose()
556 { 550 {
557 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 551 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
552
553 // make sure no stepping happens while we're deleting stuff
554 m_initialized = false;
555
556 if (m_constraintCollection != null)
557 {
558 m_constraintCollection.Dispose();
559 m_constraintCollection = null;
560 }
561
562 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
563 {
564 kvp.Value.Destroy();
565 }
566 m_avatars.Clear();
567
568 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
569 {
570 kvp.Value.Destroy();
571 }
572 m_prims.Clear();
573
574 // Anything left in the unmanaged code should be cleaned out
575 BulletSimAPI.Shutdown(WorldID);
576
577 // Not logging any more
578 PhysicsLogging.Close();
558 } 579 }
559 580
560 public override Dictionary<uint, float> GetTopColliders() 581 public override Dictionary<uint, float> GetTopColliders()
@@ -680,10 +701,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
680 } 701 }
681 702
682 // The calls to the PhysicsActors can't directly call into the physics engine 703 // 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. 704 // 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. 705 // We rely on C#'s closure to save and restore the context for the delegate.
685 public void TaintedObject(TaintCallback callback) 706 public void TaintedObject(TaintCallback callback)
686 { 707 {
708 if (!m_initialized) return;
709
687 lock (_taintLock) 710 lock (_taintLock)
688 _taintedObjects.Add(callback); 711 _taintedObjects.Add(callback);
689 return; 712 return;
@@ -757,61 +780,371 @@ public class BSScene : PhysicsScene, IPhysicsParameters
757 } 780 }
758 #endregion Vehicles 781 #endregion Vehicles
759 782
760 #region Runtime settable parameters 783 #region Parameters
761 public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] 784
762 { 785 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)"), 786 delegate float ParamGet(BSScene scene);
764 new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), 787 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
765 new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), 788
766 new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), 789 private struct ParameterDefn
767 new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), 790 {
768 new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"), 791 public string name;
769 792 public string desc;
770 new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"), 793 public float defaultValue;
771 new PhysParameterEntry("DefaultDensity", "Density for new objects" ), 794 public ParamUser userParam;
772 new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ), 795 public ParamGet getter;
773 // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ), 796 public ParamSet setter;
774 new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ), 797 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
775 798 {
776 new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ), 799 name = n;
777 new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ), 800 desc = d;
778 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), 801 defaultValue = v;
779 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), 802 userParam = u;
780 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), 803 getter = g;
781 new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ), 804 setter = s;
782 new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ), 805 }
783 new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ), 806 }
784 // Can only change the following at initialization time. Change the INI file and reboot. 807
785 new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"), 808 // List of all of the externally visible parameters.
786 new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"), 809 // For each parameter, this table maps a text name to getter and setters.
787 new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"), 810 // A ParameterDefn() takes the following parameters:
788 new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"), 811 // -- the text name of the parameter. This is used for console input and ini file.
789 new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"), 812 // -- a short text description of the parameter. This shows up in the console listing.
790 new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"), 813 // -- a delegate for fetching the parameter from the ini file.
791 new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"), 814 // Should handle fetching the right type from the ini file and converting it.
792 815 // -- a delegate for getting the value as a float
793 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 816 // -- a delegate for setting the value from a float
794 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 817 //
795 818 // To add a new variable, it is best to find an existing definition and copy it.
796 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 819 private ParameterDefn[] ParameterDefinitions =
797 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 820 {
798 821 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
799 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), 822 ConfigurationParameters.numericTrue,
800 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), 823 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
801 new PhysParameterEntry("TerrainRestitution", "Bouncyness" ), 824 (s) => { return s.NumericBool(s._meshSculptedPrim); },
802 new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ), 825 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ),
803 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), 826 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
804 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), 827 ConfigurationParameters.numericFalse,
805 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), 828 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
806 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ), 829 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); },
807 new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions") 830 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ),
831
832 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
833 8f,
834 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
835 (s) => { return (float)s.m_meshLOD; },
836 (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
837 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
838 32,
839 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
840 (s) => { return (float)s.m_sculptLOD; },
841 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
842
843 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
844 10f,
845 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
846 (s) => { return (float)s.m_maxSubSteps; },
847 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
848 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
849 1f / 60f,
850 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
851 (s) => { return (float)s.m_fixedTimeStep; },
852 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
853 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
854 2048f,
855 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
856 (s) => { return (float)s.m_maxCollisionsPerFrame; },
857 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
858 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
859 8000f,
860 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
861 (s) => { return (float)s.m_maxUpdatesPerFrame; },
862 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
863 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
864 10000.01f,
865 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
866 (s) => { return (float)s.m_maximumObjectMass; },
867 (s,p,l,v) => { s.m_maximumObjectMass = v; } ),
868
869 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
870 2200f,
871 (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
872 (s) => { return (float)s.PID_D; },
873 (s,p,l,v) => { s.PID_D = v; } ),
874 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
875 900f,
876 (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
877 (s) => { return (float)s.PID_P; },
878 (s,p,l,v) => { s.PID_P = v; } ),
879
880 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
881 0.5f,
882 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
883 (s) => { return s.m_params[0].defaultFriction; },
884 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
885 new ParameterDefn("DefaultDensity", "Density for new objects" ,
886 10.000006836f, // Aluminum g/cm3
887 (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
888 (s) => { return s.m_params[0].defaultDensity; },
889 (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
890 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
891 0f,
892 (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
893 (s) => { return s.m_params[0].defaultRestitution; },
894 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
895 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
896 0f,
897 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
898 (s) => { return s.m_params[0].collisionMargin; },
899 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
900 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
901 -9.80665f,
902 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
903 (s) => { return s.m_params[0].gravity; },
904 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
905
906
907 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
908 0f,
909 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
910 (s) => { return s.m_params[0].linearDamping; },
911 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
912 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
913 0f,
914 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
915 (s) => { return s.m_params[0].angularDamping; },
916 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
917 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
918 0.2f,
919 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
920 (s) => { return s.m_params[0].deactivationTime; },
921 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
922 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
923 0.8f,
924 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
925 (s) => { return s.m_params[0].linearSleepingThreshold; },
926 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
927 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
928 1.0f,
929 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
930 (s) => { return s.m_params[0].angularSleepingThreshold; },
931 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
932 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
933 0f, // set to zero to disable
934 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
935 (s) => { return s.m_params[0].ccdMotionThreshold; },
936 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
937 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
938 0f,
939 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
940 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
941 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
942 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
943 0.1f,
944 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
945 (s) => { return s.m_params[0].contactProcessingThreshold; },
946 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
947
948 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
949 0.5f,
950 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
951 (s) => { return s.m_params[0].terrainFriction; },
952 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
953 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
954 0.8f,
955 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
956 (s) => { return s.m_params[0].terrainHitFraction; },
957 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
958 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
959 0f,
960 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
961 (s) => { return s.m_params[0].terrainRestitution; },
962 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
963 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
964 0.5f,
965 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
966 (s) => { return s.m_params[0].avatarFriction; },
967 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
968 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
969 60f,
970 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].avatarDensity; },
972 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
973 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
974 0f,
975 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
976 (s) => { return s.m_params[0].avatarRestitution; },
977 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
978 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
979 0.37f,
980 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
981 (s) => { return s.m_params[0].avatarCapsuleRadius; },
982 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
983 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
984 1.5f,
985 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
986 (s) => { return s.m_params[0].avatarCapsuleHeight; },
987 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
988 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
989 0.1f,
990 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
991 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
992 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
993
994
995 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)",
996 0f, // zero to disable
997 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
999 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1000 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
1001 ConfigurationParameters.numericTrue,
1002 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1003 (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
1004 (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
1005 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
1006 ConfigurationParameters.numericFalse,
1007 (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1008 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1009 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1010 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1011 ConfigurationParameters.numericFalse,
1012 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1013 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1014 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1015 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1016 ConfigurationParameters.numericFalse,
1017 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1018 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1019 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
1020 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
1021 ConfigurationParameters.numericFalse,
1022 (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1023 (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
1024 (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
1025 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
1026 0f, // zero says use Bullet default
1027 (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
1028 (s) => { return s.m_params[0].numberOfSolverIterations; },
1029 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1030
1031 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1032 ConfigurationParameters.numericFalse,
1033 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1034 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1035 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
1036 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
1037 ConfigurationParameters.numericTrue,
1038 (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1039 (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
1040 (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
1041 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
1042 5.0f,
1043 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
1045 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
1046 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
1047 0.1f,
1048 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1050 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1051
1052 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1053 0f,
1054 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1055 (s) => { return (float)s.m_detailedStatsStep; },
1056 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
1057 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1058 ConfigurationParameters.numericFalse,
1059 (s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1060 (s) => { return s.NumericBool(s.shouldDebugLog); },
1061 (s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ),
808 1062
809 }; 1063 };
810 1064
1065 // Convert a boolean to our numeric true and false values
1066 public float NumericBool(bool b)
1067 {
1068 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
1069 }
1070
1071 // Convert numeric true and false values to a boolean
1072 public bool BoolNumeric(float b)
1073 {
1074 return (b == ConfigurationParameters.numericTrue ? true : false);
1075 }
1076
1077 // Search through the parameter definitions and return the matching
1078 // ParameterDefn structure.
1079 // Case does not matter as names are compared after converting to lower case.
1080 // Returns 'false' if the parameter is not found.
1081 private bool TryGetParameter(string paramName, out ParameterDefn defn)
1082 {
1083 bool ret = false;
1084 ParameterDefn foundDefn = new ParameterDefn();
1085 string pName = paramName.ToLower();
1086
1087 foreach (ParameterDefn parm in ParameterDefinitions)
1088 {
1089 if (pName == parm.name.ToLower())
1090 {
1091 foundDefn = parm;
1092 ret = true;
1093 break;
1094 }
1095 }
1096 defn = foundDefn;
1097 return ret;
1098 }
1099
1100 // Pass through the settable parameters and set the default values
1101 private void SetParameterDefaultValues()
1102 {
1103 foreach (ParameterDefn parm in ParameterDefinitions)
1104 {
1105 parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
1106 }
1107 }
1108
1109 // Get user set values out of the ini file.
1110 private void SetParameterConfigurationValues(IConfig cfg)
1111 {
1112 foreach (ParameterDefn parm in ParameterDefinitions)
1113 {
1114 parm.userParam(this, cfg, parm.name, parm.defaultValue);
1115 }
1116 }
1117
1118 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1119
1120 private void BuildParameterTable()
1121 {
1122 if (SettableParameters.Length < ParameterDefinitions.Length)
1123 {
1124
1125 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1126 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1127 {
1128 ParameterDefn pd = ParameterDefinitions[ii];
1129 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
1130 }
1131
1132 // make the list in alphabetical order for estetic reasons
1133 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
1134 {
1135 return ppe1.name.CompareTo(ppe2.name);
1136 });
1137
1138 SettableParameters = entries.ToArray();
1139 }
1140 }
1141
1142
811 #region IPhysicsParameters 1143 #region IPhysicsParameters
812 // Get the list of parameters this physics engine supports 1144 // Get the list of parameters this physics engine supports
813 public PhysParameterEntry[] GetParameterList() 1145 public PhysParameterEntry[] GetParameterList()
814 { 1146 {
1147 BuildParameterTable();
815 return SettableParameters; 1148 return SettableParameters;
816 } 1149 }
817 1150
@@ -823,63 +1156,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
823 // value activated ('terrainFriction' for instance). 1156 // value activated ('terrainFriction' for instance).
824 public bool SetPhysicsParameter(string parm, float val, uint localID) 1157 public bool SetPhysicsParameter(string parm, float val, uint localID)
825 { 1158 {
826 bool ret = true; 1159 bool ret = false;
827 string lparm = parm.ToLower(); 1160 ParameterDefn theParam;
828 switch (lparm) 1161 if (TryGetParameter(parm, out theParam))
829 { 1162 {
830 case "detailedstats": m_detailedStatsStep = (int)val; break; 1163 theParam.setter(this, parm, localID, val);
831 1164 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 } 1165 }
878 return ret; 1166 return ret;
879 } 1167 }
880 1168
881 // check to see if we are updating a parameter for a particular or all of the prims 1169 // 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) 1170 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
883 { 1171 {
884 List<uint> operateOn; 1172 List<uint> operateOn;
885 lock (m_prims) operateOn = new List<uint>(m_prims.Keys); 1173 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
@@ -887,7 +1175,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
887 } 1175 }
888 1176
889 // check to see if we are updating a parameter for a particular or all of the avatars 1177 // 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) 1178 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
891 { 1179 {
892 List<uint> operateOn; 1180 List<uint> operateOn;
893 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1181 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
@@ -898,7 +1186,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
898 // If the local ID is APPLY_TO_NONE, just change the default value 1186 // 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 1187 // 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 1188 // 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) 1189 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
902 { 1190 {
903 switch (localID) 1191 switch (localID)
904 { 1192 {
@@ -925,7 +1213,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
925 } 1213 }
926 1214
927 // schedule the actual updating of the paramter to when the phys engine is not busy 1215 // 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) 1216 protected void TaintedUpdateParameter(string parm, uint localID, float val)
929 { 1217 {
930 uint xlocalID = localID; 1218 uint xlocalID = localID;
931 string xparm = parm.ToLower(); 1219 string xparm = parm.ToLower();
@@ -940,50 +1228,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
940 public bool GetPhysicsParameter(string parm, out float value) 1228 public bool GetPhysicsParameter(string parm, out float value)
941 { 1229 {
942 float val = 0f; 1230 float val = 0f;
943 bool ret = true; 1231 bool ret = false;
944 switch (parm.ToLower()) 1232 ParameterDefn theParam;
945 { 1233 if (TryGetParameter(parm, out theParam))
946 case "detailedstats": val = (int)m_detailedStatsStep; break; 1234 {
947 case "meshlod": val = (float)m_meshLOD; break; 1235 val = theParam.getter(this);
948 case "sculptlod": val = (float)m_sculptLOD; break; 1236 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 } 1237 }
988 value = val; 1238 value = val;
989 return ret; 1239 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 086f0dc..65e3145 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{
@@ -142,10 +164,32 @@ public struct ConfigurationParameters
142 public float shouldEnableFrictionCaching; 164 public float shouldEnableFrictionCaching;
143 public float numberOfSolverIterations; 165 public float numberOfSolverIterations;
144 166
167 public float linkConstraintUseFrameOffset;
168 public float linkConstraintEnableTransMotor;
169 public float linkConstraintTransMotorMaxVel;
170 public float linkConstraintTransMotorMaxForce;
171
145 public const float numericTrue = 1f; 172 public const float numericTrue = 1f;
146 public const float numericFalse = 0f; 173 public const float numericFalse = 0f;
147} 174}
148 175
176// Values used by Bullet and BulletSim to control collisions
177public enum CollisionFlags : uint
178{
179 STATIC_OBJECT = 1 << 0,
180 KINEMATIC_OBJECT = 1 << 1,
181 NO_CONTACT_RESPONSE = 1 << 2,
182 CUSTOM_MATERIAL_CALLBACK = 1 << 3,
183 CHARACTER_OBJECT = 1 << 4,
184 DISABLE_VISUALIZE_OBJECT = 1 << 5,
185 DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
186 // Following used by BulletSim to control collisions
187 VOLUME_DETECT_OBJECT = 1 << 10,
188 PHANTOM_OBJECT = 1 << 11,
189 PHYSICAL_OBJECT = 1 << 12,
190};
191
192// ===============================================================================
149static class BulletSimAPI { 193static class BulletSimAPI {
150 194
151[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 195[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -195,6 +239,7 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
195[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 239[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
196public static extern bool CreateObject(uint worldID, ShapeData shapeData); 240public static extern bool CreateObject(uint worldID, ShapeData shapeData);
197 241
242/* Remove old functionality
198[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 243[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
199public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); 244public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
200 245
@@ -209,11 +254,15 @@ public static extern bool RemoveConstraintByID(uint worldID, uint id1);
209 254
210[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 255[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
211public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); 256public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
257 */
212 258
213[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 259[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
214public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 260public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
215 261
216[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 262[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
263public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
264
265[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
217public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); 266public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
218 267
219[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 268[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -268,5 +317,175 @@ public static extern void DumpBulletStatistics();
268public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 317public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
269[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 318[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
270public static extern void SetDebugLogCallback(DebugLogCallback callback); 319public static extern void SetDebugLogCallback(DebugLogCallback callback);
320
321// ===============================================================================
322// ===============================================================================
323// ===============================================================================
324// A new version of the API that enables moving all the logic out of the C++ code and into
325// the C# code. This will make modifications easier for the next person.
326// This interface passes the actual pointers to the objects in the unmanaged
327// address space. All the management (calls for creation/destruction/lookup)
328// is done in the C# code.
329// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
330// and the old code is removed.
331
332[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
333public static extern IntPtr GetSimHandle2(uint worldID);
334
335[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
336public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
337
338[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
339public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id);
340
341// ===============================================================================
342[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
343public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
344 int maxCollisions, IntPtr collisionArray,
345 int maxUpdates, IntPtr updateArray);
346
347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
348public static extern bool UpdateParameter2(IntPtr sim, uint localID, String parm, float value);
349
350[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
351public static extern void SetHeightmap2(IntPtr sim, float[] heightmap);
352
353[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
354public static extern void Shutdown2(IntPtr sim);
355
356[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
357public static extern int PhysicsStep2(IntPtr sim, float timeStep, int maxSubSteps, float fixedTimeStep,
358 out int updatedEntityCount,
359 out IntPtr updatedEntitiesPtr,
360 out int collidersCount,
361 out IntPtr collidersPtr);
362
363/*
364[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
365public static extern IntPtr CreateMesh2(IntPtr sim, int indicesCount, int* indices, int verticesCount, float* vertices );
366
367[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
368public static extern bool BuildHull2(IntPtr sim, IntPtr mesh);
369
370[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
371public static extern bool ReleaseHull2(IntPtr sim, IntPtr mesh);
372
373[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
374public static extern bool DestroyMesh2(IntPtr sim, IntPtr mesh);
375
376[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
377public static extern IntPtr CreateObject2(IntPtr sim, ShapeData shapeData);
378*/
379
380[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
381public static extern IntPtr CreateConstraint2(IntPtr sim, IntPtr obj1, IntPtr obj2,
382 Vector3 frame1loc, Quaternion frame1rot,
383 Vector3 frame2loc, Quaternion frame2rot);
384
385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
386public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
387
388[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
389public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
390
391[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
392public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
393
394[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
395public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
396
397[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
398public static extern bool CalculateTransforms2(IntPtr constrain);
399
400[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
401public static extern bool DestroyConstraint2(IntPtr sim, IntPtr constrain);
402
403[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
404public static extern Vector3 GetPosition2(IntPtr obj);
405
406[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
407public static extern Quaternion GetOrientation2(IntPtr obj);
408
409[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
410public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
411
412[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
413public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity);
414
415[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
416public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
417
418[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
419public static extern bool SetObjectForce2(IntPtr obj, Vector3 force);
420
421[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
422public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val);
423
424[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
425public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val);
426
427[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
428public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
429
430[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
431public static extern bool SetDeactivationTime2(IntPtr obj, float val);
432
433[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
434public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
435
436[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
437public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
438
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
440public static extern bool SetFriction2(IntPtr obj, float val);
441
442[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
443public static extern bool SetRestitution2(IntPtr obj, float val);
444
445[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
446public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val);
447
448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
449public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang);
450
451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
452public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags);
453
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags);
456
457[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
458public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags);
459
460[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
461public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
462
463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
464public static extern bool UpdateInertiaTensor2(IntPtr obj);
465
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern bool SetGravity2(IntPtr obj, Vector3 val);
468
469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
470public static extern IntPtr ClearForces2(IntPtr obj);
471
472[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
473public static extern bool SetMargin2(IntPtr obj, float val);
474
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
477
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
480
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
483
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern bool DestroyObject2(IntPtr world, uint id);
486
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern void DumpPhysicsStatistics2(IntPtr sim);
489
271} 490}
272} 491}
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()