aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
authorRobert Adams2012-08-25 23:18:46 -0700
committerRobert Adams2012-08-31 11:41:18 -0700
commit7c140570db3b01eb83efc0d42a47715d3047e376 (patch)
treeb077012e0c00cc7bb07f6e81e07359e14ffd2721 /OpenSim/Region/Physics/BulletSPlugin
parentBulletSim: unify physical objects under BSPhysObjects. Now BSScene and BSLink... (diff)
downloadopensim-SC_OLD-7c140570db3b01eb83efc0d42a47715d3047e376.zip
opensim-SC_OLD-7c140570db3b01eb83efc0d42a47715d3047e376.tar.gz
opensim-SC_OLD-7c140570db3b01eb83efc0d42a47715d3047e376.tar.bz2
opensim-SC_OLD-7c140570db3b01eb83efc0d42a47715d3047e376.tar.xz
BulletSim: Changes to terrain storage and management so mega-regions work.
Moved all terrain code out of BSScene and into new BSTerrainManager. Added logic to manage multiple terrains for mega-regions. Added new functions to BulletSimAPI to match the library. Moved all of the terrain creation and setup logic from C++ code to C# code. The unused code has not yet been removed from either place. Soon. Moved checks for avatar above ground and in bounds into BSCharacter.
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs37
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs3
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs9
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs118
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs245
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs307
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs61
8 files changed, 597 insertions, 185 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 784076d..e76d8a4 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -226,16 +226,37 @@ public class BSCharacter : BSPhysObject
226 bool ret = false; 226 bool ret = false;
227 227
228 // If below the ground, move the avatar up 228 // If below the ground, move the avatar up
229 float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); 229 float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position);
230 if (_position.Z < terrainHeight) 230 if (Position.Z < terrainHeight)
231 { 231 {
232 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); 232 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
233 _position.Z = terrainHeight + 2.0f; 233 Vector3 newPos = _position;
234 newPos.Z = terrainHeight + 2.0f;
235 _position = newPos;
234 ret = true; 236 ret = true;
235 } 237 }
236 238
237 // TODO: check for out of bounds 239 // TODO: check for out of bounds
240 return ret;
241 }
238 242
243 // A version of the sanity check that also makes sure a new position value is
244 // pushed back to the physics engine. This routine would be used by anyone
245 // who is not already pushing the value.
246 private bool PositionSanityCheck2()
247 {
248 bool ret = false;
249 if (PositionSanityCheck())
250 {
251 // The new position value must be pushed into the physics engine but we can't
252 // just assign to "Position" because of potential call loops.
253 _scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
254 {
255 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
256 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
257 });
258 ret = true;
259 }
239 return ret; 260 return ret;
240 } 261 }
241 262
@@ -500,9 +521,13 @@ public class BSCharacter : BSPhysObject
500 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 521 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
501 // base.RequestPhysicsterseUpdate(); 522 // base.RequestPhysicsterseUpdate();
502 523
503 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 524 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
525 PositionSanityCheck2();
526
527 float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // just for debug
528 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
504 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 529 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
505 entprop.Acceleration, entprop.RotationalVelocity); 530 entprop.Acceleration, entprop.RotationalVelocity, heightHere);
506 } 531 }
507 532
508 // Called by the scene when a collision with this object is reported 533 // Called by the scene when a collision with this object is reported
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 25084d8..d9270d1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -48,11 +48,10 @@ public abstract class BSConstraint : IDisposable
48 { 48 {
49 if (m_enabled) 49 if (m_enabled)
50 { 50 {
51 // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID); 51 m_enabled = false;
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr); 52 bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
53 m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); 53 m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
54 m_constraint.Ptr = System.IntPtr.Zero; 54 m_constraint.Ptr = System.IntPtr.Zero;
55 m_enabled = false;
56 } 55 }
57 } 56 }
58 57
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index d7213fc..8169e99 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -465,6 +465,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
465 } 465 }
466 }//end SetDefaultsForType 466 }//end SetDefaultsForType
467 467
468 // One step of the vehicle properties for the next 'pTimestep' seconds.
468 internal void Step(float pTimestep) 469 internal void Step(float pTimestep)
469 { 470 {
470 if (m_type == Vehicle.TYPE_NONE) return; 471 if (m_type == Vehicle.TYPE_NONE) return;
@@ -592,9 +593,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
592 } 593 }
593 594
594 // If below the terrain, move us above the ground a little. 595 // If below the terrain, move us above the ground a little.
595 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) 596 if (pos.Z < m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos))
596 { 597 {
597 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; 598 pos.Z = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2;
598 m_prim.Position = pos; 599 m_prim.Position = pos;
599 VDetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); 600 VDetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos);
600 } 601 }
@@ -609,7 +610,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
609 } 610 }
610 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 611 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
611 { 612 {
612 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 613 m_VhoverTargetHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
613 } 614 }
614 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 615 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
615 { 616 {
@@ -673,7 +674,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
673 { 674 {
674 grav.Z = (float)(grav.Z * 1.125); 675 grav.Z = (float)(grav.Z * 1.125);
675 } 676 }
676 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos); 677 float terraintemp = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos);
677 float postemp = (pos.Z - terraintemp); 678 float postemp = (pos.Z - terraintemp);
678 if (postemp > 2.5f) 679 if (postemp > 2.5f)
679 { 680 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 6e205a9..ef463ca 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -1,58 +1,60 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30 30
31using OMV = OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37// Class to wrap all objects. 37// Class to wrap all objects.
38// The rest of BulletSim doesn't need to keep checking for avatars or prims 38// The rest of BulletSim doesn't need to keep checking for avatars or prims
39// unless the difference is significant. 39// unless the difference is significant.
40public abstract class BSPhysObject : PhysicsActor 40public abstract class BSPhysObject : PhysicsActor
41{ 41{
42 public abstract BSLinkset Linkset { get; set; } 42 public abstract BSLinkset Linkset { get; set; }
43 43
44 public abstract void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type, 44 public abstract void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type,
45 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); 45 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
46 public abstract void SendCollisions(); 46 public abstract void SendCollisions();
47 47
48 // Return the object mass without calculating it or side effects 48 // Return the object mass without calculating it or side effects
49 public abstract float MassRaw { get; } 49 public abstract float MassRaw { get; }
50 50
51 public abstract BulletBody Body { get; set; } 51 public abstract BulletBody Body { get; set; }
52 public abstract void ZeroMotion(); 52 public abstract void ZeroMotion();
53 53
54 public abstract void UpdateProperties(EntityProperties entprop); 54 public virtual void StepVehicle(float timeStep) { }
55 55
56 public abstract void Destroy(); 56 public abstract void UpdateProperties(EntityProperties entprop);
57} 57
58} 58 public abstract void Destroy();
59}
60}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 036fd4f..6bfce5c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -377,7 +377,7 @@ public sealed class BSPrim : BSPhysObject
377 377
378 // Called each simulation step to advance vehicle characteristics. 378 // Called each simulation step to advance vehicle characteristics.
379 // Called from Scene when doing simulation step so we're in taint processing time. 379 // Called from Scene when doing simulation step so we're in taint processing time.
380 public void StepVehicle(float timeStep) 380 public override void StepVehicle(float timeStep)
381 { 381 {
382 if (IsPhysical) 382 if (IsPhysical)
383 _vehicle.Step(timeStep); 383 _vehicle.Step(timeStep);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index ce64b9b..f80304d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,8 +39,6 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Debug linkset
43// Test with multiple regions in one simulator
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) 42// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties 43// Test sculpties
46// Compute physics FPS reasonably 44// Compute physics FPS reasonably
@@ -54,10 +52,8 @@ using OpenMetaverse;
54// Use collision masks for collision with terrain and phantom objects 52// Use collision masks for collision with terrain and phantom objects
55// Check out llVolumeDetect. Must do something for that. 53// Check out llVolumeDetect. Must do something for that.
56// Should prim.link() and prim.delink() membership checking happen at taint time? 54// Should prim.link() and prim.delink() membership checking happen at taint time?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root.
58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 55// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 56// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
61// Implement LockAngularMotion 57// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
63// Does NeedsMeshing() really need to exclude all the different shapes? 59// Does NeedsMeshing() really need to exclude all the different shapes?
@@ -85,18 +81,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
85 // moved to a better place. 81 // moved to a better place.
86 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); 82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
87 83
88 private List<BSPrim> m_vehicles = new List<BSPrim>(); 84 // List of all the objects that have vehicle properties and should be called
89 85 // to update each physics step.
90 private float[] m_heightMap; 86 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
91 private float m_waterLevel;
92 private uint m_worldID;
93 public uint WorldID { get { return m_worldID; } }
94 87
95 // let my minuions use my logger 88 // let my minuions use my logger
96 public ILog Logger { get { return m_log; } } 89 public ILog Logger { get { return m_log; } }
97 90
98 private bool m_initialized = false; 91 // If non-zero, the number of simulation steps between calls to the physics
99 92 // engine to output detailed physics stats. Debug logging level must be on also.
100 private int m_detailedStatsStep = 0; 93 private int m_detailedStatsStep = 0;
101 94
102 public IMesher mesher; 95 public IMesher mesher;
@@ -106,29 +99,31 @@ public class BSScene : PhysicsScene, IPhysicsParameters
106 public float MeshMegaPrimThreshold { get; private set; } 99 public float MeshMegaPrimThreshold { get; private set; }
107 public float SculptLOD { get; private set; } 100 public float SculptLOD { get; private set; }
108 101
109 private BulletSim m_worldSim; 102 public uint WorldID { get; private set; }
110 public BulletSim World 103 public BulletSim World { get; private set; }
111 { 104
112 get { return m_worldSim; } 105 // All the constraints that have been allocated in this instance.
113 } 106 public BSConstraintCollection Constraints { get; private set; }
114 private BSConstraintCollection m_constraintCollection;
115 public BSConstraintCollection Constraints
116 {
117 get { return m_constraintCollection; }
118 }
119 107
108 // Simulation parameters
120 private int m_maxSubSteps; 109 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 110 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 111 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 112 public long SimulationStep { get { return m_simulationStep; } }
124 113
114 // The length of the last timestep we were asked to simulate.
115 // This is used by the vehicle code. Since the vehicle code is called
116 // once per simulation step, its constants need to be scaled by this.
125 public float LastSimulatedTimestep { get; private set; } 117 public float LastSimulatedTimestep { get; private set; }
126 118
127 // A value of the time now so all the collision and update routines do not have to get their own 119 // A value of the time now so all the collision and update routines do not have to get their own
128 // Set to 'now' just before all the prims and actors are called for collisions and updates 120 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 121 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 122
123 // True if initialized and ready to do simulation steps
124 private bool m_initialized = false;
131 125
126 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 127 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 128 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 129 private GCHandle m_collisionArrayPinnedHandle;
@@ -145,6 +140,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
145 140
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 141 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 142 public const uint GROUNDPLANE_ID = 1;
143 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
144
145 private float m_waterLevel;
146 public BSTerrainManager TerrainManager { get; private set; }
148 147
149 public ConfigurationParameters Params 148 public ConfigurationParameters Params
150 { 149 {
@@ -155,12 +154,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
155 get { return new Vector3(0f, 0f, Params.gravity); } 154 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 155 }
157 156
158 private float m_maximumObjectMass; 157 public float MaximumObjectMass { get; private set; }
159 public float MaximumObjectMass
160 {
161 get { return m_maximumObjectMass; }
162 }
163 158
159 // When functions in the unmanaged code must be called, it is only
160 // done at a known time just before the simulation step. The taint
161 // system saves all these function calls and executes them in
162 // order before the simulation.
164 public delegate void TaintCallback(); 163 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 164 private struct TaintCallbackEntry
166 { 165 {
@@ -176,6 +175,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
176 private Object _taintLock = new Object(); 175 private Object _taintLock = new Object();
177 176
178 // A pointer to an instance if this structure is passed to the C++ code 177 // A pointer to an instance if this structure is passed to the C++ code
178 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 179 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 180 GCHandle m_paramsHandle;
181 181
@@ -189,11 +189,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private bool m_physicsLoggingEnabled; 189 private bool m_physicsLoggingEnabled;
190 private string m_physicsLoggingDir; 190 private string m_physicsLoggingDir;
191 private string m_physicsLoggingPrefix; 191 private string m_physicsLoggingPrefix;
192 private int m_physicsLoggingFileMinutes; 192 private int m_physicsLoggingFileMinutes;
193 193 // 'true' of the vehicle code is to log lots of details
194 private bool m_vehicleLoggingEnabled; 194 public bool VehicleLoggingEnabled { get; private set; }
195 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
196 195
196 #region Construction and Initialization
197 public BSScene(string identifier) 197 public BSScene(string identifier)
198 { 198 {
199 m_initialized = false; 199 m_initialized = false;
@@ -216,6 +216,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
216 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 216 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
217 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 217 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
218 218
219 mesher = meshmerizer;
220 _taintedObjects = new List<TaintCallbackEntry>();
221
219 // Enable very detailed logging. 222 // Enable very detailed logging.
220 // By creating an empty logger when not logging, the log message invocation code 223 // By creating an empty logger when not logging, the log message invocation code
221 // can be left in and every call doesn't have to check for null. 224 // can be left in and every call doesn't have to check for null.
@@ -228,11 +231,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
228 PhysicsLogging = new Logging.LogWriter(); 231 PhysicsLogging = new Logging.LogWriter();
229 } 232 }
230 233
231 // Get the version of the DLL
232 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
233 // BulletSimVersion = BulletSimAPI.GetVersion();
234 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
235
236 // If Debug logging level, enable logging from the unmanaged code 234 // If Debug logging level, enable logging from the unmanaged code
237 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 235 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
238 { 236 {
@@ -245,22 +243,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
245 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); 243 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
246 } 244 }
247 245
248 _taintedObjects = new List<TaintCallbackEntry>(); 246 // Get the version of the DLL
249 247 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
250 mesher = meshmerizer; 248 // BulletSimVersion = BulletSimAPI.GetVersion();
249 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
251 250
252 // The bounding box for the simulated world 251 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
252 // a child in a mega-region.
253 // Turns out that Bullet really doesn't care about the extents of the simulated
254 // area. It tracks active objects no matter where they are.
253 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 255 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
254 256
255 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 257 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
256 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 258 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
257 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 259 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
258 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 260 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
259 261
260 // Initialization to support the transition to a new API which puts most of the logic 262 // Initialization to support the transition to a new API which puts most of the logic
261 // into the C# code so it is easier to modify and add to. 263 // into the C# code so it is easier to modify and add to.
262 m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); 264 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
263 m_constraintCollection = new BSConstraintCollection(World); 265
266 Constraints = new BSConstraintCollection(World);
267
268 // Note: choose one of the two following lines
269 // BulletSimAPI.CreateInitialGroundPlaneAndTerrain(WorldID);
270 TerrainManager = new BSTerrainManager(this);
271 TerrainManager.CreateInitialGroundPlaneAndTerrain();
264 272
265 m_initialized = true; 273 m_initialized = true;
266 } 274 }
@@ -288,7 +296,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
288 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 296 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
289 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 297 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
290 // Very detailed logging for vehicle debugging 298 // Very detailed logging for vehicle debugging
291 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 299 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
292 300
293 // Do any replacements in the parameters 301 // Do any replacements in the parameters
294 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 302 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
@@ -323,6 +331,38 @@ public class BSScene : PhysicsScene, IPhysicsParameters
323 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 331 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
324 } 332 }
325 333
334 public override void Dispose()
335 {
336 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
337
338 // make sure no stepping happens while we're deleting stuff
339 m_initialized = false;
340
341 TerrainManager.ReleaseGroundPlaneAndTerrain();
342
343 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
344 {
345 kvp.Value.Destroy();
346 }
347 PhysObjects.Clear();
348
349 // Now that the prims are all cleaned up, there should be no constraints left
350 if (Constraints != null)
351 {
352 Constraints.Dispose();
353 Constraints = null;
354 }
355
356 // Anything left in the unmanaged code should be cleaned out
357 BulletSimAPI.Shutdown(WorldID);
358
359 // Not logging any more
360 PhysicsLogging.Close();
361 }
362 #endregion // Construction and Initialization
363
364 #region Prim and Avatar addition and removal
365
326 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 366 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
327 { 367 {
328 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 368 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -413,6 +453,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
413 // information call is not needed. 453 // information call is not needed.
414 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 454 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
415 455
456 #endregion // Prim and Avatar addition and removal
457
458 #region Simulation
416 // Simulate one timestep 459 // Simulate one timestep
417 public override float Simulate(float timeStep) 460 public override float Simulate(float timeStep)
418 { 461 {
@@ -428,7 +471,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
428 471
429 int simulateStartTime = Util.EnvironmentTickCount(); 472 int simulateStartTime = Util.EnvironmentTickCount();
430 473
431 // update the prim states while we know the physics engine is not busy 474 // update the prim states while we know the physics engine is not busy
475 int numTaints = _taintedObjects.Count;
432 ProcessTaints(); 476 ProcessTaints();
433 477
434 // Some of the prims operate with special vehicle properties 478 // Some of the prims operate with special vehicle properties
@@ -440,14 +484,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
440 int numSubSteps = 0; 484 int numSubSteps = 0;
441 try 485 try
442 { 486 {
443 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 487 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
444 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 488 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
445 DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 489 DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}",
490 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
446 } 491 }
447 catch (Exception e) 492 catch (Exception e)
448 { 493 {
449 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 494 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
450 // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 495 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
496 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
497 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
451 updatedEntityCount = 0; 498 updatedEntityCount = 0;
452 collidersCount = 0; 499 collidersCount = 0;
453 } 500 }
@@ -456,7 +503,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
456 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 503 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
457 504
458 // Get a value for 'now' so all the collision and update routines don't have to get their own 505 // Get a value for 'now' so all the collision and update routines don't have to get their own
459 m_simulationNowTime = Util.EnvironmentTickCount(); 506 SimulationNowTime = Util.EnvironmentTickCount();
460 507
461 // If there were collisions, process them by sending the event to the prim. 508 // If there were collisions, process them by sending the event to the prim.
462 // Collisions must be processed before updates. 509 // Collisions must be processed before updates.
@@ -527,7 +574,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
527 // Something has collided 574 // Something has collided
528 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) 575 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
529 { 576 {
530 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 577 if (localID <= TerrainManager.HighestTerrainID)
531 { 578 {
532 return; // don't send collisions to the terrain 579 return; // don't send collisions to the terrain
533 } 580 }
@@ -539,7 +586,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
539 BSPhysObject collidee = null; 586 BSPhysObject collidee = null;
540 587
541 ActorTypes type = ActorTypes.Prim; 588 ActorTypes type = ActorTypes.Prim;
542 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 589 if (collidingWith <= TerrainManager.HighestTerrainID)
543 { 590 {
544 type = ActorTypes.Ground; 591 type = ActorTypes.Ground;
545 } 592 }
@@ -558,28 +605,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
558 return; 605 return;
559 } 606 }
560 607
608 #endregion // Simulation
609
561 public override void GetResults() { } 610 public override void GetResults() { }
562 611
563 public override void SetTerrain(float[] heightMap) { 612 #region Terrain
564 m_heightMap = heightMap;
565 this.TaintedObject("BSScene.SetTerrain", delegate()
566 {
567 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
568 });
569 }
570 613
571 // Someday we will have complex terrain with caves and tunnels 614 public override void SetTerrain(float[] heightMap) {
572 // For the moment, it's flat and convex 615 TerrainManager.SetTerrain(heightMap);
573 public float GetTerrainHeightAtXYZ(Vector3 loc)
574 {
575 return GetTerrainHeightAtXY(loc.X, loc.Y);
576 }
577
578 public float GetTerrainHeightAtXY(float tX, float tY)
579 {
580 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
581 return 30;
582 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
583 } 616 }
584 617
585 public override void SetWaterLevel(float baseheight) 618 public override void SetWaterLevel(float baseheight)
@@ -595,35 +628,29 @@ public class BSScene : PhysicsScene, IPhysicsParameters
595 public override void DeleteTerrain() 628 public override void DeleteTerrain()
596 { 629 {
597 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 630 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
631 }
632
633 // Although no one seems to check this, I do support combining.
634 public override bool SupportsCombining()
635 {
636 return TerrainManager.SupportsCombining();
598 } 637 }
599 638 // This call says I am a child to region zero in a mega-region. 'pScene' is that
600 public override void Dispose() 639 // of region zero, 'offset' is my offset from regions zero's origin, and
601 { 640 // 'extents' is the largest XY that is handled in my region.
602 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 641 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
603 642 {
604 // make sure no stepping happens while we're deleting stuff 643 TerrainManager.Combine(pScene, offset, extents);
605 m_initialized = false; 644 }
606 645
607 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) 646 // Unhook all the combining that I know about.
608 { 647 public override void UnCombine(PhysicsScene pScene)
609 kvp.Value.Destroy(); 648 {
610 } 649 TerrainManager.UnCombine(pScene);
611 PhysObjects.Clear();
612
613 // Now that the prims are all cleaned up, there should be no constraints left
614 if (m_constraintCollection != null)
615 {
616 m_constraintCollection.Dispose();
617 m_constraintCollection = null;
618 }
619
620 // Anything left in the unmanaged code should be cleaned out
621 BulletSimAPI.Shutdown(WorldID);
622
623 // Not logging any more
624 PhysicsLogging.Close();
625 } 650 }
626 651
652 #endregion // Terrain
653
627 public override Dictionary<uint, float> GetTopColliders() 654 public override Dictionary<uint, float> GetTopColliders()
628 { 655 {
629 return new Dictionary<uint, float>(); 656 return new Dictionary<uint, float>();
@@ -833,14 +860,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
833 // no locking because only called when physics engine is not busy 860 // no locking because only called when physics engine is not busy
834 private void ProcessVehicles(float timeStep) 861 private void ProcessVehicles(float timeStep)
835 { 862 {
836 foreach (BSPrim prim in m_vehicles) 863 foreach (BSPhysObject pobj in m_vehicles)
837 { 864 {
838 prim.StepVehicle(timeStep); 865 pobj.StepVehicle(timeStep);
839 } 866 }
840 } 867 }
841 #endregion Vehicles 868 #endregion Vehicles
842 869
843 #region Parameters 870 #region INI and command line parameter processing
844 871
845 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 872 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
846 delegate float ParamGet(BSScene scene); 873 delegate float ParamGet(BSScene scene);
@@ -943,9 +970,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
943 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 970 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
944 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 971 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
945 10000.01f, 972 10000.01f,
946 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 973 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
947 (s) => { return (float)s.m_maximumObjectMass; }, 974 (s) => { return (float)s.MaximumObjectMass; },
948 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 975 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
949 976
950 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 977 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
951 2200f, 978 2200f,
@@ -1207,6 +1234,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1207 1234
1208 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1235 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1209 1236
1237 // This creates an array in the correct format for returning the list of
1238 // parameters. This is used by the 'list' option of the 'physics' command.
1210 private void BuildParameterTable() 1239 private void BuildParameterTable()
1211 { 1240 {
1212 if (SettableParameters.Length < ParameterDefinitions.Length) 1241 if (SettableParameters.Length < ParameterDefinitions.Length)
@@ -1283,7 +1312,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1283 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1312 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1284 foreach (uint lID in objectIDs) 1313 foreach (uint lID in objectIDs)
1285 { 1314 {
1286 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); 1315 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1287 } 1316 }
1288 }); 1317 });
1289 break; 1318 break;
@@ -1301,7 +1330,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1301 string xparm = parm.ToLower(); 1330 string xparm = parm.ToLower();
1302 float xval = val; 1331 float xval = val;
1303 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1332 TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
1304 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1333 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
1305 }); 1334 });
1306 } 1335 }
1307 1336
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
new file mode 100755
index 0000000..28c1940
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,307 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public class BSTerrainManager
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
46
47 BSScene m_physicsScene;
48
49 private BulletBody m_groundPlane;
50
51 // If doing mega-regions, if we're region zero we will be managing multiple
52 // region terrains since region zero does the physics for the whole mega-region.
53 private Dictionary<Vector2, BulletBody> m_terrains;
54 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
55
56 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
57 // This is incremented before assigning to new region so it is the last ID allocated.
58 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
59 public uint HighestTerrainID { get {return m_terrainCount; } }
60
61 // If doing mega-regions, this holds our offset from region zero of
62 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
63 private Vector3 m_worldOffset = Vector3.Zero;
64 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
65 private PhysicsScene m_parentScene = null;
66
67 public BSTerrainManager(BSScene physicsScene)
68 {
69 m_physicsScene = physicsScene;
70 m_terrains = new Dictionary<Vector2,BulletBody>();
71 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
72 }
73
74 // Create the initial instance of terrain and the underlying ground plane.
75 // The objects are allocated in the unmanaged space and the pointers are tracked
76 // by the managed code.
77 // The terrains and the groundPlane are not added to the list of PhysObjects.
78 // This is called from the initialization routine so we presume it is
79 // safe to call Bullet in real time. We hope no one is moving around prim yet.
80 public void CreateInitialGroundPlaneAndTerrain()
81 {
82 // The ground plane is here to catch things that are trying to drop to negative infinity
83 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
84 BulletSimAPI.CreateGroundPlaneBody2(BSScene.GROUNDPLANE_ID, 1f, 0.4f));
85 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
86
87 Vector3 minTerrainCoords = new Vector3(0f, 0f, 24f);
88 Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, 25f);
89 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
90 float[] initialMap = new float[totalHeights];
91 for (int ii = 0; ii < totalHeights; ii++)
92 {
93 initialMap[ii] = 25f;
94 }
95 CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords);
96 }
97
98 public void ReleaseGroundPlaneAndTerrain()
99 {
100 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr))
101 {
102 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
103 }
104 m_groundPlane.Ptr = IntPtr.Zero;
105
106 foreach (KeyValuePair<Vector2, BulletBody> kvp in m_terrains)
107 {
108 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.Ptr))
109 {
110 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.Ptr);
111 BulletSimAPI.ReleaseHeightmapInfo2(m_heightMaps[kvp.Key].Ptr);
112 }
113 }
114 m_terrains.Clear();
115 m_heightMaps.Clear();
116 }
117
118 // Create a new terrain description. This is used for mega-regions where
119 // the children of region zero give region zero all of the terrain
120 // segments since region zero does all the physics for the mega-region.
121 // Call at taint time!!
122 public void CreateNewTerrainSegment(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
123 {
124 // The Z coordinates are recalculated to be the min and max height of the terrain
125 // itself. The caller may have passed us the real region extent.
126 float minZ = float.MaxValue;
127 float maxZ = float.MinValue;
128 int hSize = heightMap.Length;
129 for (int ii = 0; ii < hSize; ii++)
130 {
131 minZ = heightMap[ii] < minZ ? heightMap[ii] : minZ;
132 maxZ = heightMap[ii] > maxZ ? heightMap[ii] : maxZ;
133 }
134 minCoords.Z = minZ;
135 maxCoords.Z = maxZ;
136 // If the terrain is flat, make a difference so we get a good bounding box
137 if (minZ == maxZ)
138 minZ -= 0.2f;
139 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
140
141 // Create the heightmap data structure in the unmanaged space
142 BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(
143 BulletSimAPI.CreateHeightmap2(minCoords, maxCoords, heightMap), heightMap);
144 mapInfo.terrainRegionBase = terrainRegionBase;
145 mapInfo.maxRegionExtent = maxCoords;
146 mapInfo.minZ = minZ;
147 mapInfo.maxZ = maxZ;
148 mapInfo.sizeX = maxCoords.X - minCoords.X;
149 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
150
151 DetailLog("{0},BSScene.CreateNewTerrainSegment,call,minZ={1},maxZ={2},hMapPtr={3},minC={4},maxC={5}",
152 BSScene.DetailLogZero, minZ, maxZ, mapInfo.Ptr, minCoords, maxCoords);
153 // Create the terrain body from that heightmap
154 BulletBody terrainBody = new BulletBody(id, BulletSimAPI.CreateTerrainBody2(id, mapInfo.Ptr, 0.01f));
155
156 BulletSimAPI.SetFriction2(terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
157 BulletSimAPI.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
158 BulletSimAPI.SetRestitution2(terrainBody.Ptr, m_physicsScene.Params.terrainRestitution);
159 BulletSimAPI.SetCollisionFlags2(terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
160 BulletSimAPI.Activate2(terrainBody.Ptr, true);
161
162 // Add the new terrain to the dynamics world
163 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, terrainBody.Ptr);
164 BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, terrainBody.Ptr);
165
166
167 // Add the created terrain to the management set. If we are doing mega-regions,
168 // the terrains of our children will be added.
169 m_terrains.Add(terrainRegionBase, terrainBody);
170 m_heightMaps.Add(terrainRegionBase, mapInfo);
171 }
172
173 public void SetTerrain(float[] heightMap) {
174 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
175 {
176 // If doing the mega-prim stuff and we are the child of the zero region,
177 // the terrain is really added to our parent
178 if (m_parentScene is BSScene)
179 {
180 ((BSScene)m_parentScene).TerrainManager.SetTerrain(heightMap, m_worldOffset);
181 }
182 }
183 else
184 {
185 // if not doing the mega-prim thing, just change the terrain
186 SetTerrain(heightMap, m_worldOffset);
187 }
188 }
189
190 private void SetTerrain(float[] heightMap, Vector3 tOffset)
191 {
192 float minZ = float.MaxValue;
193 float maxZ = float.MinValue;
194
195 // Copy heightMap local and compute some statistics.
196 // Not really sure if we need to do this deep copy but, given
197 // the magic that happens to make the closure for taint
198 // below, I don't want there to be any problem with sharing
199 // locations of there are multiple calls to this routine
200 // within one tick.
201 int heightMapSize = heightMap.Length;
202 float[] localHeightMap = new float[heightMapSize];
203 for (int ii = 0; ii < heightMapSize; ii++)
204 {
205 float height = heightMap[ii];
206 if (height < minZ) minZ = height;
207 if (height > maxZ) maxZ = height;
208 localHeightMap[ii] = height;
209 }
210
211 Vector2 terrainRegionBase = new Vector2(tOffset.X, tOffset.Y);
212 BulletHeightMapInfo mapInfo;
213 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
214 {
215 // If this is terrain we know about, it's easy to update
216 mapInfo.heightMap = localHeightMap;
217 m_physicsScene.TaintedObject("BSScene.SetTerrain:UpdateExisting", delegate()
218 {
219 DetailLog("{0},SetTerrain:UpdateExisting,baseX={1},baseY={2},minZ={3},maxZ={4}",
220 BSScene.DetailLogZero, tOffset.X, tOffset.Y, minZ, maxZ);
221 BulletSimAPI.UpdateHeightMap2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.heightMap);
222 });
223 }
224 else
225 {
226 // Our mega-prim child is giving us a new terrain to add to the phys world
227 uint newTerrainID = ++m_terrainCount;
228
229 Vector3 minCoords = tOffset;
230 minCoords.Z = minZ;
231 Vector3 maxCoords = new Vector3(tOffset.X + Constants.RegionSize,
232 tOffset.Y + Constants.RegionSize,
233 maxZ);
234 m_physicsScene.TaintedObject("BSScene.SetTerrain:NewTerrain", delegate()
235 {
236 DetailLog("{0},SetTerrain:NewTerrain,baseX={1},baseY={2}", BSScene.DetailLogZero, tOffset.X, tOffset.Y);
237 CreateNewTerrainSegment(newTerrainID, heightMap, minCoords, maxCoords);
238 });
239 }
240 }
241
242 // Someday we will have complex terrain with caves and tunnels
243 // For the moment, it's flat and convex
244 public float GetTerrainHeightAtXYZ(Vector3 loc)
245 {
246 return GetTerrainHeightAtXY(loc.X, loc.Y);
247 }
248
249 // Given an X and Y, find the height of the terrain.
250 // Since we could be handling multiple terrains for a mega-region,
251 // the base of the region is calcuated assuming all regions are
252 // the same size and that is the default.
253 // Once the heightMapInfo is found, we have all the information to
254 // compute the offset into the array.
255 public float GetTerrainHeightAtXY(float tX, float tY)
256 {
257 float ret = 30f;
258
259 int offsetX = ((int)(tX / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
260 int offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
261 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
262
263 BulletHeightMapInfo mapInfo;
264 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
265 {
266 float regionX = tX - offsetX;
267 float regionY = tY - offsetY;
268 regionX = regionX > mapInfo.sizeX ? 0 : regionX;
269 regionY = regionY > mapInfo.sizeY ? 0 : regionY;
270 ret = mapInfo.heightMap[(int)(regionX * mapInfo.sizeX + regionY)];
271 }
272 else
273 {
274 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}",
275 LogHeader, tX, tY);
276 }
277 return ret;
278 }
279
280 // Although no one seems to check this, I do support combining.
281 public bool SupportsCombining()
282 {
283 return true;
284 }
285 // This call says I am a child to region zero in a mega-region. 'pScene' is that
286 // of region zero, 'offset' is my offset from regions zero's origin, and
287 // 'extents' is the largest XY that is handled in my region.
288 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
289 {
290 m_worldOffset = offset;
291 WorldExtents = new Vector2(extents.X, extents.Y);
292 m_parentScene = pScene;
293 }
294
295 // Unhook all the combining that I know about.
296 public void UnCombine(PhysicsScene pScene)
297 {
298 // Just like ODE, for the moment a NOP
299 }
300
301
302 private void DetailLog(string msg, params Object[] args)
303 {
304 m_physicsScene.PhysicsLogging.Write(msg, args);
305 }
306}
307}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index dab2420..3b319fb 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -33,6 +33,9 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin { 33namespace OpenSim.Region.Physics.BulletSPlugin {
34 34
35// Classes to allow some type checking for the API 35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
36public struct BulletSim 39public struct BulletSim
37{ 40{
38 public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } 41 public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; }
@@ -42,6 +45,7 @@ public struct BulletSim
42 public IntPtr Ptr; 45 public IntPtr Ptr;
43} 46}
44 47
48// An allocated Bullet btRigidBody
45public struct BulletBody 49public struct BulletBody
46{ 50{
47 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } 51 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
@@ -49,12 +53,35 @@ public struct BulletBody
49 public uint ID; 53 public uint ID;
50} 54}
51 55
56// An allocated Bullet btConstraint
52public struct BulletConstraint 57public struct BulletConstraint
53{ 58{
54 public BulletConstraint(IntPtr xx) { Ptr = xx; } 59 public BulletConstraint(IntPtr xx) { Ptr = xx; }
55 public IntPtr Ptr; 60 public IntPtr Ptr;
56} 61}
57 62
63// An allocated HeightMapThing which hold various heightmap info
64// Made a class rather than a struct so there would be only one
65// instance of this and C# will pass around pointers rather
66// than making copies.
67public class BulletHeightMapInfo
68{
69 public BulletHeightMapInfo(IntPtr xx, float[] hm) {
70 Ptr = xx;
71 heightMap = hm;
72 terrainRegionBase = new Vector2(0f, 0f);
73 maxRegionExtent = new Vector3(100f, 100f, 25f);
74 minZ = maxZ = 0f;
75 sizeX = sizeY = 256f;
76 }
77 public IntPtr Ptr;
78 public float[] heightMap;
79 public Vector2 terrainRegionBase;
80 public Vector3 maxRegionExtent;
81 public float sizeX, sizeY;
82 public float minZ, maxZ;
83}
84
58// =============================================================================== 85// ===============================================================================
59[StructLayout(LayoutKind.Sequential)] 86[StructLayout(LayoutKind.Sequential)]
60public struct ConvexHull 87public struct ConvexHull
@@ -231,6 +258,9 @@ public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
231 int maxUpdates, IntPtr updateArray); 258 int maxUpdates, IntPtr updateArray);
232 259
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 260[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
261public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
262
263[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 264public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
235 265
236[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 266[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -414,12 +444,23 @@ public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
414 444
415// ===================================================================================== 445// =====================================================================================
416[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 446[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
417public static extern IntPtr CreateGroundPlaneBody2(uint id, Vector3 center, float collisionMargin); 447public static extern IntPtr CreateGroundPlaneBody2(uint id, float height, float collisionMargin);
418 448
419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
420public static extern IntPtr CreateTerrainBody2(uint id, 450public static extern IntPtr CreateTerrainBody2(uint id,
421 Vector3 minCoords, Vector3 maxCoords, float collisionMargin, 451 IntPtr heightMapInfo,
422 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 452 float collisionMargin);
453
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern IntPtr CreateHeightmap2(Vector3 minCoords, Vector3 maxCoords,
456 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
457
458[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
459public static extern bool ReleaseHeightmapInfo2(IntPtr heightMapInfo);
460
461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
462public static extern void UpdateHeightMap2(IntPtr world, IntPtr heightMapInfo,
463 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
423 464
424// ===================================================================================== 465// =====================================================================================
425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -473,11 +514,16 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams
473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
474public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); 515public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
475 516
517// =====================================================================================
476[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 518[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
477public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); 519public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
478 520
479[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 521[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
480public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 522public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
523
524// =====================================================================================
525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
526public static extern void Activate2(IntPtr obj, bool forceActivation);
481 527
482[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
483public static extern Vector3 GetPosition2(IntPtr obj); 529public static extern Vector3 GetPosition2(IntPtr obj);
@@ -522,6 +568,9 @@ public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
522public static extern bool SetFriction2(IntPtr obj, float val); 568public static extern bool SetFriction2(IntPtr obj, float val);
523 569
524[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
571public static extern bool SetHitFraction2(IntPtr obj, float val);
572
573[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
525public static extern bool SetRestitution2(IntPtr obj, float val); 574public static extern bool SetRestitution2(IntPtr obj, float val);
526 575
527[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 576[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -564,7 +613,7 @@ public static extern bool SetMargin2(IntPtr obj, float val);
564public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); 613public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
565 614
566[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
567public static extern bool DestroyObject2(IntPtr world, uint id); 616public static extern bool DestroyObject2(IntPtr world, IntPtr obj);
568 617
569[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
570public static extern void DumpPhysicsStatistics2(IntPtr sim); 619public static extern void DumpPhysicsStatistics2(IntPtr sim);