aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-07-20 23:20:40 +0100
committerJustin Clark-Casey (justincc)2012-07-20 23:20:40 +0100
commitef14232e64c659cb3f0f1bb690e6ce4ac0f3e075 (patch)
tree23037bef0445a91cb764468c8e44eb121198095b /OpenSim/Region
parentMove RegionConfig.ini.example into bin/Regions/Regions.ini.example - all othe... (diff)
parentBulletSim: more detail logging for vehicle and general physics debugging. (diff)
downloadopensim-SC_OLD-ef14232e64c659cb3f0f1bb690e6ce4ac0f3e075.zip
opensim-SC_OLD-ef14232e64c659cb3f0f1bb690e6ce4ac0f3e075.tar.gz
opensim-SC_OLD-ef14232e64c659cb3f0f1bb690e6ce4ac0f3e075.tar.bz2
opensim-SC_OLD-ef14232e64c659cb3f0f1bb690e6ce4ac0f3e075.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs2
-rwxr-xr-xOpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs161
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs69
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs187
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs331
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs136
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs51
7 files changed, 694 insertions, 243 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index a75ff62..9b1b1a3 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -39,7 +39,7 @@ using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41 41
42namespace OpenSim.Region.CoreModules.Avatar.Attachments 42namespace OpenSim.Region.CoreModules.Statistics.Logging
43{ 43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BinaryLoggingModule")] 44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BinaryLoggingModule")]
45 public class BinaryLoggingModule : INonSharedRegionModule 45 public class BinaryLoggingModule : INonSharedRegionModule
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
new file mode 100755
index 0000000..65e4c90
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using log4net;
32
33namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
34{
35 /// <summary>
36 /// Class for writing a high performance, high volume log file.
37 /// Sometimes, to debug, one has a high volume logging to do and the regular
38 /// log file output is not appropriate.
39 /// Create a new instance with the parameters needed and
40 /// call Write() to output a line. Call Close() when finished.
41 /// If created with no parameters, it will not log anything.
42 /// </summary>
43 public class LogWriter : IDisposable
44 {
45 public bool Enabled { get; private set; }
46
47 private string m_logDirectory = ".";
48 private int m_logMaxFileTimeMin = 5; // 5 minutes
49 public String LogFileHeader { get; set; }
50
51 private StreamWriter m_logFile = null;
52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object();
55
56 // set externally when debugging. If let 'null', this does not write any error messages.
57 public ILog ErrorLogger = null;
58 private string LogHeader = "[LOG WRITER]";
59
60 /// <summary>
61 /// Create a log writer that will not write anything. Good for when not enabled
62 /// but the write statements are still in the code.
63 /// </summary>
64 public LogWriter()
65 {
66 Enabled = false;
67 m_logFile = null;
68 }
69
70 /// <summary>
71 /// Create a log writer instance.
72 /// </summary>
73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
76 public LogWriter(string dir, string headr, int maxFileTime)
77 {
78 m_logDirectory = dir == null ? "." : dir;
79
80 LogFileHeader = headr == null ? "log-" : headr;
81
82 m_logMaxFileTimeMin = maxFileTime;
83 if (m_logMaxFileTimeMin < 1)
84 m_logMaxFileTimeMin = 5;
85
86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
87 m_logFileEndTime = DateTime.Now + m_logFileLife;
88
89 Enabled = true;
90 }
91
92 public void Dispose()
93 {
94 this.Close();
95 }
96
97 public void Close()
98 {
99 Enabled = false;
100 if (m_logFile != null)
101 {
102 m_logFile.Close();
103 m_logFile.Dispose();
104 m_logFile = null;
105 }
106 }
107
108 public void Write(string line, params object[] args)
109 {
110 if (!Enabled) return;
111 Write(String.Format(line, args));
112 }
113
114 public void Write(string line)
115 {
116 if (!Enabled) return;
117 try
118 {
119 lock (m_logFileWriteLock)
120 {
121 DateTime now = DateTime.Now;
122 if (m_logFile == null || now > m_logFileEndTime)
123 {
124 if (m_logFile != null)
125 {
126 m_logFile.Close();
127 m_logFile.Dispose();
128 m_logFile = null;
129 }
130
131 // First log file or time has expired, start writing to a new log file
132 m_logFileEndTime = now + m_logFileLife;
133 string path = (m_logDirectory.Length > 0 ? m_logDirectory
134 + System.IO.Path.DirectorySeparatorChar.ToString() : "")
135 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
136 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
137 }
138 if (m_logFile != null)
139 {
140 StringBuilder buff = new StringBuilder(line.Length + 25);
141 buff.Append(now.ToString("yyyyMMddHHmmssfff"));
142 // buff.Append(now.ToString("yyyyMMddHHmmss"));
143 buff.Append(",");
144 buff.Append(line);
145 buff.Append("\r\n");
146 m_logFile.Write(buff.ToString());
147 }
148 }
149 }
150 catch (Exception e)
151 {
152 if (ErrorLogger != null)
153 {
154 ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
155 }
156 Enabled = false;
157 }
158 return;
159 }
160 }
161} \ No newline at end of file
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/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/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 130f1ca..71a4303 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
@@ -86,8 +89,8 @@ 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;
90 private BSPrim _parentPrim; 92 private BSPrim _parentPrim;
93 private List<BSPrim> _childrenPrims;
91 94
92 private int _subscribedEventsMs = 0; 95 private int _subscribedEventsMs = 0;
93 private int _nextCollisionOkTime = 0; 96 private int _nextCollisionOkTime = 0;
@@ -145,9 +148,19 @@ public sealed class BSPrim : PhysicsActor
145 public void Destroy() 148 public void Destroy()
146 { 149 {
147 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 150 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
151 // DetailLog("{0},Destroy", LocalID);
148 // Undo any vehicle properties 152 // Undo any vehicle properties
149 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); 153 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
150 _scene.RemoveVehiclePrim(this); // just to make sure 154 _scene.RemoveVehiclePrim(this); // just to make sure
155
156 // undo any dependance with/on other objects
157 if (_parentPrim != null)
158 {
159 // If I'm someone's child, tell them to forget about me.
160 _parentPrim.RemoveChildFromLinkset(this);
161 _parentPrim = null;
162 }
163
151 _scene.TaintedObject(delegate() 164 _scene.TaintedObject(delegate()
152 { 165 {
153 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 166 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
@@ -202,7 +215,8 @@ public sealed class BSPrim : PhysicsActor
202 // link me to the specified parent 215 // link me to the specified parent
203 public override void link(PhysicsActor obj) { 216 public override void link(PhysicsActor obj) {
204 BSPrim parent = obj as BSPrim; 217 BSPrim parent = obj as BSPrim;
205 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); 218 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
219 DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
206 // TODO: decide if this parent checking needs to happen at taint time 220 // TODO: decide if this parent checking needs to happen at taint time
207 if (_parentPrim == null) 221 if (_parentPrim == null)
208 { 222 {
@@ -225,7 +239,7 @@ public sealed class BSPrim : PhysicsActor
225 else 239 else
226 { 240 {
227 // asking to reparent a prim should not happen 241 // asking to reparent a prim should not happen
228 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader); 242 m_log.ErrorFormat("{0}: link(): Reparenting a prim. ", LogHeader);
229 } 243 }
230 } 244 }
231 } 245 }
@@ -236,7 +250,9 @@ public sealed class BSPrim : PhysicsActor
236 public override void delink() { 250 public override void delink() {
237 // TODO: decide if this parent checking needs to happen at taint time 251 // 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 252 // 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); 253 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
254 (_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString()));
255 DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString()));
240 if (_parentPrim != null) 256 if (_parentPrim != null)
241 { 257 {
242 _parentPrim.RemoveChildFromLinkset(this); 258 _parentPrim.RemoveChildFromLinkset(this);
@@ -252,8 +268,10 @@ public sealed class BSPrim : PhysicsActor
252 { 268 {
253 if (!_childrenPrims.Contains(child)) 269 if (!_childrenPrims.Contains(child))
254 { 270 {
271 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, this.LocalID);
272 DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID);
255 _childrenPrims.Add(child); 273 _childrenPrims.Add(child);
256 child.ParentPrim = this; // the child has gained a parent 274 child._parentPrim = this; // the child has gained a parent
257 RecreateGeomAndObject(); // rebuild my shape with the new child added 275 RecreateGeomAndObject(); // rebuild my shape with the new child added
258 } 276 }
259 }); 277 });
@@ -269,9 +287,14 @@ public sealed class BSPrim : PhysicsActor
269 { 287 {
270 if (_childrenPrims.Contains(child)) 288 if (_childrenPrims.Contains(child))
271 { 289 {
272 BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID); 290 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
291 DetailLog("{0},RemoveChildToLinkset,child={1}", LocalID, pchild.LocalID);
292 if (!BulletSimAPI.RemoveConstraintByID(_scene.WorldID, child.LocalID))
293 {
294 m_log.ErrorFormat("{0}: RemoveChildFromLinkset: Failed remove constraint for {1}", LogHeader, child.LocalID);
295 }
273 _childrenPrims.Remove(child); 296 _childrenPrims.Remove(child);
274 child.ParentPrim = null; // the child has lost its parent 297 child._parentPrim = null; // the child has lost its parent
275 RecreateGeomAndObject(); // rebuild my shape with the child removed 298 RecreateGeomAndObject(); // rebuild my shape with the child removed
276 } 299 }
277 else 300 else
@@ -282,11 +305,6 @@ public sealed class BSPrim : PhysicsActor
282 return; 305 return;
283 } 306 }
284 307
285 public BSPrim ParentPrim
286 {
287 set { _parentPrim = value; }
288 }
289
290 // return true if we are the root of a linkset (there are children to manage) 308 // return true if we are the root of a linkset (there are children to manage)
291 public bool IsRootOfLinkset 309 public bool IsRootOfLinkset
292 { 310 {
@@ -304,20 +322,28 @@ public sealed class BSPrim : PhysicsActor
304 base.RequestPhysicsterseUpdate(); 322 base.RequestPhysicsterseUpdate();
305 } 323 }
306 324
307 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 325 public override void LockAngularMotion(OMV.Vector3 axis)
326 {
327 DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis);
328 return;
329 }
308 330
309 public override OMV.Vector3 Position { 331 public override OMV.Vector3 Position {
310 get { 332 get {
311 // don't do the following GetObjectPosition because this function is called a zillion times 333 // child prims move around based on their parent. Need to get the latest location
334 if (_parentPrim != null)
335 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
336 // don't do the GetObjectPosition for root elements because this function is called a zillion times
312 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 337 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
313 return _position; 338 return _position;
314 } 339 }
315 set { 340 set {
316 _position = value; 341 _position = value;
342 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
317 _scene.TaintedObject(delegate() 343 _scene.TaintedObject(delegate()
318 { 344 {
345 DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
319 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 346 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
320 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
321 }); 347 });
322 } 348 }
323 } 349 }
@@ -330,6 +356,7 @@ public sealed class BSPrim : PhysicsActor
330 _force = value; 356 _force = value;
331 _scene.TaintedObject(delegate() 357 _scene.TaintedObject(delegate()
332 { 358 {
359 DetailLog("{0},SetForce,taint,force={1}", LocalID, _force);
333 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 360 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
334 }); 361 });
335 } 362 }
@@ -341,15 +368,23 @@ public sealed class BSPrim : PhysicsActor
341 } 368 }
342 set { 369 set {
343 Vehicle type = (Vehicle)value; 370 Vehicle type = (Vehicle)value;
344 _vehicle.ProcessTypeChange(type);
345 _scene.TaintedObject(delegate() 371 _scene.TaintedObject(delegate()
346 { 372 {
373 DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type);
374 _vehicle.ProcessTypeChange(type);
347 if (type == Vehicle.TYPE_NONE) 375 if (type == Vehicle.TYPE_NONE)
348 { 376 {
349 _scene.RemoveVehiclePrim(this); 377 _scene.RemoveVehiclePrim(this);
350 } 378 }
351 else 379 else
352 { 380 {
381 _scene.TaintedObject(delegate()
382 {
383 // Tell the physics engine to clear state
384 IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID);
385 BulletSimAPI.ClearForces2(obj);
386 });
387
353 // make it so the scene will call us each tick to do vehicle things 388 // make it so the scene will call us each tick to do vehicle things
354 _scene.AddVehiclePrim(this); 389 _scene.AddVehiclePrim(this);
355 } 390 }
@@ -359,37 +394,52 @@ public sealed class BSPrim : PhysicsActor
359 } 394 }
360 public override void VehicleFloatParam(int param, float value) 395 public override void VehicleFloatParam(int param, float value)
361 { 396 {
362 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 397 m_log.DebugFormat("{0} VehicleFloatParam. {1} <= {2}", LogHeader, param, value);
398 _scene.TaintedObject(delegate()
399 {
400 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
401 });
363 } 402 }
364 public override void VehicleVectorParam(int param, OMV.Vector3 value) 403 public override void VehicleVectorParam(int param, OMV.Vector3 value)
365 { 404 {
366 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 405 m_log.DebugFormat("{0} VehicleVectorParam. {1} <= {2}", LogHeader, param, value);
406 _scene.TaintedObject(delegate()
407 {
408 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
409 });
367 } 410 }
368 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 411 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
369 { 412 {
370 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 413 m_log.DebugFormat("{0} VehicleRotationParam. {1} <= {2}", LogHeader, param, rotation);
414 _scene.TaintedObject(delegate()
415 {
416 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
417 });
371 } 418 }
372 public override void VehicleFlags(int param, bool remove) 419 public override void VehicleFlags(int param, bool remove)
373 { 420 {
374 _vehicle.ProcessVehicleFlags(param, remove); 421 m_log.DebugFormat("{0} VehicleFlags. {1}. Remove={2}", LogHeader, param, remove);
422 _scene.TaintedObject(delegate()
423 {
424 _vehicle.ProcessVehicleFlags(param, remove);
425 });
375 } 426 }
376 // Called each simulation step to advance vehicle characteristics 427
428 // Called each simulation step to advance vehicle characteristics.
429 // Called from Scene when doing simulation step so we're in taint processing time.
377 public void StepVehicle(float timeStep) 430 public void StepVehicle(float timeStep)
378 { 431 {
379 _vehicle.Step(timeStep, _scene); 432 _vehicle.Step(timeStep);
380 } 433 }
381 434
382 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 435 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
383 public override void SetVolumeDetect(int param) { 436 public override void SetVolumeDetect(int param) {
384 bool newValue = (param != 0); 437 bool newValue = (param != 0);
385 if (_isVolumeDetect != newValue) 438 _isVolumeDetect = newValue;
439 _scene.TaintedObject(delegate()
386 { 440 {
387 _isVolumeDetect = newValue; 441 SetObjectDynamic();
388 _scene.TaintedObject(delegate() 442 });
389 {
390 SetObjectDynamic();
391 });
392 }
393 return; 443 return;
394 } 444 }
395 445
@@ -397,9 +447,11 @@ public sealed class BSPrim : PhysicsActor
397 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 447 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
398 public override OMV.Vector3 Velocity { 448 public override OMV.Vector3 Velocity {
399 get { return _velocity; } 449 get { return _velocity; }
400 set { _velocity = value; 450 set {
451 _velocity = value;
401 _scene.TaintedObject(delegate() 452 _scene.TaintedObject(delegate()
402 { 453 {
454 DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity);
403 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 455 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
404 }); 456 });
405 } 457 }
@@ -407,6 +459,7 @@ public sealed class BSPrim : PhysicsActor
407 public override OMV.Vector3 Torque { 459 public override OMV.Vector3 Torque {
408 get { return _torque; } 460 get { return _torque; }
409 set { _torque = value; 461 set { _torque = value;
462 DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque);
410 } 463 }
411 } 464 }
412 public override float CollisionScore { 465 public override float CollisionScore {
@@ -419,13 +472,21 @@ public sealed class BSPrim : PhysicsActor
419 set { _acceleration = value; } 472 set { _acceleration = value; }
420 } 473 }
421 public override OMV.Quaternion Orientation { 474 public override OMV.Quaternion Orientation {
422 get { return _orientation; } 475 get {
476 if (_parentPrim != null)
477 {
478 // children move around because tied to parent. Get a fresh value.
479 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
480 }
481 return _orientation;
482 }
423 set { 483 set {
424 _orientation = value; 484 _orientation = value;
425 // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); 485 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
426 _scene.TaintedObject(delegate() 486 _scene.TaintedObject(delegate()
427 { 487 {
428 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 488 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
489 DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
429 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 490 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
430 }); 491 });
431 } 492 }
@@ -458,8 +519,9 @@ public sealed class BSPrim : PhysicsActor
458 get { return !IsPhantom && !_isVolumeDetect; } 519 get { return !IsPhantom && !_isVolumeDetect; }
459 } 520 }
460 521
461 // make gravity work if the object is physical and not selected 522 // Make gravity work if the object is physical and not selected
462 // no locking here because only called when it is safe 523 // No locking here because only called when it is safe
524 // Only called at taint time so it is save to call into Bullet.
463 private void SetObjectDynamic() 525 private void SetObjectDynamic()
464 { 526 {
465 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); 527 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
@@ -476,6 +538,7 @@ public sealed class BSPrim : PhysicsActor
476 RecreateGeomAndObject(); 538 RecreateGeomAndObject();
477 539
478 } 540 }
541 DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, _mass);
479 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); 542 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
480 } 543 }
481 544
@@ -516,11 +579,24 @@ public sealed class BSPrim : PhysicsActor
516 set { _floatOnWater = value; } 579 set { _floatOnWater = value; }
517 } 580 }
518 public override OMV.Vector3 RotationalVelocity { 581 public override OMV.Vector3 RotationalVelocity {
519 get { return _rotationalVelocity; } 582 get {
520 set { _rotationalVelocity = value; 583 /*
584 OMV.Vector3 pv = OMV.Vector3.Zero;
585 // if close to zero, report zero
586 // This is copied from ODE but I'm not sure why it returns zero but doesn't
587 // zero the property in the physics engine.
588 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
589 return pv;
590 */
591
592 return _rotationalVelocity;
593 }
594 set {
595 _rotationalVelocity = value;
521 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 596 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
522 _scene.TaintedObject(delegate() 597 _scene.TaintedObject(delegate()
523 { 598 {
599 DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
524 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 600 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
525 }); 601 });
526 } 602 }
@@ -533,11 +609,13 @@ public sealed class BSPrim : PhysicsActor
533 } 609 }
534 public override float Buoyancy { 610 public override float Buoyancy {
535 get { return _buoyancy; } 611 get { return _buoyancy; }
536 set { _buoyancy = value; 612 set {
537 _scene.TaintedObject(delegate() 613 _buoyancy = value;
538 { 614 _scene.TaintedObject(delegate()
539 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); 615 {
540 }); 616 DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
617 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
618 });
541 } 619 }
542 } 620 }
543 621
@@ -573,27 +651,45 @@ public sealed class BSPrim : PhysicsActor
573 public override float APIDStrength { set { return; } } 651 public override float APIDStrength { set { return; } }
574 public override float APIDDamping { set { return; } } 652 public override float APIDDamping { set { return; } }
575 653
654 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
576 public override void AddForce(OMV.Vector3 force, bool pushforce) { 655 public override void AddForce(OMV.Vector3 force, bool pushforce) {
577 if (force.IsFinite()) 656 if (force.IsFinite())
578 { 657 {
579 _force.X += force.X; 658 // _force += force;
580 _force.Y += force.Y; 659 lock (m_accumulatedForces)
581 _force.Z += force.Z; 660 m_accumulatedForces.Add(new OMV.Vector3(force));
582 } 661 }
583 else 662 else
584 { 663 {
585 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 664 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
665 return;
586 } 666 }
587 _scene.TaintedObject(delegate() 667 _scene.TaintedObject(delegate()
588 { 668 {
589 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 669 lock (m_accumulatedForces)
670 {
671 if (m_accumulatedForces.Count > 0)
672 {
673 OMV.Vector3 fSum = OMV.Vector3.Zero;
674 foreach (OMV.Vector3 v in m_accumulatedForces)
675 {
676 fSum += v;
677 }
678 m_accumulatedForces.Clear();
679
680 DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum);
681 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum);
682 }
683 }
590 }); 684 });
591 } 685 }
592 686
593 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 687 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
688 DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
594 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 689 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
595 } 690 }
596 public override void SetMomentum(OMV.Vector3 momentum) { 691 public override void SetMomentum(OMV.Vector3 momentum) {
692 DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum);
597 } 693 }
598 public override void SubscribeEvents(int ms) { 694 public override void SubscribeEvents(int ms) {
599 _subscribedEventsMs = ms; 695 _subscribedEventsMs = ms;
@@ -918,6 +1014,7 @@ public sealed class BSPrim : PhysicsActor
918 { 1014 {
919 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); 1015 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
920 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; 1016 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
1017 DetailLog("{0},CreateGeom,sphere", LocalID);
921 // Bullet native objects are scaled by the Bullet engine so pass the size in 1018 // Bullet native objects are scaled by the Bullet engine so pass the size in
922 _scale = _size; 1019 _scale = _size;
923 } 1020 }
@@ -925,6 +1022,7 @@ public sealed class BSPrim : PhysicsActor
925 else 1022 else
926 { 1023 {
927 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); 1024 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
1025 DetailLog("{0},CreateGeom,box", LocalID);
928 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; 1026 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
929 _scale = _size; 1027 _scale = _size;
930 } 1028 }
@@ -961,10 +1059,12 @@ public sealed class BSPrim : PhysicsActor
961 // if this new shape is the same as last time, don't recreate the mesh 1059 // if this new shape is the same as last time, don't recreate the mesh
962 if (_meshKey == newMeshKey) return; 1060 if (_meshKey == newMeshKey) return;
963 1061
1062 DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey);
964 // Since we're recreating new, get rid of any previously generated shape 1063 // Since we're recreating new, get rid of any previously generated shape
965 if (_meshKey != 0) 1064 if (_meshKey != 0)
966 { 1065 {
967 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); 1066 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1067 DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
968 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1068 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
969 _mesh = null; 1069 _mesh = null;
970 _meshKey = 0; 1070 _meshKey = 0;
@@ -981,7 +1081,6 @@ public sealed class BSPrim : PhysicsActor
981 int vi = 0; 1081 int vi = 0;
982 foreach (OMV.Vector3 vv in vertices) 1082 foreach (OMV.Vector3 vv in vertices)
983 { 1083 {
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; 1084 verticesAsFloats[vi++] = vv.X;
986 verticesAsFloats[vi++] = vv.Y; 1085 verticesAsFloats[vi++] = vv.Y;
987 verticesAsFloats[vi++] = vv.Z; 1086 verticesAsFloats[vi++] = vv.Z;
@@ -995,6 +1094,7 @@ public sealed class BSPrim : PhysicsActor
995 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; 1094 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
996 // meshes are already scaled by the meshmerizer 1095 // meshes are already scaled by the meshmerizer
997 _scale = new OMV.Vector3(1f, 1f, 1f); 1096 _scale = new OMV.Vector3(1f, 1f, 1f);
1097 DetailLog("{0},CreateGeomMesh,done", LocalID);
998 return; 1098 return;
999 } 1099 }
1000 1100
@@ -1008,13 +1108,17 @@ public sealed class BSPrim : PhysicsActor
1008 // if the hull hasn't changed, don't rebuild it 1108 // if the hull hasn't changed, don't rebuild it
1009 if (newHullKey == _hullKey) return; 1109 if (newHullKey == _hullKey) return;
1010 1110
1111 DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey);
1112
1011 // Since we're recreating new, get rid of any previously generated shape 1113 // Since we're recreating new, get rid of any previously generated shape
1012 if (_hullKey != 0) 1114 if (_hullKey != 0)
1013 { 1115 {
1014 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); 1116 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1117 DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey);
1015 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); 1118 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1016 _hullKey = 0; 1119 _hullKey = 0;
1017 _hulls.Clear(); 1120 _hulls.Clear();
1121 DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey);
1018 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1122 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1019 _mesh = null; // the mesh cannot match either 1123 _mesh = null; // the mesh cannot match either
1020 _meshKey = 0; 1124 _meshKey = 0;
@@ -1111,6 +1215,7 @@ public sealed class BSPrim : PhysicsActor
1111 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; 1215 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1112 // meshes are already scaled by the meshmerizer 1216 // meshes are already scaled by the meshmerizer
1113 _scale = new OMV.Vector3(1f, 1f, 1f); 1217 _scale = new OMV.Vector3(1f, 1f, 1f);
1218 DetailLog("{0},CreateGeomHull,done", LocalID);
1114 return; 1219 return;
1115 } 1220 }
1116 1221
@@ -1129,7 +1234,6 @@ public sealed class BSPrim : PhysicsActor
1129 if (IsRootOfLinkset) 1234 if (IsRootOfLinkset)
1130 { 1235 {
1131 // Create a linkset around this object 1236 // Create a linkset around this object
1132 // CreateLinksetWithCompoundHull();
1133 CreateLinksetWithConstraints(); 1237 CreateLinksetWithConstraints();
1134 } 1238 }
1135 else 1239 else
@@ -1191,33 +1295,33 @@ public sealed class BSPrim : PhysicsActor
1191 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added 1295 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added
1192 void CreateLinksetWithConstraints() 1296 void CreateLinksetWithConstraints()
1193 { 1297 {
1194 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); 1298 DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1195 1299
1196 // remove any constraints that might be in place 1300 // remove any constraints that might be in place
1197 foreach (BSPrim prim in _childrenPrims) 1301 foreach (BSPrim prim in _childrenPrims)
1198 { 1302 {
1199 // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); 1303 DebugLog("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1200 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); 1304 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1201 } 1305 }
1202 // create constraints between the root prim and each of the children 1306 // create constraints between the root prim and each of the children
1203 foreach (BSPrim prim in _childrenPrims) 1307 foreach (BSPrim prim in _childrenPrims)
1204 { 1308 {
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 1309 // Zero motion for children so they don't interpolate
1208 prim.ZeroMotion(); 1310 prim.ZeroMotion();
1209 1311
1210 // relative position normalized to the root prim 1312 // relative position normalized to the root prim
1211 OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation); 1313 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation);
1314 OMV.Vector3 childRelativePosition = (prim._position - this._position) * invThisOrientation;
1212 1315
1213 // relative rotation of the child to the parent 1316 // relative rotation of the child to the parent
1214 OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation; 1317 OMV.Quaternion childRelativeRotation = invThisOrientation * prim._orientation;
1215 1318
1216 // this is a constraint that allows no freedom of movement between the two objects 1319 // this is a constraint that allows no freedom of movement between the two objects
1217 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 1320 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1321 DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1218 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, 1322 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID,
1219 childRelativePosition, 1323 childRelativePosition,
1220 relativeRotation, 1324 childRelativeRotation,
1221 OMV.Vector3.Zero, 1325 OMV.Vector3.Zero,
1222 OMV.Quaternion.Identity, 1326 OMV.Quaternion.Identity,
1223 OMV.Vector3.Zero, OMV.Vector3.Zero, 1327 OMV.Vector3.Zero, OMV.Vector3.Zero,
@@ -1252,78 +1356,71 @@ public sealed class BSPrim : PhysicsActor
1252 const float POSITION_TOLERANCE = 0.05f; 1356 const float POSITION_TOLERANCE = 0.05f;
1253 const float ACCELERATION_TOLERANCE = 0.01f; 1357 const float ACCELERATION_TOLERANCE = 0.01f;
1254 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1358 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1255 const bool SHOULD_DAMP_UPDATES = false;
1256 1359
1257 public void UpdateProperties(EntityProperties entprop) 1360 public void UpdateProperties(EntityProperties entprop)
1258 { 1361 {
1362 /*
1259 UpdatedProperties changed = 0; 1363 UpdatedProperties changed = 0;
1260 if (SHOULD_DAMP_UPDATES) 1364 // assign to the local variables so the normal set action does not happen
1365 // if (_position != entprop.Position)
1366 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1261 { 1367 {
1262 // assign to the local variables so the normal set action does not happen 1368 _position = entprop.Position;
1263 // if (_position != entprop.Position) 1369 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 } 1370 }
1309 else 1371 // if (_orientation != entprop.Rotation)
1372 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1310 { 1373 {
1311 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1374 _orientation = entprop.Rotation;
1312 1375 changed |= UpdatedProperties.Rotation;
1313 // Only updates only for individual prims and for the root object of a linkset. 1376 }
1377 // if (_velocity != entprop.Velocity)
1378 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1379 {
1380 _velocity = entprop.Velocity;
1381 changed |= UpdatedProperties.Velocity;
1382 }
1383 // if (_acceleration != entprop.Acceleration)
1384 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1385 {
1386 _acceleration = entprop.Acceleration;
1387 changed |= UpdatedProperties.Acceleration;
1388 }
1389 // if (_rotationalVelocity != entprop.RotationalVelocity)
1390 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1391 {
1392 _rotationalVelocity = entprop.RotationalVelocity;
1393 changed |= UpdatedProperties.RotationalVel;
1394 }
1395 if (changed != 0)
1396 {
1397 // Only update the position of single objects and linkset roots
1314 if (this._parentPrim == null) 1398 if (this._parentPrim == null)
1315 { 1399 {
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(); 1400 base.RequestPhysicsterseUpdate();
1325 } 1401 }
1326 } 1402 }
1403 */
1404
1405 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1406
1407 // Updates only for individual prims and for the root object of a linkset.
1408 if (this._parentPrim == null)
1409 {
1410 // Assign to the local variables so the normal set action does not happen
1411 _position = entprop.Position;
1412 _orientation = entprop.Rotation;
1413 _velocity = entprop.Velocity;
1414 _acceleration = entprop.Acceleration;
1415 _rotationalVelocity = entprop.RotationalVelocity;
1416
1417 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1418 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1419 DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1420 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1421
1422 base.RequestPhysicsterseUpdate();
1423 }
1327 } 1424 }
1328 1425
1329 // I've collided with something 1426 // I've collided with something
@@ -1362,5 +1459,11 @@ public sealed class BSPrim : PhysicsActor
1362 collisionCollection.Clear(); 1459 collisionCollection.Clear();
1363 } 1460 }
1364 } 1461 }
1462
1463 // Invoke the detailed logger and output something if it's enabled.
1464 private void DetailLog(string msg, params Object[] args)
1465 {
1466 Scene.PhysicsLogging.Write(msg, args);
1467 }
1365} 1468}
1366} 1469}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f..9d41ce8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -29,12 +29,13 @@ 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;
35using OpenSim.Region.Physics.Manager; 34using OpenSim.Region.Physics.Manager;
35using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
36using Nini.Config;
37using log4net;
36using OpenMetaverse; 38using OpenMetaverse;
37using OpenSim.Region.Framework;
38 39
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 40// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Debug linkset 41// Debug linkset
@@ -44,15 +45,17 @@ using OpenSim.Region.Framework;
44// Compute physics FPS reasonably 45// Compute physics FPS reasonably
45// Based on material, set density and friction 46// Based on material, set density and friction
46// More efficient memory usage when passing hull information from BSPrim to BulletSim 47// More efficient memory usage when passing hull information from BSPrim to BulletSim
48// 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? 49// 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) 50// 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 51// At the moment, physical and phantom causes object to drop through the terrain
50// Physical phantom objects and related typing (collision options ) 52// Physical phantom objects and related typing (collision options )
53// Use collision masks for collision with terrain and phantom objects
51// Check out llVolumeDetect. Must do something for that. 54// Check out llVolumeDetect. Must do something for that.
52// Should prim.link() and prim.delink() membership checking happen at taint time? 55// Should prim.link() and prim.delink() membership checking happen at taint time?
56// 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 57// 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 58// 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) 59// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
57// Implement LockAngularMotion 60// Implement LockAngularMotion
58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 61// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@@ -60,9 +63,6 @@ using OpenSim.Region.Framework;
60// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 63// 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? 64// Add PID movement operations. What does ScenePresence.MoveToTarget do?
62// Check terrain size. 128 or 127? 65// 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 66// Raycast
67// 67//
68namespace OpenSim.Region.Physics.BulletSPlugin 68namespace OpenSim.Region.Physics.BulletSPlugin
@@ -72,6 +72,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
72 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 72 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
73 private static readonly string LogHeader = "[BULLETS SCENE]"; 73 private static readonly string LogHeader = "[BULLETS SCENE]";
74 74
75 private void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
76
75 public string BulletSimVersion = "?"; 77 public string BulletSimVersion = "?";
76 78
77 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 79 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
@@ -105,6 +107,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
105 private long m_simulationStep = 0; 107 private long m_simulationStep = 0;
106 public long SimulationStep { get { return m_simulationStep; } } 108 public long SimulationStep { get { return m_simulationStep; } }
107 109
110 public float LastSimulatedTimestep { get; private set; }
111
108 // A value of the time now so all the collision and update routines do not have to get their own 112 // 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 113 // Set to 'now' just before all the prims and actors are called for collisions and updates
110 private int m_simulationNowTime; 114 private int m_simulationNowTime;
@@ -121,6 +125,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
121 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 125 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 126 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
123 127
128 public float PID_D { get; private set; } // derivative
129 public float PID_P { get; private set; } // proportional
130
124 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 131 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
125 public const uint GROUNDPLANE_ID = 1; 132 public const uint GROUNDPLANE_ID = 1;
126 133
@@ -147,8 +154,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
147 ConfigurationParameters[] m_params; 154 ConfigurationParameters[] m_params;
148 GCHandle m_paramsHandle; 155 GCHandle m_paramsHandle;
149 156
157 public bool shouldDebugLog { get; private set; }
158
150 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 159 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
151 160
161 // Sometimes you just have to log everything.
162 public Logging.LogWriter PhysicsLogging;
163 private bool m_physicsLoggingEnabled;
164 private string m_physicsLoggingDir;
165 private string m_physicsLoggingPrefix;
166 private int m_physicsLoggingFileMinutes;
167
168 private bool m_vehicleLoggingEnabled;
169 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
170
152 public BSScene(string identifier) 171 public BSScene(string identifier)
153 { 172 {
154 m_initialized = false; 173 m_initialized = false;
@@ -169,17 +188,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
169 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 188 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
170 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 189 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
171 190
191 // Enable very detailed logging.
192 // By creating an empty logger when not logging, the log message invocation code
193 // can be left in and every call doesn't have to check for null.
194 if (m_physicsLoggingEnabled)
195 {
196 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
197 }
198 else
199 {
200 PhysicsLogging = new Logging.LogWriter();
201 }
202
172 // Get the version of the DLL 203 // Get the version of the DLL
173 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 204 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
174 // BulletSimVersion = BulletSimAPI.GetVersion(); 205 // BulletSimVersion = BulletSimAPI.GetVersion();
175 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); 206 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
176 207
177 // if Debug, enable logging from the unmanaged code 208 // if Debug, enable logging from the unmanaged code
178 if (m_log.IsDebugEnabled) 209 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
179 { 210 {
180 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 211 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 212 if (PhysicsLogging.Enabled)
182 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 213 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
214 else
215 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
216 // the handle is saved in a variable to make sure it doesn't get freed after this call
183 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); 217 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
184 } 218 }
185 219
@@ -209,6 +243,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
209 m_meshLOD = 8f; 243 m_meshLOD = 8f;
210 m_sculptLOD = 32f; 244 m_sculptLOD = 32f;
211 245
246 shouldDebugLog = false;
212 m_detailedStatsStep = 0; // disabled 247 m_detailedStatsStep = 0; // disabled
213 248
214 m_maxSubSteps = 10; 249 m_maxSubSteps = 10;
@@ -217,6 +252,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
217 m_maxUpdatesPerFrame = 2048; 252 m_maxUpdatesPerFrame = 2048;
218 m_maximumObjectMass = 10000.01f; 253 m_maximumObjectMass = 10000.01f;
219 254
255 PID_D = 2200f;
256 PID_P = 900f;
257
220 parms.defaultFriction = 0.5f; 258 parms.defaultFriction = 0.5f;
221 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 259 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
222 parms.defaultRestitution = 0f; 260 parms.defaultRestitution = 0f;
@@ -261,7 +299,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
261 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); 299 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
262 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); 300 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
263 301
302 shouldDebugLog = pConfig.GetBoolean("ShouldDebugLog", shouldDebugLog);
264 m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep); 303 m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep);
304
265 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); 305 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD);
266 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); 306 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD);
267 307
@@ -271,6 +311,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
271 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame); 311 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
272 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass); 312 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
273 313
314 PID_D = pConfig.GetFloat("PIDDerivative", PID_D);
315 PID_P = pConfig.GetFloat("PIDProportional", PID_P);
316
274 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction); 317 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
275 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity); 318 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
276 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution); 319 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
@@ -303,6 +346,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
303 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands); 346 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
304 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching); 347 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
305 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations); 348 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
349
350 // Very detailed logging for physics debugging
351 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
352 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
353 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-");
354 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
355 // Very detailed logging for vehicle debugging
356 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
306 } 357 }
307 } 358 }
308 m_params[0] = parms; 359 m_params[0] = parms;
@@ -323,12 +374,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
323 return ret; 374 return ret;
324 } 375 }
325 376
326
327 // Called directly from unmanaged code so don't do much 377 // Called directly from unmanaged code so don't do much
328 private void BulletLogger(string msg) 378 private void BulletLogger(string msg)
329 { 379 {
330 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 380 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
331 } 381 }
382
383 // Called directly from unmanaged code so don't do much
384 private void BulletLoggerPhysLog(string msg)
385 {
386 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
387 }
332 388
333 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 389 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
334 { 390 {
@@ -347,34 +403,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
347 public override void RemoveAvatar(PhysicsActor actor) 403 public override void RemoveAvatar(PhysicsActor actor)
348 { 404 {
349 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); 405 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
350 if (actor is BSCharacter) 406 BSCharacter bsactor = actor as BSCharacter;
351 { 407 if (bsactor != null)
352 ((BSCharacter)actor).Destroy();
353 }
354 try
355 { 408 {
356 lock (m_avatars) m_avatars.Remove(actor.LocalID); 409 try
357 } 410 {
358 catch (Exception e) 411 lock (m_avatars) m_avatars.Remove(actor.LocalID);
359 { 412 }
360 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); 413 catch (Exception e)
414 {
415 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
416 }
417 bsactor.Destroy();
418 // bsactor.dispose();
361 } 419 }
362 } 420 }
363 421
364 public override void RemovePrim(PhysicsActor prim) 422 public override void RemovePrim(PhysicsActor prim)
365 { 423 {
366 // m_log.DebugFormat("{0}: RemovePrim", LogHeader); 424 BSPrim bsprim = prim as BSPrim;
367 if (prim is BSPrim) 425 if (bsprim != null)
368 {
369 ((BSPrim)prim).Destroy();
370 }
371 try
372 { 426 {
373 lock (m_prims) m_prims.Remove(prim.LocalID); 427 m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
428 try
429 {
430 lock (m_prims) m_prims.Remove(bsprim.LocalID);
431 }
432 catch (Exception e)
433 {
434 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
435 }
436 bsprim.Destroy();
437 // bsprim.dispose();
374 } 438 }
375 catch (Exception e) 439 else
376 { 440 {
377 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); 441 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
378 } 442 }
379 } 443 }
380 444
@@ -400,6 +464,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 int collidersCount; 464 int collidersCount;
401 IntPtr collidersPtr; 465 IntPtr collidersPtr;
402 466
467 LastSimulatedTimestep = timeStep;
468
403 // prevent simulation until we've been initialized 469 // prevent simulation until we've been initialized
404 if (!m_initialized) return 10.0f; 470 if (!m_initialized) return 10.0f;
405 471
@@ -459,7 +525,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
459 for (int ii = 0; ii < updatedEntityCount; ii++) 525 for (int ii = 0; ii < updatedEntityCount; ii++)
460 { 526 {
461 EntityProperties entprop = m_updateArray[ii]; 527 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; 528 BSPrim prim;
464 if (m_prims.TryGetValue(entprop.ID, out prim)) 529 if (m_prims.TryGetValue(entprop.ID, out prim))
465 { 530 {
@@ -532,8 +597,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
532 }); 597 });
533 } 598 }
534 599
600 // Someday we will have complex terrain with caves and tunnels
601 // For the moment, it's flat and convex
602 public float GetTerrainHeightAtXYZ(Vector3 loc)
603 {
604 return GetTerrainHeightAtXY(loc.X, loc.Y);
605 }
606
535 public float GetTerrainHeightAtXY(float tX, float tY) 607 public float GetTerrainHeightAtXY(float tX, float tY)
536 { 608 {
609 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
610 return 30;
537 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; 611 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
538 } 612 }
539 613
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 086f0dc..babb707 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -146,6 +146,22 @@ public struct ConfigurationParameters
146 public const float numericFalse = 0f; 146 public const float numericFalse = 0f;
147} 147}
148 148
149// Values used by Bullet and BulletSim to control collisions
150public enum CollisionFlags : uint
151{
152 STATIC_OBJECT = 1 << 0,
153 KINEMATIC_OBJECT = 1 << 1,
154 NO_CONTACT_RESPONSE = 1 << 2,
155 CUSTOM_MATERIAL_CALLBACK = 1 << 3,
156 CHARACTER_OBJECT = 1 << 4,
157 DISABLE_VISUALIZE_OBJECT = 1 << 5,
158 DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
159 // Following used by BulletSim to control collisions
160 VOLUME_DETECT_OBJECT = 1 << 10,
161 PHANTOM_OBJECT = 1 << 11,
162 PHYSICAL_OBJECT = 1 << 12,
163};
164
149static class BulletSimAPI { 165static class BulletSimAPI {
150 166
151[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 167[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -214,6 +230,9 @@ public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
214public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 230public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
215 231
216[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 232[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
233public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
234
235[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
217public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); 236public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
218 237
219[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 238[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -268,5 +287,37 @@ public static extern void DumpBulletStatistics();
268public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 287public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
269[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
270public static extern void SetDebugLogCallback(DebugLogCallback callback); 289public static extern void SetDebugLogCallback(DebugLogCallback callback);
290
291// ===============================================================================
292// ===============================================================================
293// ===============================================================================
294// A new version of the API that moves all the logic out of the C++ code and into
295// the C# code. This will make modifications easier for the next person.
296// This interface passes the actual pointers to the objects in the unmanaged
297// address space. All the management (calls for creation/destruction/lookup)
298// is done in the C# code.
299// The names have a 2 tacked on. This will be removed as the code gets rebuilt
300// and the old code is removed from the C# code.
301[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
302public static extern IntPtr GetSimHandle2(uint worldID);
303
304[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
305public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
306
307[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
308public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id);
309
310[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
311public static extern IntPtr ClearForces2(IntPtr obj);
312
313[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
314public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags);
315
316[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
317public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags);
318
319[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
320public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags);
321
271} 322}
272} 323}