diff options
Diffstat (limited to '')
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 | ||