aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs3
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs56
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs158
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs88
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs10
9 files changed, 270 insertions, 111 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index e208d3a..90c2d9c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -479,7 +479,7 @@ public sealed class BSCharacter : BSPhysObject
479 // The character is out of the known/simulated area. 479 // The character is out of the known/simulated area.
480 // Force the avatar position to be within known. ScenePresence will use the position 480 // Force the avatar position to be within known. ScenePresence will use the position
481 // plus the velocity to decide if the avatar is moving out of the region. 481 // plus the velocity to decide if the avatar is moving out of the region.
482 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); 482 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
483 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); 483 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
484 return true; 484 return true;
485 } 485 }
@@ -898,7 +898,7 @@ public sealed class BSCharacter : BSPhysObject
898 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 898 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
899 if (PositionSanityCheck(true)) 899 if (PositionSanityCheck(true))
900 { 900 {
901 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); 901 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
902 entprop.Position = _position; 902 entprop.Position = _position;
903 } 903 }
904 904
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5549984..65df741 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -321,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
321 } 321 }
322 } 322 }
323 323
324 internal void ProcessTypeChange(Vehicle pType) 324 public void ProcessTypeChange(Vehicle pType)
325 { 325 {
326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
327 // Set Defaults For Type 327 // Set Defaults For Type
@@ -1301,14 +1301,52 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. 1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1302 public void ComputeAngularVerticalAttraction() 1302 public void ComputeAngularVerticalAttraction()
1303 { 1303 {
1304
1304 // If vertical attaction timescale is reasonable 1305 // If vertical attaction timescale is reasonable
1305 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1306 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1306 { 1307 {
1308 // Possible solution derived from a discussion at:
1309 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1310
1311 // Create a rotation that is only the vehicle's rotation around Z
1312 Vector3 currentEuler = Vector3.Zero;
1313 VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
1314 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
1315
1316 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1317 Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1318 // Compute the angle between those to vectors.
1319 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1320 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1321
1322 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1323 // TODO: add 'efficiency'.
1324 differenceAngle /= m_verticalAttractionTimescale;
1325
1326 // Create the quaterian representing the correction angle
1327 Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
1328
1329 // Turn that quaternion into Euler values to make it into velocities to apply.
1330 Vector3 vertContributionV = Vector3.Zero;
1331 correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
1332 vertContributionV *= -1f;
1333
1334 VehicleRotationalVelocity += vertContributionV;
1335
1336 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1337 Prim.LocalID,
1338 differenceAxis,
1339 differenceAngle,
1340 correctionRotation,
1341 vertContributionV);
1342
1343 // ===================================================================
1344 /*
1307 Vector3 vertContributionV = Vector3.Zero; 1345 Vector3 vertContributionV = Vector3.Zero;
1308 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG 1346 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1309 1347
1310 // Take a vector pointing up and convert it from world to vehicle relative coords. 1348 // Take a vector pointing up and convert it from world to vehicle relative coords.
1311 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; 1349 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1312 1350
1313 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) 1351 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1314 // is now: 1352 // is now:
@@ -1334,13 +1372,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1334 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. 1372 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1335 // Correction happens over a number of seconds. 1373 // Correction happens over a number of seconds.
1336 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG 1374 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1375
1376 // The correction happens over the user's time period
1337 vertContributionV /= m_verticalAttractionTimescale; 1377 vertContributionV /= m_verticalAttractionTimescale;
1338 1378
1339 VehicleRotationalVelocity += vertContributionV; 1379 // Rotate the vehicle rotation to the world coordinates.
1380 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1340 1381
1341 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", 1382 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1342 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, 1383 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1343 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); 1384 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1385 */
1344 } 1386 }
1345 } 1387 }
1346 1388
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
index 92d62ff..ee77d6e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -180,11 +180,14 @@ public static class BSMaterials
180 // Use reflection to set the value in the attribute structure. 180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val) 181 private static void SetAttributeValue(int matType, string attribName, float val)
182 { 182 {
183 // Get the current attribute values for this material
183 MaterialAttributes thisAttrib = Attributes[matType]; 184 MaterialAttributes thisAttrib = Attributes[matType];
185 // Find the field for the passed attribute name (eg, find field named 'friction')
184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); 186 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
185 if (fieldInfo != null) 187 if (fieldInfo != null)
186 { 188 {
187 fieldInfo.SetValue(thisAttrib, val); 189 fieldInfo.SetValue(thisAttrib, val);
190 // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
188 Attributes[matType] = thisAttrib; 191 Attributes[matType] = thisAttrib;
189 } 192 }
190 } 193 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 4d89a88..385ed9e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -142,6 +142,14 @@ public static class BSParam
142 public static float VehicleAngularBankingTimescaleFudge { get; private set; } 142 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
143 public static bool VehicleDebuggingEnabled { get; private set; } 143 public static bool VehicleDebuggingEnabled { get; private set; }
144 144
145 // Convex Hulls
146 public static int CSHullMaxDepthSplit { get; private set; }
147 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
148 public static float CSHullConcavityThresholdPercent { get; private set; }
149 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
150 public static int CSHullMaxVertices { get; private set; }
151 public static float CSHullMaxSkinWidth { get; private set; }
152
145 // Linkset implementation parameters 153 // Linkset implementation parameters
146 public static float LinksetImplementation { get; private set; } 154 public static float LinksetImplementation { get; private set; }
147 public static bool LinkConstraintUseFrameOffset { get; private set; } 155 public static bool LinkConstraintUseFrameOffset { get; private set; }
@@ -195,10 +203,10 @@ public static class BSParam
195 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj); 203 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
196 public sealed class ParameterDefn<T> : ParameterDefnBase 204 public sealed class ParameterDefn<T> : ParameterDefnBase
197 { 205 {
198 T defaultValue; 206 private T defaultValue;
199 PSetValue<T> setter; 207 private PSetValue<T> setter;
200 PGetValue<T> getter; 208 private PGetValue<T> getter;
201 PSetOnObject<T> objectSet; 209 private PSetOnObject<T> objectSet;
202 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter) 210 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
203 : base(pName, pDesc) 211 : base(pName, pDesc)
204 { 212 {
@@ -215,13 +223,23 @@ public static class BSParam
215 getter = pGetter; 223 getter = pGetter;
216 objectSet = pObjSetter; 224 objectSet = pObjSetter;
217 } 225 }
226 /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work
227 public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc)
228 : base(pName, pDesc)
229 {
230 defaultValue = pDefault;
231 setter = (s, v) => { loc = v; };
232 getter = (s) => { return loc; };
233 objectSet = null;
234 }
235 */
218 public override void AssignDefault(BSScene s) 236 public override void AssignDefault(BSScene s)
219 { 237 {
220 setter(s, defaultValue); 238 setter(s, defaultValue);
221 } 239 }
222 public override string GetValue(BSScene s) 240 public override string GetValue(BSScene s)
223 { 241 {
224 return String.Format("{0}", getter(s)); 242 return getter(s).ToString();
225 } 243 }
226 public override void SetValue(BSScene s, string valAsString) 244 public override void SetValue(BSScene s, string valAsString)
227 { 245 {
@@ -244,6 +262,7 @@ public static class BSParam
244 try 262 try
245 { 263 {
246 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); 264 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
265 // Store the parsed value
247 setter(s, setValue); 266 setter(s, setValue);
248 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); 267 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
249 } 268 }
@@ -463,7 +482,7 @@ public static class BSParam
463 (s) => { return TerrainImplementation; }, 482 (s) => { return TerrainImplementation; },
464 (s,v) => { TerrainImplementation = v; } ), 483 (s,v) => { TerrainImplementation = v; } ),
465 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , 484 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
466 3, 485 2,
467 (s) => { return TerrainMeshMagnification; }, 486 (s) => { return TerrainMeshMagnification; },
468 (s,v) => { TerrainMeshMagnification = v; } ), 487 (s,v) => { TerrainMeshMagnification = v; } ),
469 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , 488 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
@@ -623,6 +642,31 @@ public static class BSParam
623 (s) => { return GlobalContactBreakingThreshold; }, 642 (s) => { return GlobalContactBreakingThreshold; },
624 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), 643 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
625 644
645 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
646 7,
647 (s) => { return CSHullMaxDepthSplit; },
648 (s,v) => { CSHullMaxDepthSplit = v; } ),
649 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
650 2,
651 (s) => { return CSHullMaxDepthSplitForSimpleShapes; },
652 (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
653 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
654 5f,
655 (s) => { return CSHullConcavityThresholdPercent; },
656 (s,v) => { CSHullConcavityThresholdPercent = v; } ),
657 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
658 5f,
659 (s) => { return CSHullVolumeConservationThresholdPercent; },
660 (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
661 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
662 32,
663 (s) => { return CSHullMaxVertices; },
664 (s,v) => { CSHullMaxVertices = v; } ),
665 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
666 0,
667 (s) => { return CSHullMaxSkinWidth; },
668 (s,v) => { CSHullMaxSkinWidth = v; } ),
669
626 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", 670 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
627 (float)BSLinkset.LinksetImplementation.Compound, 671 (float)BSLinkset.LinksetImplementation.Compound,
628 (s) => { return LinksetImplementation; }, 672 (s) => { return LinksetImplementation; },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f953c1e..6bb88c7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -86,7 +86,7 @@ public abstract class BSPhysObject : PhysicsActor
86 PhysBody = new BulletBody(localID); 86 PhysBody = new BulletBody(localID);
87 PhysShape = new BulletShape(); 87 PhysShape = new BulletShape();
88 88
89 LastAssetBuildFailed = false; 89 PrimAssetState = PrimAssetCondition.Unknown;
90 90
91 // Default material type. Also sets Friction, Restitution and Density. 91 // Default material type. Also sets Friction, Restitution and Density.
92 SetMaterial((int)MaterialAttributes.Material.Wood); 92 SetMaterial((int)MaterialAttributes.Material.Wood);
@@ -133,9 +133,13 @@ public abstract class BSPhysObject : PhysicsActor
133 // Reference to the physical shape (btCollisionShape) of this object 133 // Reference to the physical shape (btCollisionShape) of this object
134 public BulletShape PhysShape; 134 public BulletShape PhysShape;
135 135
136 // 'true' if the mesh's underlying asset failed to build. 136 // The physical representation of the prim might require an asset fetch.
137 // This will keep us from looping after the first time the build failed. 137 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
138 public bool LastAssetBuildFailed { get; set; } 138 public enum PrimAssetCondition
139 {
140 Unknown, Waiting, Failed, Fetched
141 }
142 public PrimAssetCondition PrimAssetState { get; set; }
139 143
140 // The objects base shape information. Null if not a prim type shape. 144 // The objects base shape information. Null if not a prim type shape.
141 public PrimitiveBaseShape BaseShape { get; protected set; } 145 public PrimitiveBaseShape BaseShape { get; protected set; }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2cbbe9a..6a5461a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -155,7 +155,7 @@ public class BSPrim : BSPhysObject
155 public override PrimitiveBaseShape Shape { 155 public override PrimitiveBaseShape Shape {
156 set { 156 set {
157 BaseShape = value; 157 BaseShape = value;
158 LastAssetBuildFailed = false; 158 PrimAssetState = PrimAssetCondition.Unknown;
159 ForceBodyShapeRebuild(false); 159 ForceBodyShapeRebuild(false);
160 } 160 }
161 } 161 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 05c147d..220fbbc 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -447,17 +447,10 @@ public sealed class BSShapeCollection : IDisposable
447 447
448 // If the prim attributes are simple, this could be a simple Bullet native shape 448 // If the prim attributes are simple, this could be a simple Bullet native shape
449 if (!haveShape 449 if (!haveShape
450 && nativeShapePossible
450 && pbs != null 451 && pbs != null
451 && !pbs.SculptEntry 452 && !pbs.SculptEntry
452 && nativeShapePossible 453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
454 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
455 && pbs.ProfileHollow == 0
456 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
457 && pbs.PathBegin == 0 && pbs.PathEnd == 0
458 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
459 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
460 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
461 { 454 {
462 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
463 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
@@ -508,6 +501,18 @@ public sealed class BSShapeCollection : IDisposable
508 return ret; 501 return ret;
509 } 502 }
510 503
504 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0
509 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
510 && pbs.PathBegin == 0 && pbs.PathEnd == 0
511 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
512 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
513 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
514 }
515
511 // return 'true' if the prim's shape was changed. 516 // return 'true' if the prim's shape was changed.
512 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
513 { 518 {
@@ -518,7 +523,7 @@ public sealed class BSShapeCollection : IDisposable
518 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
519 { 524 {
520 // Update prim.BSShape to reference a hull of this shape. 525 // Update prim.BSShape to reference a hull of this shape.
521 ret = GetReferenceToHull(prim,shapeCallback); 526 ret = GetReferenceToHull(prim, shapeCallback);
522 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
523 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
524 } 529 }
@@ -699,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
699 704
700 // See that hull shape exists in the physical world and update prim.BSShape. 705 // See that hull shape exists in the physical world and update prim.BSShape.
701 // We could be creating the hull because scale changed or whatever. 706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
702 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
703 { 709 {
704 BulletShape newShape; 710 BulletShape newShape;
@@ -717,6 +723,7 @@ public sealed class BSShapeCollection : IDisposable
717 DereferenceShape(prim.PhysShape, shapeCallback); 723 DereferenceShape(prim.PhysShape, shapeCallback);
718 724
719 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); 725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
720 newShape = VerifyMeshCreated(newShape, prim); 727 newShape = VerifyMeshCreated(newShape, prim);
721 728
722 ReferenceShape(newShape); 729 ReferenceShape(newShape);
@@ -735,13 +742,13 @@ public sealed class BSShapeCollection : IDisposable
735 HullDesc hullDesc; 742 HullDesc hullDesc;
736 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
737 { 744 {
738 // If the hull shape already is created, just use it. 745 // If the hull shape already has been created, just use the one shared instance.
739 newShape = hullDesc.shape.Clone(); 746 newShape = hullDesc.shape.Clone();
740 } 747 }
741 else 748 else
742 { 749 {
743 // Build a new hull in the physical world 750 // Build a new hull in the physical world.
744 // Pass true for physicalness as this creates some sort of bounding box which we don't need 751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
745 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); 752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
746 if (meshData != null) 753 if (meshData != null)
747 { 754 {
@@ -761,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
761 convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); 768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
762 } 769 }
763 770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
764 // setup and do convex hull conversion 783 // setup and do convex hull conversion
765 m_hulls = new List<ConvexResult>(); 784 m_hulls = new List<ConvexResult>();
766 DecompDesc dcomp = new DecompDesc(); 785 DecompDesc dcomp = new DecompDesc();
767 dcomp.mIndices = convIndices; 786 dcomp.mIndices = convIndices;
768 dcomp.mVertices = convVertices; 787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
769 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); 793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
770 // create the hull into the _hulls variable 794 // create the hull into the _hulls variable
771 convexBuilder.process(dcomp); 795 convexBuilder.process(dcomp);
772 796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
773 // Convert the vertices and indices for passing to unmanaged. 800 // Convert the vertices and indices for passing to unmanaged.
774 // The hull information is passed as a large floating point array. 801 // The hull information is passed as a large floating point array.
775 // The format is: 802 // The format is:
@@ -904,58 +931,79 @@ public sealed class BSShapeCollection : IDisposable
904 if (newShape.HasPhysicalShape) 931 if (newShape.HasPhysicalShape)
905 return newShape; 932 return newShape;
906 933
907 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 934 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
908 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) 935 // fetched but we end up here again, the meshing of the asset must have failed.
936 // Prevent trying to keep fetching the mesh by declaring failure.
937 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
938 {
939 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
940 PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
941 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
942 }
943 else
909 { 944 {
910 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed); 945 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
911 // This will prevent looping through this code as we keep trying to get the failed shape 946 if (prim.BaseShape.SculptEntry
912 prim.LastAssetBuildFailed = true; 947 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
948 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
949 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
950 )
951 {
952 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
953 // Multiple requestors will know we're waiting for this asset
954 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
913 955
914 BSPhysObject xprim = prim; 956 BSPhysObject xprim = prim;
915 Util.FireAndForget(delegate 957 Util.FireAndForget(delegate
916 {
917 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
918 if (assetProvider != null)
919 { 958 {
920 BSPhysObject yprim = xprim; // probably not necessary, but, just in case. 959 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
921 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) 960 if (assetProvider != null)
922 { 961 {
923 bool assetFound = false; // DEBUG DEBUG 962 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
924 string mismatchIDs = String.Empty; // DEBUG DEBUG 963 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
925 if (asset != null && yprim.BaseShape.SculptEntry)
926 { 964 {
927 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) 965 bool assetFound = false;
966 string mismatchIDs = String.Empty; // DEBUG DEBUG
967 if (asset != null && yprim.BaseShape.SculptEntry)
928 { 968 {
929 yprim.BaseShape.SculptData = asset.Data; 969 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
930 // This will cause the prim to see that the filler shape is not the right 970 {
931 // one and try again to build the object. 971 yprim.BaseShape.SculptData = asset.Data;
932 // No race condition with the normal shape setting since the rebuild is at taint time. 972 // This will cause the prim to see that the filler shape is not the right
933 yprim.ForceBodyShapeRebuild(false /* inTaintTime */); 973 // one and try again to build the object.
934 assetFound = true; 974 // No race condition with the normal shape setting since the rebuild is at taint time.
975 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
976 assetFound = true;
977 }
978 else
979 {
980 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
981 }
935 } 982 }
983 if (assetFound)
984 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
936 else 985 else
937 { 986 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
938 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; 987 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
939 } 988 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
940 }
941 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
942 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
943 989
944 }); 990 });
945 } 991 }
946 else 992 else
947 { 993 {
948 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", 994 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
949 LogHeader, PhysicsScene.Name); 995 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
950 } 996 LogHeader, PhysicsScene.Name);
951 }); 997 }
952 } 998 });
953 else 999 }
954 { 1000 else
955 if (prim.LastAssetBuildFailed)
956 { 1001 {
957 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", 1002 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
958 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); 1003 {
1004 PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1005 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1006 }
959 } 1007 }
960 } 1008 }
961 1009
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index a60946d..b2fb835 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -132,6 +132,7 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
134 { 134 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
135 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
136 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 137 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 138 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
@@ -145,14 +146,18 @@ public sealed class BSTerrainManager : IDisposable
145 m_groundPlane.collisionType = CollisionType.Groundplane; 146 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_groundPlane.ApplyCollisionMask(PhysicsScene); 147 m_groundPlane.ApplyCollisionMask(PhysicsScene);
147 148
148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
150 m_terrains.Add(Vector3.Zero, initialTerrain); 150 lock (m_terrains)
151 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
153 m_terrains.Add(Vector3.Zero, initialTerrain);
154 }
151 } 155 }
152 156
153 // Release all the terrain structures we might have allocated 157 // Release all the terrain structures we might have allocated
154 public void ReleaseGroundPlaneAndTerrain() 158 public void ReleaseGroundPlaneAndTerrain()
155 { 159 {
160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
156 if (m_groundPlane.HasPhysicalBody) 161 if (m_groundPlane.HasPhysicalBody)
157 { 162 {
158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 163 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
@@ -193,11 +198,16 @@ public sealed class BSTerrainManager : IDisposable
193 // the terrain is added to our parent 198 // the terrain is added to our parent
194 if (MegaRegionParentPhysicsScene is BSScene) 199 if (MegaRegionParentPhysicsScene is BSScene)
195 { 200 {
196 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 201 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
197 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 202 // This looks really odd but this region is passing its terrain to its mega-region root region
198 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 203 // and the creation of the terrain must happen on the root region's taint thread and not
199 BSScene.CHILDTERRAIN_ID, localHeightMap, 204 // my taint thread.
200 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 205 ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate()
206 {
207 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
208 BSScene.CHILDTERRAIN_ID, localHeightMap,
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
210 });
201 } 211 }
202 } 212 }
203 else 213 else
@@ -206,16 +216,16 @@ public sealed class BSTerrainManager : IDisposable
206 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 216 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
207 217
208 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 218 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 219 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
210 } 220 }
211 }); 221 });
212 } 222 }
213 223
214 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 224 // If called for terrain has has not been previously allocated, a new terrain will be built
215 // based on the passed information. The 'id' should be either the terrain id or 225 // based on the passed information. The 'id' should be either the terrain id or
216 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 226 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
217 // The latter feature is for creating child terrains for mega-regions. 227 // The latter feature is for creating child terrains for mega-regions.
218 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 228 // If there is an existing terrain body, a new
219 // terrain shape is created and added to the body. 229 // terrain shape is created and added to the body.
220 // This call is most often used to update the heightMap and parameters of the terrain. 230 // This call is most often used to update the heightMap and parameters of the terrain.
221 // (The above does suggest that some simplification/refactoring is in order.) 231 // (The above does suggest that some simplification/refactoring is in order.)
@@ -223,8 +233,8 @@ public sealed class BSTerrainManager : IDisposable
223 private void UpdateTerrain(uint id, float[] heightMap, 233 private void UpdateTerrain(uint id, float[] heightMap,
224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 234 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
225 { 235 {
226 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 236 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}",
227 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 237 BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime);
228 238
229 // Find high and low points of passed heightmap. 239 // Find high and low points of passed heightmap.
230 // The min and max passed in is usually the area objects can be in (maximum 240 // The min and max passed in is usually the area objects can be in (maximum
@@ -253,7 +263,7 @@ public sealed class BSTerrainManager : IDisposable
253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) 263 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
254 { 264 {
255 // There is already a terrain in this spot. Free the old and build the new. 265 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 266 DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); 267 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
258 268
259 // Remove old terrain from the collection 269 // Remove old terrain from the collection
@@ -292,7 +302,7 @@ public sealed class BSTerrainManager : IDisposable
292 if (newTerrainID >= BSScene.CHILDTERRAIN_ID) 302 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
293 newTerrainID = ++m_terrainCount; 303 newTerrainID = ++m_terrainCount;
294 304
295 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 305 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
296 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 306 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
297 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 307 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
298 m_terrains.Add(terrainRegionBase, newTerrainPhys); 308 m_terrains.Add(terrainRegionBase, newTerrainPhys);
@@ -343,37 +353,35 @@ public sealed class BSTerrainManager : IDisposable
343 { 353 {
344 Vector3 ret = pPos; 354 Vector3 ret = pPos;
345 355
356 // First, base addresses are never negative so correct for that possible problem.
357 if (ret.X < 0f || ret.Y < 0f)
358 {
359 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
360 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
361 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
362 BSScene.DetailLogZero, pPos, ret);
363 }
364
346 // Can't do this function if we don't know about any terrain. 365 // Can't do this function if we don't know about any terrain.
347 if (m_terrains.Count == 0) 366 if (m_terrains.Count == 0)
348 return ret; 367 return ret;
349 368
350 int loopPrevention = 5; 369 int loopPrevention = 10;
351 Vector3 terrainBaseXYZ; 370 Vector3 terrainBaseXYZ;
352 BSTerrainPhys physTerrain; 371 BSTerrainPhys physTerrain;
353 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) 372 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
354 { 373 {
355 // The passed position is not within a known terrain area. 374 // The passed position is not within a known terrain area.
375 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
356 376
357 // First, base addresses are never negative so correct for that possible problem. 377 // Must be off the top of a region. Find an adjacent region to move into.
358 if (ret.X < 0f || ret.Y < 0f) 378 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
359 { 379
360 if (ret.X < 0f) 380 ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X));
361 ret.X = 0f; 381 ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y));
362 if (ret.Y < 0f) 382 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
363 ret.Y = 0f; 383 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
364 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
365 BSScene.DetailLogZero, pPos, ret);
366 }
367 else
368 {
369 // Must be off the top of a region. Find an adjacent region to move into.
370 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
371 384
372 ret.X = Math.Min(ret.X, adjacentTerrainBase.X + DefaultRegionSize.X);
373 ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + DefaultRegionSize.Y);
374 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
375 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
376 }
377 if (loopPrevention-- < 0f) 385 if (loopPrevention-- < 0f)
378 { 386 {
379 // The 'while' is a little dangerous so this prevents looping forever if the 387 // The 'while' is a little dangerous so this prevents looping forever if the
@@ -383,6 +391,7 @@ public sealed class BSTerrainManager : IDisposable
383 break; 391 break;
384 } 392 }
385 } 393 }
394
386 return ret; 395 return ret;
387 } 396 }
388 397
@@ -479,11 +488,20 @@ public sealed class BSTerrainManager : IDisposable
479 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) 488 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
480 { 489 {
481 Vector3 ret = pTerrainBase; 490 Vector3 ret = pTerrainBase;
491
492 // Can't do this function if we don't know about any terrain.
493 if (m_terrains.Count == 0)
494 return ret;
495
496 // Just some sanity
497 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
498 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
482 ret.Z = 0f; 499 ret.Z = 0f;
500
483 lock (m_terrains) 501 lock (m_terrains)
484 { 502 {
485 // Once down to the <0,0> region, we have to be done. 503 // Once down to the <0,0> region, we have to be done.
486 while (ret.X > 0f && ret.Y > 0f) 504 while (ret.X > 0f || ret.Y > 0f)
487 { 505 {
488 if (ret.X > 0f) 506 if (ret.X > 0f)
489 { 507 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index a9cd8a1..2ce1513 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -98,20 +98,20 @@ public sealed class BSTerrainMesh : BSTerrainPhys
98 if (!meshCreationSuccess) 98 if (!meshCreationSuccess)
99 { 99 {
100 // DISASTER!! 100 // DISASTER!!
101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); 101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
102 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); 102 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
103 // Something is very messed up and a crash is in our future. 103 // Something is very messed up and a crash is in our future.
104 return; 104 return;
105 } 105 }
106 106
107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", 107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
108 ID, indicesCount, indices.Length, verticesCount, vertices.Length); 108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
109 109
110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); 110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape) 111 if (!m_terrainShape.HasPhysicalShape)
112 { 112 {
113 // DISASTER!! 113 // DISASTER!!
114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); 115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
116 // Something is very messed up and a crash is in our future. 116 // Something is very messed up and a crash is in our future.
117 return; 117 return;
@@ -151,7 +151,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
151 151
152 if (BSParam.UseSingleSidedMeshes) 152 if (BSParam.UseSingleSidedMeshes)
153 { 153 {
154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial", id); 154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); 155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 } 156 }
157 157