diff options
author | Melanie | 2012-11-22 03:17:33 +0000 |
---|---|---|
committer | Melanie | 2012-11-22 03:17:33 +0000 |
commit | c4c612175271d146f4afe133cdb42ca430df445b (patch) | |
tree | 3b49ec8e0d8e2cfe2c514b620f34d941bfba5f3e /OpenSim | |
parent | Merge branch 'master' into careminster (diff) | |
parent | If an asset POST does not contain well-formed XML, return a 400 (Bad Request)... (diff) | |
download | opensim-SC-c4c612175271d146f4afe133cdb42ca430df445b.zip opensim-SC-c4c612175271d146f4afe133cdb42ca430df445b.tar.gz opensim-SC-c4c612175271d146f4afe133cdb42ca430df445b.tar.bz2 opensim-SC-c4c612175271d146f4afe133cdb42ca430df445b.tar.xz |
Merge branch 'master' into careminster
Diffstat (limited to 'OpenSim')
14 files changed, 835 insertions, 324 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 3c48dcc..e2aa41e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -82,7 +82,13 @@ public sealed class BSCharacter : BSPhysObject | |||
82 | { | 82 | { |
83 | _physicsActorType = (int)ActorTypes.Agent; | 83 | _physicsActorType = (int)ActorTypes.Agent; |
84 | _position = pos; | 84 | _position = pos; |
85 | |||
86 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
87 | // replace with the default values. | ||
85 | _size = size; | 88 | _size = size; |
89 | if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; | ||
90 | if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; | ||
91 | |||
86 | _flying = isFlying; | 92 | _flying = isFlying; |
87 | _orientation = OMV.Quaternion.Identity; | 93 | _orientation = OMV.Quaternion.Identity; |
88 | _velocity = OMV.Vector3.Zero; | 94 | _velocity = OMV.Vector3.Zero; |
@@ -175,8 +181,7 @@ public sealed class BSCharacter : BSPhysObject | |||
175 | get | 181 | get |
176 | { | 182 | { |
177 | // Avatar capsule size is kept in the scale parameter. | 183 | // Avatar capsule size is kept in the scale parameter. |
178 | // return _size; | 184 | return _size; |
179 | return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z); | ||
180 | } | 185 | } |
181 | 186 | ||
182 | set { | 187 | set { |
@@ -184,8 +189,8 @@ public sealed class BSCharacter : BSPhysObject | |||
184 | _size = value; | 189 | _size = value; |
185 | ComputeAvatarScale(_size); | 190 | ComputeAvatarScale(_size); |
186 | ComputeAvatarVolumeAndMass(); | 191 | ComputeAvatarVolumeAndMass(); |
187 | DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", | 192 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
188 | LocalID, Scale, _avatarDensity, _avatarVolume, RawMass); | 193 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); |
189 | 194 | ||
190 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 195 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
191 | { | 196 | { |
@@ -203,9 +208,9 @@ public sealed class BSCharacter : BSPhysObject | |||
203 | set { BaseShape = value; } | 208 | set { BaseShape = value; } |
204 | } | 209 | } |
205 | // I want the physics engine to make an avatar capsule | 210 | // I want the physics engine to make an avatar capsule |
206 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape | 211 | public override PhysicsShapeType PreferredPhysicalShape |
207 | { | 212 | { |
208 | get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; } | 213 | get {return PhysicsShapeType.SHAPE_CAPSULE; } |
209 | } | 214 | } |
210 | 215 | ||
211 | public override bool Grabbed { | 216 | public override bool Grabbed { |
@@ -614,13 +619,19 @@ public sealed class BSCharacter : BSPhysObject | |||
614 | // The 'size' given by the simulator is the mid-point of the avatar | 619 | // The 'size' given by the simulator is the mid-point of the avatar |
615 | // and X and Y are unspecified. | 620 | // and X and Y are unspecified. |
616 | 621 | ||
617 | OMV.Vector3 newScale = OMV.Vector3.Zero; | 622 | OMV.Vector3 newScale = size; |
618 | newScale.X = PhysicsScene.Params.avatarCapsuleRadius; | 623 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; |
619 | newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; | 624 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; |
620 | 625 | ||
621 | // From the total height, remove the capsule half spheres that are at each end | 626 | // From the total height, remove the capsule half spheres that are at each end |
622 | newScale.Z = size.Z - (newScale.X + newScale.Y); | 627 | // The 1.15f came from ODE. Not sure what this factors in. |
623 | Scale = newScale; | 628 | // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); |
629 | |||
630 | // The total scale height is the central cylindar plus the caps on the two ends. | ||
631 | newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); | ||
632 | |||
633 | // Convert diameters to radii and height to half height -- the way Bullet expects it. | ||
634 | Scale = newScale / 2f; | ||
624 | } | 635 | } |
625 | 636 | ||
626 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 637 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 436e043..4ee047b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -82,9 +82,9 @@ public abstract class BSLinkset | |||
82 | 82 | ||
83 | // Some linksets have a preferred physical shape. | 83 | // Some linksets have a preferred physical shape. |
84 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | 84 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. |
85 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 85 | public virtual PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
86 | { | 86 | { |
87 | return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | 87 | return PhysicsShapeType.SHAPE_UNKNOWN; |
88 | } | 88 | } |
89 | 89 | ||
90 | // Linksets move around the children so the linkset might need to compute the child position | 90 | // Linksets move around the children so the linkset might need to compute the child position |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 3238c85..cb37840 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -42,12 +42,12 @@ public sealed class BSLinksetCompound : BSLinkset | |||
42 | } | 42 | } |
43 | 43 | ||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 44 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 45 | public override PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
46 | { | 46 | { |
47 | ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | 47 | PhysicsShapeType ret = PhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 48 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 49 | { |
50 | ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | 50 | ret = PhysicsShapeType.SHAPE_COMPOUND; |
51 | } | 51 | } |
52 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | 52 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); |
53 | return ret; | 53 | return ret; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 991e5b1..e68b167 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -94,9 +94,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
94 | public PrimitiveBaseShape BaseShape { get; protected set; } | 94 | public PrimitiveBaseShape BaseShape { get; protected set; } |
95 | // Some types of objects have preferred physical representations. | 95 | // Some types of objects have preferred physical representations. |
96 | // Returns SHAPE_UNKNOWN if there is no preference. | 96 | // Returns SHAPE_UNKNOWN if there is no preference. |
97 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape | 97 | public virtual PhysicsShapeType PreferredPhysicalShape |
98 | { | 98 | { |
99 | get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; } | 99 | get { return PhysicsShapeType.SHAPE_UNKNOWN; } |
100 | } | 100 | } |
101 | 101 | ||
102 | // When the physical properties are updated, an EntityProperty holds the update values. | 102 | // When the physical properties are updated, an EntityProperty holds the update values. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 500c84a..5d16bbf 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -47,7 +47,6 @@ public sealed class BSPrim : BSPhysObject | |||
47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | 47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | 48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. |
49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
50 | // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer | ||
51 | 50 | ||
52 | private bool _grabbed; | 51 | private bool _grabbed; |
53 | private bool _isSelected; | 52 | private bool _isSelected; |
@@ -94,7 +93,7 @@ public sealed class BSPrim : BSPhysObject | |||
94 | _physicsActorType = (int)ActorTypes.Prim; | 93 | _physicsActorType = (int)ActorTypes.Prim; |
95 | _position = pos; | 94 | _position = pos; |
96 | _size = size; | 95 | _size = size; |
97 | Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type | 96 | Scale = size; // the scale will be set by CreateGeom depending on object type |
98 | _orientation = rotation; | 97 | _orientation = rotation; |
99 | _buoyancy = 1f; | 98 | _buoyancy = 1f; |
100 | _velocity = OMV.Vector3.Zero; | 99 | _velocity = OMV.Vector3.Zero; |
@@ -155,6 +154,8 @@ public sealed class BSPrim : BSPhysObject | |||
155 | public override OMV.Vector3 Size { | 154 | public override OMV.Vector3 Size { |
156 | get { return _size; } | 155 | get { return _size; } |
157 | set { | 156 | set { |
157 | // We presume the scale and size are the same. If scale must be changed for | ||
158 | // the physical shape, that is done when the geometry is built. | ||
158 | _size = value; | 159 | _size = value; |
159 | ForceBodyShapeRebuild(false); | 160 | ForceBodyShapeRebuild(false); |
160 | } | 161 | } |
@@ -170,7 +171,7 @@ public sealed class BSPrim : BSPhysObject | |||
170 | } | 171 | } |
171 | } | 172 | } |
172 | // Whatever the linkset wants is what I want. | 173 | // Whatever the linkset wants is what I want. |
173 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape | 174 | public override PhysicsShapeType PreferredPhysicalShape |
174 | { get { return Linkset.PreferredPhysicalShape(this); } } | 175 | { get { return Linkset.PreferredPhysicalShape(this); } } |
175 | 176 | ||
176 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | 177 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
@@ -274,19 +275,19 @@ public sealed class BSPrim : BSPhysObject | |||
274 | if (!Linkset.IsRoot(this)) | 275 | if (!Linkset.IsRoot(this)) |
275 | _position = Linkset.Position(this); | 276 | _position = Linkset.Position(this); |
276 | 277 | ||
277 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | 278 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
278 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 279 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
279 | return _position; | 280 | return _position; |
280 | } | 281 | } |
281 | set { | 282 | set { |
282 | // If you must push the position into the physics engine, use ForcePosition. | 283 | // If the position must be forced into the physics engine, use ForcePosition. |
283 | if (_position == value) | 284 | if (_position == value) |
284 | { | 285 | { |
285 | return; | 286 | return; |
286 | } | 287 | } |
287 | _position = value; | 288 | _position = value; |
288 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | 289 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? |
289 | PositionSanityCheck(); | 290 | PositionSanityCheck(false); |
290 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 291 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
291 | { | 292 | { |
292 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 293 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
@@ -302,7 +303,7 @@ public sealed class BSPrim : BSPhysObject | |||
302 | } | 303 | } |
303 | set { | 304 | set { |
304 | _position = value; | 305 | _position = value; |
305 | PositionSanityCheck(); | 306 | // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. |
306 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 307 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
307 | ActivateIfPhysical(false); | 308 | ActivateIfPhysical(false); |
308 | } | 309 | } |
@@ -311,52 +312,43 @@ public sealed class BSPrim : BSPhysObject | |||
311 | // Check that the current position is sane and, if not, modify the position to make it so. | 312 | // Check that the current position is sane and, if not, modify the position to make it so. |
312 | // Check for being below terrain and being out of bounds. | 313 | // Check for being below terrain and being out of bounds. |
313 | // Returns 'true' of the position was made sane by some action. | 314 | // Returns 'true' of the position was made sane by some action. |
314 | private bool PositionSanityCheck() | 315 | private bool PositionSanityCheck(bool inTaintTime) |
315 | { | 316 | { |
316 | bool ret = false; | 317 | bool ret = false; |
317 | 318 | ||
318 | // If totally below the ground, move the prim up | ||
319 | // TODO: figure out the right solution for this... only for dynamic objects? | ||
320 | /* | ||
321 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 319 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
320 | OMV.Vector3 upForce = OMV.Vector3.Zero; | ||
322 | if (Position.Z < terrainHeight) | 321 | if (Position.Z < terrainHeight) |
323 | { | 322 | { |
324 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 323 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
325 | _position.Z = terrainHeight + 2.0f; | 324 | float targetHeight = terrainHeight + (Size.Z / 2f); |
325 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | ||
326 | upForce.Z = (terrainHeight - Position.Z) * 1f; | ||
326 | ret = true; | 327 | ret = true; |
327 | } | 328 | } |
328 | */ | 329 | |
329 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
330 | { | 331 | { |
331 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); |
332 | // TODO: a floating motor so object will bob in the water | 333 | // TODO: a floating motor so object will bob in the water |
333 | if (Position.Z < waterHeight) | 334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) |
334 | { | 335 | { |
335 | _position.Z = waterHeight; | 336 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
337 | upForce.Z = (waterHeight - Position.Z) * 1f; | ||
336 | ret = true; | 338 | ret = true; |
337 | } | 339 | } |
338 | } | 340 | } |
339 | 341 | ||
340 | // TODO: check for out of bounds | 342 | // TODO: check for out of bounds |
341 | return ret; | ||
342 | } | ||
343 | 343 | ||
344 | // A version of the sanity check that also makes sure a new position value is | 344 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. |
345 | // pushed to the physics engine. This routine would be used by anyone | 345 | if (ret) |
346 | // who is not already pushing the value. | ||
347 | private bool PositionSanityCheck(bool inTaintTime) | ||
348 | { | ||
349 | bool ret = false; | ||
350 | if (PositionSanityCheck()) | ||
351 | { | 346 | { |
352 | // The new position value must be pushed into the physics engine but we can't | 347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() |
353 | // just assign to "Position" because of potential call loops. | ||
354 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate() | ||
355 | { | 348 | { |
356 | DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 349 | // Apply upforce and overcome gravity. |
357 | ForcePosition = _position; | 350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; |
358 | }); | 351 | }); |
359 | ret = true; | ||
360 | } | 352 | } |
361 | return ret; | 353 | return ret; |
362 | } | 354 | } |
@@ -940,6 +932,7 @@ public sealed class BSPrim : BSPhysObject | |||
940 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 932 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
941 | AddForce(force, pushforce, false); | 933 | AddForce(force, pushforce, false); |
942 | } | 934 | } |
935 | // Applying a force just adds this to the total force on the object. | ||
943 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 936 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
944 | // for an object, doesn't matter if force is a pushforce or not | 937 | // for an object, doesn't matter if force is a pushforce or not |
945 | if (force.IsFinite()) | 938 | if (force.IsFinite()) |
@@ -971,6 +964,7 @@ public sealed class BSPrim : BSPhysObject | |||
971 | }); | 964 | }); |
972 | } | 965 | } |
973 | 966 | ||
967 | // An impulse force is scaled by the mass of the object. | ||
974 | public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) | 968 | public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) |
975 | { | 969 | { |
976 | OMV.Vector3 applyImpulse = impulse; | 970 | OMV.Vector3 applyImpulse = impulse; |
@@ -1423,7 +1417,7 @@ public sealed class BSPrim : BSPhysObject | |||
1423 | if (changed != 0) | 1417 | if (changed != 0) |
1424 | { | 1418 | { |
1425 | // Only update the position of single objects and linkset roots | 1419 | // Only update the position of single objects and linkset roots |
1426 | if (this._parentPrim == null) | 1420 | if (Linkset.IsRoot(this)) |
1427 | { | 1421 | { |
1428 | base.RequestPhysicsterseUpdate(); | 1422 | base.RequestPhysicsterseUpdate(); |
1429 | } | 1423 | } |
@@ -1435,19 +1429,24 @@ public sealed class BSPrim : BSPhysObject | |||
1435 | // Updates only for individual prims and for the root object of a linkset. | 1429 | // Updates only for individual prims and for the root object of a linkset. |
1436 | if (Linkset.IsRoot(this)) | 1430 | if (Linkset.IsRoot(this)) |
1437 | { | 1431 | { |
1438 | // Assign to the local variables so the normal set action does not happen | 1432 | // Assign directly to the local variables so the normal set action does not happen |
1439 | _position = entprop.Position; | 1433 | _position = entprop.Position; |
1440 | _orientation = entprop.Rotation; | 1434 | _orientation = entprop.Rotation; |
1441 | _velocity = entprop.Velocity; | 1435 | _velocity = entprop.Velocity; |
1442 | _acceleration = entprop.Acceleration; | 1436 | _acceleration = entprop.Acceleration; |
1443 | _rotationalVelocity = entprop.RotationalVelocity; | 1437 | _rotationalVelocity = entprop.RotationalVelocity; |
1444 | 1438 | ||
1439 | // The sanity check can change the velocity and/or position. | ||
1440 | if (PositionSanityCheck(true)) | ||
1441 | { | ||
1442 | entprop.Position = _position; | ||
1443 | entprop.Velocity = _velocity; | ||
1444 | } | ||
1445 | |||
1445 | // remember the current and last set values | 1446 | // remember the current and last set values |
1446 | LastEntityProperties = CurrentEntityProperties; | 1447 | LastEntityProperties = CurrentEntityProperties; |
1447 | CurrentEntityProperties = entprop; | 1448 | CurrentEntityProperties = entprop; |
1448 | 1449 | ||
1449 | PositionSanityCheck(true); | ||
1450 | |||
1451 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | 1450 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; |
1452 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1451 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1453 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | 1452 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 2fee95e..27a78d1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -712,7 +712,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
712 | // here just before the physics engine is called to step the simulation. | 712 | // here just before the physics engine is called to step the simulation. |
713 | public void ProcessTaints() | 713 | public void ProcessTaints() |
714 | { | 714 | { |
715 | InTaintTime = true; | 715 | InTaintTime = true; // Only used for debugging so locking is not necessary. |
716 | ProcessRegularTaints(); | 716 | ProcessRegularTaints(); |
717 | ProcessPostTaintTaints(); | 717 | ProcessPostTaintTaints(); |
718 | InTaintTime = false; | 718 | InTaintTime = false; |
@@ -758,6 +758,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
758 | DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); | 758 | DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); |
759 | } | 759 | } |
760 | */ | 760 | */ |
761 | |||
761 | // swizzle a new list into the list location so we can process what's there | 762 | // swizzle a new list into the list location so we can process what's there |
762 | List<TaintCallbackEntry> oldList; | 763 | List<TaintCallbackEntry> oldList; |
763 | lock (_taintLock) | 764 | lock (_taintLock) |
@@ -787,8 +788,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
787 | // will replace any previous operation by the same object. | 788 | // will replace any previous operation by the same object. |
788 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) | 789 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) |
789 | { | 790 | { |
790 | if (!m_initialized) return; | ||
791 | |||
792 | string uniqueIdent = ident + "-" + ID.ToString(); | 791 | string uniqueIdent = ident + "-" + ID.ToString(); |
793 | lock (_taintLock) | 792 | lock (_taintLock) |
794 | { | 793 | { |
@@ -864,13 +863,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
864 | } | 863 | } |
865 | } | 864 | } |
866 | 865 | ||
866 | // Only used for debugging. Does not change state of anything so locking is not necessary. | ||
867 | public bool AssertInTaintTime(string whereFrom) | 867 | public bool AssertInTaintTime(string whereFrom) |
868 | { | 868 | { |
869 | if (!InTaintTime) | 869 | if (!InTaintTime) |
870 | { | 870 | { |
871 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | 871 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); |
872 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | 872 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); |
873 | Util.PrintCallStack(); | 873 | Util.PrintCallStack(); // Prints the stack into the DEBUG log file. |
874 | } | 874 | } |
875 | return InTaintTime; | 875 | return InTaintTime; |
876 | } | 876 | } |
@@ -1145,6 +1145,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1145 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | 1145 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, |
1146 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | 1146 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), |
1147 | 1147 | ||
1148 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
1149 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||
1150 | (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); }, | ||
1151 | (s) => { return s.m_params[0].terrainImplementation; }, | ||
1152 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | ||
1148 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1153 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1149 | 0.5f, | 1154 | 0.5f, |
1150 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1155 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
@@ -1180,11 +1185,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1180 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, | 1185 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, |
1181 | (s) => { return s.m_params[0].avatarRestitution; }, | 1186 | (s) => { return s.m_params[0].avatarRestitution; }, |
1182 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), | 1187 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), |
1183 | new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", | 1188 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", |
1184 | 0.37f, | 1189 | 0.6f, |
1185 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, | 1190 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); }, |
1186 | (s) => { return s.m_params[0].avatarCapsuleRadius; }, | 1191 | (s) => { return s.m_params[0].avatarCapsuleWidth; }, |
1187 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), | 1192 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ), |
1193 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
1194 | 0.45f, | ||
1195 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); }, | ||
1196 | (s) => { return s.m_params[0].avatarCapsuleDepth; }, | ||
1197 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ), | ||
1188 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | 1198 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", |
1189 | 1.5f, | 1199 | 1.5f, |
1190 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, | 1200 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 29a23c0..869735c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -178,7 +178,7 @@ public sealed class BSShapeCollection : IDisposable | |||
178 | bool ret = false; | 178 | bool ret = false; |
179 | switch (shape.type) | 179 | switch (shape.type) |
180 | { | 180 | { |
181 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | 181 | case PhysicsShapeType.SHAPE_MESH: |
182 | MeshDesc meshDesc; | 182 | MeshDesc meshDesc; |
183 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | 183 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) |
184 | { | 184 | { |
@@ -201,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable | |||
201 | meshDesc.lastReferenced = System.DateTime.Now; | 201 | meshDesc.lastReferenced = System.DateTime.Now; |
202 | Meshes[shape.shapeKey] = meshDesc; | 202 | Meshes[shape.shapeKey] = meshDesc; |
203 | break; | 203 | break; |
204 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | 204 | case PhysicsShapeType.SHAPE_HULL: |
205 | HullDesc hullDesc; | 205 | HullDesc hullDesc; |
206 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | 206 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) |
207 | { | 207 | { |
@@ -224,7 +224,7 @@ public sealed class BSShapeCollection : IDisposable | |||
224 | hullDesc.lastReferenced = System.DateTime.Now; | 224 | hullDesc.lastReferenced = System.DateTime.Now; |
225 | Hulls[shape.shapeKey] = hullDesc; | 225 | Hulls[shape.shapeKey] = hullDesc; |
226 | break; | 226 | break; |
227 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | 227 | case PhysicsShapeType.SHAPE_UNKNOWN: |
228 | break; | 228 | break; |
229 | default: | 229 | default: |
230 | // Native shapes are not tracked and they don't go into any list | 230 | // Native shapes are not tracked and they don't go into any list |
@@ -255,16 +255,16 @@ public sealed class BSShapeCollection : IDisposable | |||
255 | { | 255 | { |
256 | switch (shape.type) | 256 | switch (shape.type) |
257 | { | 257 | { |
258 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | 258 | case PhysicsShapeType.SHAPE_HULL: |
259 | DereferenceHull(shape, shapeCallback); | 259 | DereferenceHull(shape, shapeCallback); |
260 | break; | 260 | break; |
261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | 261 | case PhysicsShapeType.SHAPE_MESH: |
262 | DereferenceMesh(shape, shapeCallback); | 262 | DereferenceMesh(shape, shapeCallback); |
263 | break; | 263 | break; |
264 | case ShapeData.PhysicsShapeType.SHAPE_COMPOUND: | 264 | case PhysicsShapeType.SHAPE_COMPOUND: |
265 | DereferenceCompound(shape, shapeCallback); | 265 | DereferenceCompound(shape, shapeCallback); |
266 | break; | 266 | break; |
267 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | 267 | case PhysicsShapeType.SHAPE_UNKNOWN: |
268 | break; | 268 | break; |
269 | default: | 269 | default: |
270 | break; | 270 | break; |
@@ -352,28 +352,28 @@ public sealed class BSShapeCollection : IDisposable | |||
352 | BulletShape shapeInfo = new BulletShape(cShape); | 352 | BulletShape shapeInfo = new BulletShape(cShape); |
353 | if (TryGetMeshByPtr(cShape, out meshDesc)) | 353 | if (TryGetMeshByPtr(cShape, out meshDesc)) |
354 | { | 354 | { |
355 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_MESH; | 355 | shapeInfo.type = PhysicsShapeType.SHAPE_MESH; |
356 | shapeInfo.shapeKey = meshDesc.shapeKey; | 356 | shapeInfo.shapeKey = meshDesc.shapeKey; |
357 | } | 357 | } |
358 | else | 358 | else |
359 | { | 359 | { |
360 | if (TryGetHullByPtr(cShape, out hullDesc)) | 360 | if (TryGetHullByPtr(cShape, out hullDesc)) |
361 | { | 361 | { |
362 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL; | 362 | shapeInfo.type = PhysicsShapeType.SHAPE_HULL; |
363 | shapeInfo.shapeKey = hullDesc.shapeKey; | 363 | shapeInfo.shapeKey = hullDesc.shapeKey; |
364 | } | 364 | } |
365 | else | 365 | else |
366 | { | 366 | { |
367 | if (BulletSimAPI.IsCompound2(cShape)) | 367 | if (BulletSimAPI.IsCompound2(cShape)) |
368 | { | 368 | { |
369 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | 369 | shapeInfo.type = PhysicsShapeType.SHAPE_COMPOUND; |
370 | } | 370 | } |
371 | else | 371 | else |
372 | { | 372 | { |
373 | if (BulletSimAPI.IsNativeShape2(cShape)) | 373 | if (BulletSimAPI.IsNativeShape2(cShape)) |
374 | { | 374 | { |
375 | shapeInfo.isNativeShape = true; | 375 | shapeInfo.isNativeShape = true; |
376 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | 376 | shapeInfo.type = PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) |
377 | } | 377 | } |
378 | } | 378 | } |
379 | } | 379 | } |
@@ -381,7 +381,7 @@ public sealed class BSShapeCollection : IDisposable | |||
381 | 381 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 383 | ||
384 | if (shapeInfo.type != ShapeData.PhysicsShapeType.SHAPE_UNKNOWN) | 384 | if (shapeInfo.type != PhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 385 | { |
386 | DereferenceShape(shapeInfo, true, null); | 386 | DereferenceShape(shapeInfo, true, null); |
387 | } | 387 | } |
@@ -405,11 +405,11 @@ public sealed class BSShapeCollection : IDisposable | |||
405 | bool ret = false; | 405 | bool ret = false; |
406 | bool haveShape = false; | 406 | bool haveShape = false; |
407 | 407 | ||
408 | if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 408 | if (!haveShape && prim.PreferredPhysicalShape == PhysicsShapeType.SHAPE_CAPSULE) |
409 | { | 409 | { |
410 | // an avatar capsule is close to a native shape (it is not shared) | 410 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, | 411 | ret = GetReferenceToNativeShape(prim, PhysicsShapeType.SHAPE_CAPSULE, |
412 | ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); | 412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | 413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
414 | ret = true; | 414 | ret = true; |
415 | haveShape = true; | 415 | haveShape = true; |
@@ -417,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable | |||
417 | 417 | ||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | 418 | // Compound shapes are handled special as they are rebuilt from scratch. |
419 | // This isn't too great a hardship since most of the child shapes will already been created. | 419 | // This isn't too great a hardship since most of the child shapes will already been created. |
420 | if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND) | 420 | if (!haveShape && prim.PreferredPhysicalShape == PhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 421 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
@@ -460,11 +460,11 @@ public sealed class BSShapeCollection : IDisposable | |||
460 | haveShape = true; | 460 | haveShape = true; |
461 | if (forceRebuild | 461 | if (forceRebuild |
462 | || prim.Scale != prim.Size | 462 | || prim.Scale != prim.Size |
463 | || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE | 463 | || prim.PhysShape.type != PhysicsShapeType.SHAPE_SPHERE |
464 | ) | 464 | ) |
465 | { | 465 | { |
466 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE, | 466 | ret = GetReferenceToNativeShape(prim, PhysicsShapeType.SHAPE_SPHERE, |
467 | ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); | 467 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", |
469 | prim.LocalID, forceRebuild, prim.PhysShape); | 469 | prim.LocalID, forceRebuild, prim.PhysShape); |
470 | } | 470 | } |
@@ -474,11 +474,11 @@ public sealed class BSShapeCollection : IDisposable | |||
474 | haveShape = true; | 474 | haveShape = true; |
475 | if (forceRebuild | 475 | if (forceRebuild |
476 | || prim.Scale != prim.Size | 476 | || prim.Scale != prim.Size |
477 | || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX | 477 | || prim.PhysShape.type != PhysicsShapeType.SHAPE_BOX |
478 | ) | 478 | ) |
479 | { | 479 | { |
480 | ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX, | 480 | ret = GetReferenceToNativeShape( prim, PhysicsShapeType.SHAPE_BOX, |
481 | ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); | 481 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", |
483 | prim.LocalID, forceRebuild, prim.PhysShape); | 483 | prim.LocalID, forceRebuild, prim.PhysShape); |
484 | } | 484 | } |
@@ -519,15 +519,12 @@ public sealed class BSShapeCollection : IDisposable | |||
519 | // Creates a native shape and assignes it to prim.BSShape. | 519 | // Creates a native shape and assignes it to prim.BSShape. |
520 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). | 520 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). |
521 | private bool GetReferenceToNativeShape(BSPhysObject prim, | 521 | private bool GetReferenceToNativeShape(BSPhysObject prim, |
522 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, | 522 | PhysicsShapeType shapeType, FixedShapeKey shapeKey, |
523 | ShapeDestructionCallback shapeCallback) | 523 | ShapeDestructionCallback shapeCallback) |
524 | { | 524 | { |
525 | // release any previous shape | 525 | // release any previous shape |
526 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 526 | DereferenceShape(prim.PhysShape, true, shapeCallback); |
527 | 527 | ||
528 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
529 | prim.Scale = prim.Size; | ||
530 | |||
531 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
532 | 529 | ||
533 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
@@ -538,8 +535,8 @@ public sealed class BSShapeCollection : IDisposable | |||
538 | return true; | 535 | return true; |
539 | } | 536 | } |
540 | 537 | ||
541 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType, | 538 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, PhysicsShapeType shapeType, |
542 | ShapeData.FixedShapeKey shapeKey) | 539 | FixedShapeKey shapeKey) |
543 | { | 540 | { |
544 | BulletShape newShape; | 541 | BulletShape newShape; |
545 | // Need to make sure the passed shape information is for the native type. | 542 | // Need to make sure the passed shape information is for the native type. |
@@ -547,12 +544,13 @@ public sealed class BSShapeCollection : IDisposable | |||
547 | nativeShapeData.Type = shapeType; | 544 | nativeShapeData.Type = shapeType; |
548 | nativeShapeData.ID = prim.LocalID; | 545 | nativeShapeData.ID = prim.LocalID; |
549 | nativeShapeData.Scale = prim.Scale; | 546 | nativeShapeData.Scale = prim.Scale; |
550 | nativeShapeData.Size = prim.Scale; | 547 | nativeShapeData.Size = prim.Scale; // unneeded, I think. |
551 | nativeShapeData.MeshKey = (ulong)shapeKey; | 548 | nativeShapeData.MeshKey = (ulong)shapeKey; |
552 | nativeShapeData.HullKey = (ulong)shapeKey; | 549 | nativeShapeData.HullKey = (ulong)shapeKey; |
553 | 550 | ||
554 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 551 | if (shapeType == PhysicsShapeType.SHAPE_CAPSULE) |
555 | { | 552 | { |
553 | // The proper scale has been calculated in the prim. | ||
556 | newShape = new BulletShape( | 554 | newShape = new BulletShape( |
557 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) |
558 | , shapeType); | 556 | , shapeType); |
@@ -560,6 +558,9 @@ public sealed class BSShapeCollection : IDisposable | |||
560 | } | 558 | } |
561 | else | 559 | else |
562 | { | 560 | { |
561 | // Native shapes are scaled in Bullet so set the scaling to the size | ||
562 | prim.Scale = prim.Size; | ||
563 | nativeShapeData.Scale = prim.Scale; | ||
563 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | 564 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); |
564 | } | 565 | } |
565 | if (newShape.ptr == IntPtr.Zero) | 566 | if (newShape.ptr == IntPtr.Zero) |
@@ -585,7 +586,7 @@ public sealed class BSShapeCollection : IDisposable | |||
585 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 586 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
586 | 587 | ||
587 | // if this new shape is the same as last time, don't recreate the mesh | 588 | // if this new shape is the same as last time, don't recreate the mesh |
588 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) | 589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == PhysicsShapeType.SHAPE_MESH) |
589 | return false; | 590 | return false; |
590 | 591 | ||
591 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
@@ -643,7 +644,7 @@ public sealed class BSShapeCollection : IDisposable | |||
643 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 644 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); |
644 | } | 645 | } |
645 | } | 646 | } |
646 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | 647 | BulletShape newShape = new BulletShape(meshPtr, PhysicsShapeType.SHAPE_MESH); |
647 | newShape.shapeKey = newMeshKey; | 648 | newShape.shapeKey = newMeshKey; |
648 | 649 | ||
649 | return newShape; | 650 | return newShape; |
@@ -659,7 +660,7 @@ public sealed class BSShapeCollection : IDisposable | |||
659 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 660 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
660 | 661 | ||
661 | // if the hull hasn't changed, don't rebuild it | 662 | // if the hull hasn't changed, don't rebuild it |
662 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) | 663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == PhysicsShapeType.SHAPE_HULL) |
663 | return false; | 664 | return false; |
664 | 665 | ||
665 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
@@ -780,7 +781,7 @@ public sealed class BSShapeCollection : IDisposable | |||
780 | } | 781 | } |
781 | } | 782 | } |
782 | 783 | ||
783 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | 784 | BulletShape newShape = new BulletShape(hullPtr, PhysicsShapeType.SHAPE_HULL); |
784 | newShape.shapeKey = newHullKey; | 785 | newShape.shapeKey = newHullKey; |
785 | 786 | ||
786 | return newShape; // 'true' means a new shape has been added to this prim | 787 | return newShape; // 'true' means a new shape has been added to this prim |
@@ -803,7 +804,7 @@ public sealed class BSShapeCollection : IDisposable | |||
803 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | 804 | // DereferenceShape(prim.PhysShape, true, shapeCallback); |
804 | 805 | ||
805 | BulletShape cShape = new BulletShape( | 806 | BulletShape cShape = new BulletShape( |
806 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND); | 807 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), PhysicsShapeType.SHAPE_COMPOUND); |
807 | 808 | ||
808 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 809 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
809 | CreateGeomMeshOrHull(prim, shapeCallback); | 810 | CreateGeomMeshOrHull(prim, shapeCallback); |
@@ -894,7 +895,7 @@ public sealed class BSShapeCollection : IDisposable | |||
894 | 895 | ||
895 | // While we figure out the real problem, stick a simple native shape on the object. | 896 | // While we figure out the real problem, stick a simple native shape on the object. |
896 | BulletShape fillinShape = | 897 | BulletShape fillinShape = |
897 | BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX); | 898 | BuildPhysicalNativeShape(prim, PhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); |
898 | 899 | ||
899 | return fillinShape; | 900 | return fillinShape; |
900 | } | 901 | } |
@@ -940,7 +941,7 @@ public sealed class BSShapeCollection : IDisposable | |||
940 | else | 941 | else |
941 | { | 942 | { |
942 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
943 | prim.LocalID, prim.ForcePosition, prim.ForceOrientation); | 944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
944 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
945 | } | 946 | } |
946 | aBody = new BulletBody(prim.LocalID, bodyPtr); | 947 | aBody = new BulletBody(prim.LocalID, bodyPtr); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index d59a486..f2e62d9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -35,7 +35,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
35 | public abstract class BSShape | 35 | public abstract class BSShape |
36 | { | 36 | { |
37 | public IntPtr ptr { get; set; } | 37 | public IntPtr ptr { get; set; } |
38 | public ShapeData.PhysicsShapeType type { get; set; } | 38 | public PhysicsShapeType type { get; set; } |
39 | public System.UInt64 key { get; set; } | 39 | public System.UInt64 key { get; set; } |
40 | public int referenceCount { get; set; } | 40 | public int referenceCount { get; set; } |
41 | public DateTime lastReferenced { get; set; } | 41 | public DateTime lastReferenced { get; set; } |
@@ -43,7 +43,7 @@ public abstract class BSShape | |||
43 | public BSShape() | 43 | public BSShape() |
44 | { | 44 | { |
45 | ptr = IntPtr.Zero; | 45 | ptr = IntPtr.Zero; |
46 | type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | 46 | type = PhysicsShapeType.SHAPE_UNKNOWN; |
47 | key = 0; | 47 | key = 0; |
48 | referenceCount = 0; | 48 | referenceCount = 0; |
49 | lastReferenced = DateTime.Now; | 49 | lastReferenced = DateTime.Now; |
@@ -54,17 +54,17 @@ public abstract class BSShape | |||
54 | { | 54 | { |
55 | BSShape ret = null; | 55 | BSShape ret = null; |
56 | 56 | ||
57 | if (prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 57 | if (prim.PreferredPhysicalShape == PhysicsShapeType.SHAPE_CAPSULE) |
58 | { | 58 | { |
59 | // an avatar capsule is close to a native shape (it is not shared) | 59 | // an avatar capsule is close to a native shape (it is not shared) |
60 | ret = BSShapeNative.GetReference(physicsScene, prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, | 60 | ret = BSShapeNative.GetReference(physicsScene, prim, PhysicsShapeType.SHAPE_CAPSULE, |
61 | ShapeData.FixedShapeKey.KEY_CAPSULE); | 61 | FixedShapeKey.KEY_CAPSULE); |
62 | physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); | 62 | physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); |
63 | } | 63 | } |
64 | 64 | ||
65 | // Compound shapes are handled special as they are rebuilt from scratch. | 65 | // Compound shapes are handled special as they are rebuilt from scratch. |
66 | // This isn't too great a hardship since most of the child shapes will already been created. | 66 | // This isn't too great a hardship since most of the child shapes will already been created. |
67 | if (ret == null && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND) | 67 | if (ret == null && prim.PreferredPhysicalShape == PhysicsShapeType.SHAPE_COMPOUND) |
68 | { | 68 | { |
69 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | 69 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added |
70 | ret = BSShapeCompound.GetReference(prim); | 70 | ret = BSShapeCompound.GetReference(prim); |
@@ -123,14 +123,14 @@ public class BSShapeNative : BSShape | |||
123 | { | 123 | { |
124 | } | 124 | } |
125 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, | 125 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, |
126 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey) | 126 | PhysicsShapeType shapeType, FixedShapeKey shapeKey) |
127 | { | 127 | { |
128 | // Native shapes are not shared and are always built anew. | 128 | // Native shapes are not shared and are always built anew. |
129 | return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); | 129 | return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); |
130 | } | 130 | } |
131 | 131 | ||
132 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, | 132 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, |
133 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey) | 133 | PhysicsShapeType shapeType, FixedShapeKey shapeKey) |
134 | { | 134 | { |
135 | ShapeData nativeShapeData = new ShapeData(); | 135 | ShapeData nativeShapeData = new ShapeData(); |
136 | nativeShapeData.Type = shapeType; | 136 | nativeShapeData.Type = shapeType; |
@@ -141,7 +141,7 @@ public class BSShapeNative : BSShape | |||
141 | nativeShapeData.HullKey = (ulong)shapeKey; | 141 | nativeShapeData.HullKey = (ulong)shapeKey; |
142 | 142 | ||
143 | 143 | ||
144 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 144 | if (shapeType == PhysicsShapeType.SHAPE_CAPSULE) |
145 | { | 145 | { |
146 | ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); | 146 | ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); |
147 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 147 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs new file mode 100755 index 0000000..8fc36d1 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework; | ||
33 | using OpenSim.Region.CoreModules; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using Nini.Config; | ||
37 | using log4net; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | public sealed class BSTerrainHeightmap : BSTerrainPhys | ||
44 | { | ||
45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; | ||
46 | |||
47 | BulletHeightMapInfo m_mapInfo = null; | ||
48 | |||
49 | // Constructor to build a default, flat heightmap terrain. | ||
50 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | ||
51 | : base(physicsScene, regionBase, id) | ||
52 | { | ||
53 | Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); | ||
54 | Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); | ||
55 | int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; | ||
56 | float[] initialMap = new float[totalHeights]; | ||
57 | for (int ii = 0; ii < totalHeights; ii++) | ||
58 | { | ||
59 | initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; | ||
60 | } | ||
61 | m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); | ||
62 | m_mapInfo.minCoords = minTerrainCoords; | ||
63 | m_mapInfo.maxCoords = maxTerrainCoords; | ||
64 | m_mapInfo.terrainRegionBase = TerrainBase; | ||
65 | // Don't have to free any previous since we just got here. | ||
66 | BuildHeightmapTerrain(); | ||
67 | } | ||
68 | |||
69 | // This minCoords and maxCoords passed in give the size of the terrain (min and max Z | ||
70 | // are the high and low points of the heightmap). | ||
71 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, | ||
72 | Vector3 minCoords, Vector3 maxCoords) | ||
73 | : base(physicsScene, regionBase, id) | ||
74 | { | ||
75 | m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); | ||
76 | m_mapInfo.minCoords = minCoords; | ||
77 | m_mapInfo.maxCoords = maxCoords; | ||
78 | m_mapInfo.minZ = minCoords.Z; | ||
79 | m_mapInfo.maxZ = maxCoords.Z; | ||
80 | m_mapInfo.terrainRegionBase = TerrainBase; | ||
81 | |||
82 | // Don't have to free any previous since we just got here. | ||
83 | BuildHeightmapTerrain(); | ||
84 | } | ||
85 | |||
86 | public override void Dispose() | ||
87 | { | ||
88 | ReleaseHeightMapTerrain(); | ||
89 | } | ||
90 | |||
91 | // Using the information in m_mapInfo, create the physical representation of the heightmap. | ||
92 | private void BuildHeightmapTerrain() | ||
93 | { | ||
94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | ||
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | ||
96 | m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); | ||
97 | |||
98 | // Create the terrain shape from the mapInfo | ||
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | ||
100 | PhysicsShapeType.SHAPE_TERRAIN); | ||
101 | |||
102 | // The terrain object initial position is at the center of the object | ||
103 | Vector3 centerPos; | ||
104 | centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); | ||
105 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); | ||
106 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); | ||
107 | |||
108 | m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, | ||
109 | BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, | ||
110 | m_mapInfo.ID, centerPos, Quaternion.Identity)); | ||
111 | |||
112 | // Set current terrain attributes | ||
113 | BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); | ||
114 | BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
115 | BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | ||
116 | BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
117 | |||
118 | // Return the new terrain to the world of physical objects | ||
119 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
120 | |||
121 | // redo its bounding box now that it is in the world | ||
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
123 | |||
124 | BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, | ||
125 | (uint)CollisionFilterGroups.TerrainFilter, | ||
126 | (uint)CollisionFilterGroups.TerrainMask); | ||
127 | |||
128 | // Make it so the terrain will not move or be considered for movement. | ||
129 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
130 | |||
131 | return; | ||
132 | } | ||
133 | |||
134 | // If there is information in m_mapInfo pointing to physical structures, release same. | ||
135 | private void ReleaseHeightMapTerrain() | ||
136 | { | ||
137 | if (m_mapInfo != null) | ||
138 | { | ||
139 | if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) | ||
140 | { | ||
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
142 | // Frees both the body and the shape. | ||
143 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
144 | BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr); | ||
145 | } | ||
146 | } | ||
147 | m_mapInfo = null; | ||
148 | } | ||
149 | |||
150 | // The passed position is relative to the base of the region. | ||
151 | public override float GetHeightAtXYZ(Vector3 pos) | ||
152 | { | ||
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
154 | |||
155 | int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X; | ||
156 | try | ||
157 | { | ||
158 | ret = m_mapInfo.heightMap[mapIndex]; | ||
159 | } | ||
160 | catch | ||
161 | { | ||
162 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
163 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | ||
164 | LogHeader, m_mapInfo.terrainRegionBase, pos); | ||
165 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
166 | } | ||
167 | return ret; | ||
168 | } | ||
169 | } | ||
170 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 7c34af2..71fca33 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -40,6 +40,32 @@ using OpenMetaverse; | |||
40 | 40 | ||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | 41 | namespace OpenSim.Region.Physics.BulletSPlugin |
42 | { | 42 | { |
43 | |||
44 | // The physical implementation of the terrain is wrapped in this class. | ||
45 | public abstract class BSTerrainPhys : IDisposable | ||
46 | { | ||
47 | public enum TerrainImplementation | ||
48 | { | ||
49 | Heightmap = 0, | ||
50 | Mesh = 1 | ||
51 | } | ||
52 | |||
53 | public BSScene PhysicsScene { get; private set; } | ||
54 | // Base of the region in world coordinates. Coordinates inside the region are relative to this. | ||
55 | public Vector3 TerrainBase { get; private set; } | ||
56 | public uint ID { get; private set; } | ||
57 | |||
58 | public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) | ||
59 | { | ||
60 | PhysicsScene = physicsScene; | ||
61 | TerrainBase = regionBase; | ||
62 | ID = id; | ||
63 | } | ||
64 | public abstract void Dispose(); | ||
65 | public abstract float GetHeightAtXYZ(Vector3 pos); | ||
66 | } | ||
67 | |||
68 | // ========================================================================================== | ||
43 | public sealed class BSTerrainManager | 69 | public sealed class BSTerrainManager |
44 | { | 70 | { |
45 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | 71 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; |
@@ -67,11 +93,10 @@ public sealed class BSTerrainManager | |||
67 | 93 | ||
68 | // If doing mega-regions, if we're region zero we will be managing multiple | 94 | // If doing mega-regions, if we're region zero we will be managing multiple |
69 | // region terrains since region zero does the physics for the whole mega-region. | 95 | // region terrains since region zero does the physics for the whole mega-region. |
70 | private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; | 96 | private Dictionary<Vector3, BSTerrainPhys> m_terrains; |
71 | 97 | ||
72 | // True of the terrain has been modified. | 98 | // Flags used to know when to recalculate the height. |
73 | // Used to force recalculation of terrain height after terrain has been modified | 99 | private bool m_terrainModified = false; |
74 | private bool m_terrainModified; | ||
75 | 100 | ||
76 | // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. | 101 | // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. |
77 | // This is incremented before assigning to new region so it is the last ID allocated. | 102 | // This is incremented before assigning to new region so it is the last ID allocated. |
@@ -89,8 +114,7 @@ public sealed class BSTerrainManager | |||
89 | public BSTerrainManager(BSScene physicsScene) | 114 | public BSTerrainManager(BSScene physicsScene) |
90 | { | 115 | { |
91 | PhysicsScene = physicsScene; | 116 | PhysicsScene = physicsScene; |
92 | m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); | 117 | m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); |
93 | m_terrainModified = false; | ||
94 | 118 | ||
95 | // Assume one region of default size | 119 | // Assume one region of default size |
96 | m_worldOffset = Vector3.Zero; | 120 | m_worldOffset = Vector3.Zero; |
@@ -99,9 +123,6 @@ public sealed class BSTerrainManager | |||
99 | } | 123 | } |
100 | 124 | ||
101 | // Create the initial instance of terrain and the underlying ground plane. | 125 | // Create the initial instance of terrain and the underlying ground plane. |
102 | // The objects are allocated in the unmanaged space and the pointers are tracked | ||
103 | // by the managed code. | ||
104 | // The terrains and the groundPlane are not added to the list of PhysObjects. | ||
105 | // This is called from the initialization routine so we presume it is | 126 | // This is called from the initialization routine so we presume it is |
106 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | 127 | // safe to call Bullet in real time. We hope no one is moving prims around yet. |
107 | public void CreateInitialGroundPlaneAndTerrain() | 128 | public void CreateInitialGroundPlaneAndTerrain() |
@@ -109,7 +130,7 @@ public sealed class BSTerrainManager | |||
109 | // The ground plane is here to catch things that are trying to drop to negative infinity | 130 | // The ground plane is here to catch things that are trying to drop to negative infinity |
110 | BulletShape groundPlaneShape = new BulletShape( | 131 | BulletShape groundPlaneShape = new BulletShape( |
111 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | 132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), |
112 | ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE); | 133 | PhysicsShapeType.SHAPE_GROUNDPLANE); |
113 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | 134 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, |
114 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 135 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, |
115 | Vector3.Zero, Quaternion.Identity)); | 136 | Vector3.Zero, Quaternion.Identity)); |
@@ -121,15 +142,9 @@ public sealed class BSTerrainManager | |||
121 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 142 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, |
122 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 143 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); |
123 | 144 | ||
124 | Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); | 145 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
125 | Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); | 146 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
126 | int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; | 147 | m_terrains.Add(Vector3.Zero, initialTerrain); |
127 | float[] initialMap = new float[totalHeights]; | ||
128 | for (int ii = 0; ii < totalHeights; ii++) | ||
129 | { | ||
130 | initialMap[ii] = HEIGHT_INITIALIZATION; | ||
131 | } | ||
132 | UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true); | ||
133 | } | 148 | } |
134 | 149 | ||
135 | // Release all the terrain structures we might have allocated | 150 | // Release all the terrain structures we might have allocated |
@@ -150,15 +165,11 @@ public sealed class BSTerrainManager | |||
150 | // Release all the terrain we have allocated | 165 | // Release all the terrain we have allocated |
151 | public void ReleaseTerrain() | 166 | public void ReleaseTerrain() |
152 | { | 167 | { |
153 | foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) | 168 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) |
154 | { | 169 | { |
155 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr)) | 170 | kvp.Value.Dispose(); |
156 | { | ||
157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr); | ||
158 | BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr); | ||
159 | } | ||
160 | } | 171 | } |
161 | m_heightMaps.Clear(); | 172 | m_terrains.Clear(); |
162 | } | 173 | } |
163 | 174 | ||
164 | // The simulator wants to set a new heightmap for the terrain. | 175 | // The simulator wants to set a new heightmap for the terrain. |
@@ -176,8 +187,9 @@ public sealed class BSTerrainManager | |||
176 | { | 187 | { |
177 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", | 188 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", |
178 | BSScene.DetailLogZero, m_worldOffset, m_worldMax); | 189 | BSScene.DetailLogZero, m_worldOffset, m_worldMax); |
179 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, | 190 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( |
180 | localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); | 191 | BSScene.CHILDTERRAIN_ID, localHeightMap, |
192 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
181 | } | 193 | } |
182 | } | 194 | } |
183 | else | 195 | else |
@@ -185,7 +197,7 @@ public sealed class BSTerrainManager | |||
185 | // If not doing the mega-prim thing, just change the terrain | 197 | // If not doing the mega-prim thing, just change the terrain |
186 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | 198 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); |
187 | 199 | ||
188 | UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, | 200 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, |
189 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | 201 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); |
190 | } | 202 | } |
191 | }); | 203 | }); |
@@ -195,56 +207,63 @@ public sealed class BSTerrainManager | |||
195 | // based on the passed information. The 'id' should be either the terrain id or | 207 | // based on the passed information. The 'id' should be either the terrain id or |
196 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | 208 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. |
197 | // The latter feature is for creating child terrains for mega-regions. | 209 | // The latter feature is for creating child terrains for mega-regions. |
198 | // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0) | ||
199 | // then a new body and shape is created and the mapInfo is filled. | ||
200 | // This call is used for doing the initial terrain creation. | ||
201 | // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new | 210 | // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new |
202 | // terrain shape is created and added to the body. | 211 | // terrain shape is created and added to the body. |
203 | // This call is most often used to update the heightMap and parameters of the terrain. | 212 | // This call is most often used to update the heightMap and parameters of the terrain. |
204 | // (The above does suggest that some simplification/refactoring is in order.) | 213 | // (The above does suggest that some simplification/refactoring is in order.) |
205 | private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | 214 | private void UpdateTerrain(uint id, float[] heightMap, |
215 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | ||
206 | { | 216 | { |
207 | DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", | 217 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", |
208 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); | 218 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); |
209 | 219 | ||
220 | // Find high and low points of passed heightmap. | ||
221 | // The min and max passed in is usually the area objects can be in (maximum | ||
222 | // object height, for instance). The terrain wants the bounding box for the | ||
223 | // terrain so we replace passed min and max Z with the actual terrain min/max Z. | ||
210 | float minZ = float.MaxValue; | 224 | float minZ = float.MaxValue; |
211 | float maxZ = float.MinValue; | 225 | float maxZ = float.MinValue; |
212 | Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y); | 226 | foreach (float height in heightMap) |
213 | |||
214 | int heightMapSize = heightMap.Length; | ||
215 | for (int ii = 0; ii < heightMapSize; ii++) | ||
216 | { | 227 | { |
217 | float height = heightMap[ii]; | ||
218 | if (height < minZ) minZ = height; | 228 | if (height < minZ) minZ = height; |
219 | if (height > maxZ) maxZ = height; | 229 | if (height > maxZ) maxZ = height; |
220 | } | 230 | } |
221 | 231 | if (minZ == maxZ) | |
222 | // The shape of the terrain is from its base to its extents. | 232 | { |
233 | // If min and max are the same, reduce min a little bit so a good bounding box is created. | ||
234 | minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; | ||
235 | } | ||
223 | minCoords.Z = minZ; | 236 | minCoords.Z = minZ; |
224 | maxCoords.Z = maxZ; | 237 | maxCoords.Z = maxZ; |
225 | 238 | ||
226 | BulletHeightMapInfo mapInfo; | 239 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); |
227 | if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) | 240 | |
241 | BSTerrainPhys terrainPhys; | ||
242 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
228 | { | 243 | { |
229 | // If this is terrain we know about, it's easy to update | 244 | // There is already a terrain in this spot. Free the old and build the new. |
230 | 245 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | |
231 | mapInfo.heightMap = heightMap; | 246 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); |
232 | mapInfo.minCoords = minCoords; | 247 | |
233 | mapInfo.maxCoords = maxCoords; | 248 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() |
234 | mapInfo.minZ = minZ; | ||
235 | mapInfo.maxZ = maxZ; | ||
236 | mapInfo.sizeX = maxCoords.X - minCoords.X; | ||
237 | mapInfo.sizeY = maxCoords.Y - minCoords.Y; | ||
238 | DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", | ||
239 | BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); | ||
240 | |||
241 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate() | ||
242 | { | 249 | { |
243 | if (MegaRegionParentPhysicsScene != null) | 250 | // Remove old terrain from the collection |
251 | m_terrains.Remove(terrainRegionBase); | ||
252 | // Release any physical memory it may be using. | ||
253 | terrainPhys.Dispose(); | ||
254 | |||
255 | if (MegaRegionParentPhysicsScene == null) | ||
256 | { | ||
257 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | ||
258 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | ||
259 | |||
260 | m_terrainModified = true; | ||
261 | } | ||
262 | else | ||
244 | { | 263 | { |
245 | // It's possible that Combine() was called after this code was queued. | 264 | // It's possible that Combine() was called after this code was queued. |
246 | // If we are a child of combined regions, we don't create any terrain for us. | 265 | // If we are a child of combined regions, we don't create any terrain for us. |
247 | DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); | 266 | DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); |
248 | 267 | ||
249 | // Get rid of any terrain that may have been allocated for us. | 268 | // Get rid of any terrain that may have been allocated for us. |
250 | ReleaseGroundPlaneAndTerrain(); | 269 | ReleaseGroundPlaneAndTerrain(); |
@@ -252,91 +271,6 @@ public sealed class BSTerrainManager | |||
252 | // I hate doing this, but just bail | 271 | // I hate doing this, but just bail |
253 | return; | 272 | return; |
254 | } | 273 | } |
255 | |||
256 | if (mapInfo.terrainBody.ptr != IntPtr.Zero) | ||
257 | { | ||
258 | // Updating an existing terrain. | ||
259 | DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", | ||
260 | BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); | ||
261 | |||
262 | // Remove from the dynamics world because we're going to mangle this object | ||
263 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
264 | |||
265 | // Get rid of the old terrain | ||
266 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
267 | BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr); | ||
268 | mapInfo.Ptr = IntPtr.Zero; | ||
269 | |||
270 | /* | ||
271 | // NOTE: This routine is half here because I can't get the terrain shape replacement | ||
272 | // to work. In the short term, the above three lines completely delete the old | ||
273 | // terrain and the code below recreates one from scratch. | ||
274 | // Hopefully the Bullet community will help me out on this one. | ||
275 | |||
276 | // First, release the old collision shape (there is only one terrain) | ||
277 | BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr); | ||
278 | |||
279 | // Fill the existing height map info with the new location and size information | ||
280 | BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID, | ||
281 | mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); | ||
282 | |||
283 | // Create a terrain shape based on the new info | ||
284 | mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr)); | ||
285 | |||
286 | // Stuff the shape into the existing terrain body | ||
287 | BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr); | ||
288 | */ | ||
289 | } | ||
290 | // else | ||
291 | { | ||
292 | // Creating a new terrain. | ||
293 | DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}", | ||
294 | BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ); | ||
295 | |||
296 | mapInfo.ID = id; | ||
297 | mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, | ||
298 | mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); | ||
299 | |||
300 | // Create the terrain shape from the mapInfo | ||
301 | mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr), | ||
302 | ShapeData.PhysicsShapeType.SHAPE_TERRAIN); | ||
303 | |||
304 | // The terrain object initial position is at the center of the object | ||
305 | Vector3 centerPos; | ||
306 | centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); | ||
307 | centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); | ||
308 | centerPos.Z = minZ + ((maxZ - minZ) / 2f); | ||
309 | |||
310 | mapInfo.terrainBody = new BulletBody(mapInfo.ID, | ||
311 | BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, | ||
312 | id, centerPos, Quaternion.Identity)); | ||
313 | } | ||
314 | |||
315 | // Make sure the entry is in the heightmap table | ||
316 | m_heightMaps[terrainRegionBase] = mapInfo; | ||
317 | |||
318 | // Set current terrain attributes | ||
319 | BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); | ||
320 | BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
321 | BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | ||
322 | BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
323 | |||
324 | // Return the new terrain to the world of physical objects | ||
325 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
326 | |||
327 | // redo its bounding box now that it is in the world | ||
328 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | ||
329 | |||
330 | BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr, | ||
331 | (uint)CollisionFilterGroups.TerrainFilter, | ||
332 | (uint)CollisionFilterGroups.TerrainMask); | ||
333 | |||
334 | // Make sure the new shape is processed. | ||
335 | // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); | ||
336 | // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
337 | BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
338 | |||
339 | m_terrainModified = true; | ||
340 | }); | 274 | }); |
341 | } | 275 | } |
342 | else | 276 | else |
@@ -353,34 +287,51 @@ public sealed class BSTerrainManager | |||
353 | Vector3 minCoordsX = minCoords; | 287 | Vector3 minCoordsX = minCoords; |
354 | Vector3 maxCoordsX = maxCoords; | 288 | Vector3 maxCoordsX = maxCoords; |
355 | 289 | ||
356 | DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | 290 | DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", |
357 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 291 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
358 | 292 | ||
359 | // Code that must happen at taint-time | 293 | // Code that must happen at taint-time |
360 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate() | 294 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() |
361 | { | 295 | { |
362 | DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); | 296 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", |
363 | // Create a new mapInfo that will be filled with the new info | 297 | BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); |
364 | mapInfo = new BulletHeightMapInfo(id, heightMapX, | 298 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
365 | BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID, | 299 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
366 | minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN)); | ||
367 | // Put the unfilled heightmap info into the collection of same | ||
368 | m_heightMaps.Add(terrainRegionBase, mapInfo); | ||
369 | // Build the terrain | ||
370 | UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true); | ||
371 | 300 | ||
372 | m_terrainModified = true; | 301 | m_terrainModified = true; |
373 | }); | 302 | }); |
374 | } | 303 | } |
375 | } | 304 | } |
376 | 305 | ||
377 | // Someday we will have complex terrain with caves and tunnels | 306 | // TODO: redo terrain implementation selection to allow other base types than heightMap. |
378 | public float GetTerrainHeightAtXYZ(Vector3 loc) | 307 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
379 | { | 308 | { |
380 | // For the moment, it's flat and convex | 309 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", |
381 | return GetTerrainHeightAtXY(loc.X, loc.Y); | 310 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, |
311 | (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); | ||
312 | BSTerrainPhys newTerrainPhys = null; | ||
313 | switch ((int)PhysicsScene.Params.terrainImplementation) | ||
314 | { | ||
315 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | ||
316 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | ||
317 | heightMap, minCoords, maxCoords); | ||
318 | break; | ||
319 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: | ||
320 | newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, | ||
321 | heightMap, minCoords, maxCoords); | ||
322 | break; | ||
323 | default: | ||
324 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | ||
325 | LogHeader, | ||
326 | (int)PhysicsScene.Params.terrainImplementation, | ||
327 | PhysicsScene.Params.terrainImplementation, | ||
328 | PhysicsScene.RegionName, terrainRegionBase); | ||
329 | break; | ||
330 | } | ||
331 | return newTerrainPhys; | ||
382 | } | 332 | } |
383 | 333 | ||
334 | |||
384 | // Given an X and Y, find the height of the terrain. | 335 | // Given an X and Y, find the height of the terrain. |
385 | // Since we could be handling multiple terrains for a mega-region, | 336 | // Since we could be handling multiple terrains for a mega-region, |
386 | // the base of the region is calcuated assuming all regions are | 337 | // the base of the region is calcuated assuming all regions are |
@@ -390,8 +341,10 @@ public sealed class BSTerrainManager | |||
390 | private float lastHeightTX = 999999f; | 341 | private float lastHeightTX = 999999f; |
391 | private float lastHeightTY = 999999f; | 342 | private float lastHeightTY = 999999f; |
392 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | 343 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; |
393 | private float GetTerrainHeightAtXY(float tX, float tY) | 344 | public float GetTerrainHeightAtXYZ(Vector3 loc) |
394 | { | 345 | { |
346 | float tX = loc.X; | ||
347 | float tY = loc.Y; | ||
395 | // You'd be surprized at the number of times this routine is called | 348 | // You'd be surprized at the number of times this routine is called |
396 | // with the same parameters as last time. | 349 | // with the same parameters as last time. |
397 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | 350 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) |
@@ -403,27 +356,14 @@ public sealed class BSTerrainManager | |||
403 | 356 | ||
404 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 357 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; |
405 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | 358 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; |
406 | Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); | 359 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); |
407 | 360 | ||
408 | BulletHeightMapInfo mapInfo; | 361 | BSTerrainPhys physTerrain; |
409 | if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo)) | 362 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) |
410 | { | 363 | { |
411 | float regionX = tX - offsetX; | 364 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); |
412 | float regionY = tY - offsetY; | 365 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", |
413 | int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX; | 366 | BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); |
414 | try | ||
415 | { | ||
416 | ret = mapInfo.heightMap[mapIndex]; | ||
417 | } | ||
418 | catch | ||
419 | { | ||
420 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
421 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}", | ||
422 | LogHeader, terrainBaseXY, regionX, regionY); | ||
423 | ret = HEIGHT_GETHEIGHT_RET; | ||
424 | } | ||
425 | // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}", | ||
426 | // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret); | ||
427 | } | 367 | } |
428 | else | 368 | else |
429 | { | 369 | { |
@@ -466,7 +406,7 @@ public sealed class BSTerrainManager | |||
466 | // Unhook all the combining that I know about. | 406 | // Unhook all the combining that I know about. |
467 | public void UnCombine(PhysicsScene pScene) | 407 | public void UnCombine(PhysicsScene pScene) |
468 | { | 408 | { |
469 | // Just like ODE, for the moment a NOP | 409 | // Just like ODE, we don't do anything yet. |
470 | DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); | 410 | DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); |
471 | } | 411 | } |
472 | 412 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs new file mode 100755 index 0000000..3279b6f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework; | ||
33 | using OpenSim.Region.CoreModules; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | using Nini.Config; | ||
37 | using log4net; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
42 | { | ||
43 | public sealed class BSTerrainMesh : BSTerrainPhys | ||
44 | { | ||
45 | static string LogHeader = "[BULLETSIM TERRAIN MESH]"; | ||
46 | |||
47 | private float[] m_savedHeightMap; | ||
48 | int m_sizeX; | ||
49 | int m_sizeY; | ||
50 | |||
51 | BulletShape m_terrainShape; | ||
52 | BulletBody m_terrainBody; | ||
53 | |||
54 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | ||
55 | : base(physicsScene, regionBase, id) | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) | ||
60 | : base(physicsScene, regionBase, id) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | // Create terrain mesh from a heightmap. | ||
65 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, | ||
66 | Vector3 minCoords, Vector3 maxCoords) | ||
67 | : base(physicsScene, regionBase, id) | ||
68 | { | ||
69 | int indicesCount; | ||
70 | int[] indices; | ||
71 | int verticesCount; | ||
72 | float[] vertices; | ||
73 | |||
74 | m_savedHeightMap = initialMap; | ||
75 | |||
76 | m_sizeX = (int)(maxCoords.X - minCoords.X); | ||
77 | m_sizeY = (int)(maxCoords.Y - minCoords.Y); | ||
78 | |||
79 | if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, | ||
80 | m_sizeX, m_sizeY, | ||
81 | (float)m_sizeX, (float)m_sizeY, | ||
82 | Vector3.Zero, 1.0f, | ||
83 | out indicesCount, out indices, out verticesCount, out vertices)) | ||
84 | { | ||
85 | // DISASTER!! | ||
86 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); | ||
87 | PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); | ||
88 | // Something is very messed up and a crash is in our future. | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | ||
93 | indicesCount, indices, verticesCount, vertices), | ||
94 | PhysicsShapeType.SHAPE_MESH); | ||
95 | if (m_terrainShape.ptr == IntPtr.Zero) | ||
96 | { | ||
97 | // DISASTER!! | ||
98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | ||
99 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); | ||
100 | // Something is very messed up and a crash is in our future. | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | Vector3 pos = regionBase; | ||
105 | Quaternion rot = Quaternion.Identity; | ||
106 | |||
107 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); | ||
108 | if (m_terrainBody.ptr == IntPtr.Zero) | ||
109 | { | ||
110 | // DISASTER!! | ||
111 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | ||
112 | // Something is very messed up and a crash is in our future. | ||
113 | return; | ||
114 | } | ||
115 | |||
116 | // Set current terrain attributes | ||
117 | BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); | ||
118 | BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
119 | BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | ||
120 | BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
121 | |||
122 | // Static objects are not very massive. | ||
123 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | ||
124 | |||
125 | // Return the new terrain to the world of physical objects | ||
126 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
127 | |||
128 | // redo its bounding box now that it is in the world | ||
129 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
130 | |||
131 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | ||
132 | (uint)CollisionFilterGroups.TerrainFilter, | ||
133 | (uint)CollisionFilterGroups.TerrainMask); | ||
134 | |||
135 | // Make it so the terrain will not move or be considered for movement. | ||
136 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
137 | } | ||
138 | |||
139 | public override void Dispose() | ||
140 | { | ||
141 | if (m_terrainBody.ptr != IntPtr.Zero) | ||
142 | { | ||
143 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
144 | // Frees both the body and the shape. | ||
145 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | public override float GetHeightAtXYZ(Vector3 pos) | ||
150 | { | ||
151 | // For the moment use the saved heightmap to get the terrain height. | ||
152 | // TODO: raycast downward to find the true terrain below the position. | ||
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
154 | |||
155 | int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; | ||
156 | try | ||
157 | { | ||
158 | ret = m_savedHeightMap[mapIndex]; | ||
159 | } | ||
160 | catch | ||
161 | { | ||
162 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
163 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | ||
164 | LogHeader, TerrainBase, pos); | ||
165 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
166 | } | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | ||
171 | // Return 'true' if successfully created. | ||
172 | public static bool ConvertHeightmapToMesh( | ||
173 | BSScene physicsScene, | ||
174 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | ||
175 | float extentX, float extentY, // zero based range for output vertices | ||
176 | Vector3 extentBase, // base to be added to all vertices | ||
177 | float magnification, // number of vertices to create between heightMap coords | ||
178 | out int indicesCountO, out int[] indicesO, | ||
179 | out int verticesCountO, out float[] verticesO) | ||
180 | { | ||
181 | bool ret = false; | ||
182 | |||
183 | int indicesCount = 0; | ||
184 | int verticesCount = 0; | ||
185 | int[] indices = new int[0]; | ||
186 | float[] vertices = new float[0]; | ||
187 | |||
188 | // Simple mesh creation which assumes magnification == 1. | ||
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | ||
190 | |||
191 | try | ||
192 | { | ||
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | ||
194 | int totalVertices = (sizeX + 1) * (sizeY + 1); | ||
195 | vertices = new float[totalVertices * 3]; | ||
196 | int totalIndices = sizeX * sizeY * 6; | ||
197 | indices = new int[totalIndices]; | ||
198 | |||
199 | float magX = (float)sizeX / extentX; | ||
200 | float magY = (float)sizeY / extentY; | ||
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | ||
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | ||
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | ||
204 | for (int yy = 0; yy <= sizeY; yy++) | ||
205 | { | ||
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | ||
207 | { | ||
208 | int offset = yy * sizeX + xx; | ||
209 | // Extend the height from the height from the last row or column | ||
210 | if (yy == sizeY) offset -= sizeX; | ||
211 | if (xx == sizeX) offset -= 1; | ||
212 | float height = heightMap[offset]; | ||
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | ||
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | ||
215 | vertices[verticesCount + 2] = height + extentBase.Z; | ||
216 | verticesCount += 3; | ||
217 | } | ||
218 | } | ||
219 | verticesCount = verticesCount / 3; | ||
220 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", | ||
221 | BSScene.DetailLogZero, verticesCount); | ||
222 | |||
223 | for (int yy = 0; yy < sizeY; yy++) | ||
224 | { | ||
225 | for (int xx = 0; xx < sizeX; xx++) | ||
226 | { | ||
227 | int offset = yy * sizeX + xx; | ||
228 | // Each vertices is presumed to be the upper left corner of a box of two triangles | ||
229 | indices[indicesCount + 0] = offset; | ||
230 | indices[indicesCount + 1] = offset + 1; | ||
231 | indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column | ||
232 | indices[indicesCount + 3] = offset + 1; | ||
233 | indices[indicesCount + 4] = offset + sizeX + 2; | ||
234 | indices[indicesCount + 5] = offset + sizeX + 1; | ||
235 | indicesCount += 6; | ||
236 | } | ||
237 | } | ||
238 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG | ||
239 | LogHeader, indicesCount); // DEBUG | ||
240 | ret = true; | ||
241 | } | ||
242 | catch (Exception e) | ||
243 | { | ||
244 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
245 | LogHeader, physicsScene.RegionName, extentBase, e); | ||
246 | } | ||
247 | |||
248 | indicesCountO = indicesCount; | ||
249 | indicesO = indices; | ||
250 | verticesCountO = verticesCount; | ||
251 | verticesO = vertices; | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | } | ||
256 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 28fae13..4647c2d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -88,11 +88,11 @@ public struct BulletShape | |||
88 | public BulletShape(IntPtr xx) | 88 | public BulletShape(IntPtr xx) |
89 | { | 89 | { |
90 | ptr = xx; | 90 | ptr = xx; |
91 | type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | 91 | type=PhysicsShapeType.SHAPE_UNKNOWN; |
92 | shapeKey = 0; | 92 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; |
93 | isNativeShape = false; | 93 | isNativeShape = false; |
94 | } | 94 | } |
95 | public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ) | 95 | public BulletShape(IntPtr xx, PhysicsShapeType typ) |
96 | { | 96 | { |
97 | ptr = xx; | 97 | ptr = xx; |
98 | type = typ; | 98 | type = typ; |
@@ -100,7 +100,7 @@ public struct BulletShape | |||
100 | isNativeShape = false; | 100 | isNativeShape = false; |
101 | } | 101 | } |
102 | public IntPtr ptr; | 102 | public IntPtr ptr; |
103 | public ShapeData.PhysicsShapeType type; | 103 | public PhysicsShapeType type; |
104 | public System.UInt64 shapeKey; | 104 | public System.UInt64 shapeKey; |
105 | public bool isNativeShape; | 105 | public bool isNativeShape; |
106 | public override string ToString() | 106 | public override string ToString() |
@@ -152,7 +152,7 @@ public class BulletHeightMapInfo | |||
152 | ID = id; | 152 | ID = id; |
153 | Ptr = xx; | 153 | Ptr = xx; |
154 | heightMap = hm; | 154 | heightMap = hm; |
155 | terrainRegionBase = new Vector2(0f, 0f); | 155 | terrainRegionBase = Vector3.Zero; |
156 | minCoords = new Vector3(100f, 100f, 25f); | 156 | minCoords = new Vector3(100f, 100f, 25f); |
157 | maxCoords = new Vector3(101f, 101f, 26f); | 157 | maxCoords = new Vector3(101f, 101f, 26f); |
158 | minZ = maxZ = 0f; | 158 | minZ = maxZ = 0f; |
@@ -161,7 +161,7 @@ public class BulletHeightMapInfo | |||
161 | public uint ID; | 161 | public uint ID; |
162 | public IntPtr Ptr; | 162 | public IntPtr Ptr; |
163 | public float[] heightMap; | 163 | public float[] heightMap; |
164 | public Vector2 terrainRegionBase; | 164 | public Vector3 terrainRegionBase; |
165 | public Vector3 minCoords; | 165 | public Vector3 minCoords; |
166 | public Vector3 maxCoords; | 166 | public Vector3 maxCoords; |
167 | public float sizeX, sizeY; | 167 | public float sizeX, sizeY; |
@@ -178,24 +178,37 @@ public struct ConvexHull | |||
178 | int VertexCount; | 178 | int VertexCount; |
179 | Vector3[] Vertices; | 179 | Vector3[] Vertices; |
180 | } | 180 | } |
181 | public enum PhysicsShapeType | ||
182 | { | ||
183 | SHAPE_UNKNOWN = 0, | ||
184 | SHAPE_CAPSULE = 1, | ||
185 | SHAPE_BOX = 2, | ||
186 | SHAPE_CONE = 3, | ||
187 | SHAPE_CYLINDER = 4, | ||
188 | SHAPE_SPHERE = 5, | ||
189 | SHAPE_MESH = 6, | ||
190 | SHAPE_HULL = 7, | ||
191 | // following defined by BulletSim | ||
192 | SHAPE_GROUNDPLANE = 20, | ||
193 | SHAPE_TERRAIN = 21, | ||
194 | SHAPE_COMPOUND = 22, | ||
195 | SHAPE_HEIGHTMAP = 23, | ||
196 | }; | ||
197 | |||
198 | // The native shapes have predefined shape hash keys | ||
199 | public enum FixedShapeKey : ulong | ||
200 | { | ||
201 | KEY_NONE = 0, | ||
202 | KEY_BOX = 1, | ||
203 | KEY_SPHERE = 2, | ||
204 | KEY_CONE = 3, | ||
205 | KEY_CYLINDER = 4, | ||
206 | KEY_CAPSULE = 5, | ||
207 | } | ||
208 | |||
181 | [StructLayout(LayoutKind.Sequential)] | 209 | [StructLayout(LayoutKind.Sequential)] |
182 | public struct ShapeData | 210 | public struct ShapeData |
183 | { | 211 | { |
184 | public enum PhysicsShapeType | ||
185 | { | ||
186 | SHAPE_UNKNOWN = 0, | ||
187 | SHAPE_AVATAR = 1, | ||
188 | SHAPE_BOX = 2, | ||
189 | SHAPE_CONE = 3, | ||
190 | SHAPE_CYLINDER = 4, | ||
191 | SHAPE_SPHERE = 5, | ||
192 | SHAPE_MESH = 6, | ||
193 | SHAPE_HULL = 7, | ||
194 | // following defined by BulletSim | ||
195 | SHAPE_GROUNDPLANE = 20, | ||
196 | SHAPE_TERRAIN = 21, | ||
197 | SHAPE_COMPOUND = 22, | ||
198 | }; | ||
199 | public uint ID; | 212 | public uint ID; |
200 | public PhysicsShapeType Type; | 213 | public PhysicsShapeType Type; |
201 | public Vector3 Position; | 214 | public Vector3 Position; |
@@ -216,16 +229,6 @@ public struct ShapeData | |||
216 | // note that bools are passed as floats since bool size changes by language and architecture | 229 | // note that bools are passed as floats since bool size changes by language and architecture |
217 | public const float numericTrue = 1f; | 230 | public const float numericTrue = 1f; |
218 | public const float numericFalse = 0f; | 231 | public const float numericFalse = 0f; |
219 | |||
220 | // The native shapes have predefined shape hash keys | ||
221 | public enum FixedShapeKey : ulong | ||
222 | { | ||
223 | KEY_BOX = 1, | ||
224 | KEY_SPHERE = 2, | ||
225 | KEY_CONE = 3, | ||
226 | KEY_CYLINDER = 4, | ||
227 | KEY_CAPSULE = 5, | ||
228 | } | ||
229 | } | 232 | } |
230 | [StructLayout(LayoutKind.Sequential)] | 233 | [StructLayout(LayoutKind.Sequential)] |
231 | public struct SweepHit | 234 | public struct SweepHit |
@@ -280,6 +283,7 @@ public struct ConfigurationParameters | |||
280 | public float ccdSweptSphereRadius; | 283 | public float ccdSweptSphereRadius; |
281 | public float contactProcessingThreshold; | 284 | public float contactProcessingThreshold; |
282 | 285 | ||
286 | public float terrainImplementation; | ||
283 | public float terrainFriction; | 287 | public float terrainFriction; |
284 | public float terrainHitFraction; | 288 | public float terrainHitFraction; |
285 | public float terrainRestitution; | 289 | public float terrainRestitution; |
@@ -287,7 +291,8 @@ public struct ConfigurationParameters | |||
287 | public float avatarStandingFriction; | 291 | public float avatarStandingFriction; |
288 | public float avatarDensity; | 292 | public float avatarDensity; |
289 | public float avatarRestitution; | 293 | public float avatarRestitution; |
290 | public float avatarCapsuleRadius; | 294 | public float avatarCapsuleWidth; |
295 | public float avatarCapsuleDepth; | ||
291 | public float avatarCapsuleHeight; | 296 | public float avatarCapsuleHeight; |
292 | public float avatarContactProcessingThreshold; | 297 | public float avatarContactProcessingThreshold; |
293 | 298 | ||
@@ -388,13 +393,13 @@ public enum CollisionFilterGroups : uint | |||
388 | ObjectFilter = BSolidFilter, | 393 | ObjectFilter = BSolidFilter, |
389 | ObjectMask = BAllFilter, | 394 | ObjectMask = BAllFilter, |
390 | StaticObjectFilter = BStaticFilter, | 395 | StaticObjectFilter = BStaticFilter, |
391 | StaticObjectMask = BAllFilter, | 396 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other |
392 | LinksetFilter = BLinksetFilter, | 397 | LinksetFilter = BLinksetFilter, |
393 | LinksetMask = BAllFilter & ~BLinksetFilter, | 398 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other |
394 | VolumeDetectFilter = BSensorTrigger, | 399 | VolumeDetectFilter = BSensorTrigger, |
395 | VolumeDetectMask = ~BSensorTrigger, | 400 | VolumeDetectMask = ~BSensorTrigger, |
396 | TerrainFilter = BTerrainFilter, | 401 | TerrainFilter = BTerrainFilter, |
397 | TerrainMask = BAllFilter & ~BStaticFilter, | 402 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide |
398 | GroundPlaneFilter = BGroundPlaneFilter, | 403 | GroundPlaneFilter = BGroundPlaneFilter, |
399 | GroundPlaneMask = BAllFilter | 404 | GroundPlaneMask = BAllFilter |
400 | 405 | ||
diff --git a/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs index 87b3d2d..a006fa8 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs | |||
@@ -57,14 +57,23 @@ namespace OpenSim.Server.Handlers.Asset | |||
57 | public override byte[] Handle(string path, Stream request, | 57 | public override byte[] Handle(string path, Stream request, |
58 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 58 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
59 | { | 59 | { |
60 | AssetBase asset; | ||
60 | XmlSerializer xs = new XmlSerializer(typeof (AssetBase)); | 61 | XmlSerializer xs = new XmlSerializer(typeof (AssetBase)); |
61 | AssetBase asset = (AssetBase) xs.Deserialize(request); | 62 | |
63 | try | ||
64 | { | ||
65 | asset = (AssetBase)xs.Deserialize(request); | ||
66 | } | ||
67 | catch (XmlException) | ||
68 | { | ||
69 | httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; | ||
70 | return null; | ||
71 | } | ||
62 | 72 | ||
63 | string[] p = SplitParams(path); | 73 | string[] p = SplitParams(path); |
64 | if (p.Length > 1) | 74 | if (p.Length > 1) |
65 | { | 75 | { |
66 | bool result = | 76 | bool result = m_AssetService.UpdateContent(p[1], asset.Data); |
67 | m_AssetService.UpdateContent(p[1], asset.Data); | ||
68 | 77 | ||
69 | xs = new XmlSerializer(typeof(bool)); | 78 | xs = new XmlSerializer(typeof(bool)); |
70 | return ServerUtils.SerializeResult(xs, result); | 79 | return ServerUtils.SerializeResult(xs, result); |
diff --git a/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs b/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs new file mode 100644 index 0000000..427fa16 --- /dev/null +++ b/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Net; | ||
31 | using System.Text; | ||
32 | using System.Xml; | ||
33 | using System.Xml.Serialization; | ||
34 | using Nini.Config; | ||
35 | using NUnit.Framework; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Server.Handlers.Asset; | ||
39 | using OpenSim.Services.AssetService; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Tests.Common; | ||
42 | using OpenSim.Tests.Common.Mock; | ||
43 | |||
44 | namespace OpenSim.Server.Handlers.Asset.Test | ||
45 | { | ||
46 | [TestFixture] | ||
47 | public class AssetServerPostHandlerTests : OpenSimTestCase | ||
48 | { | ||
49 | [Test] | ||
50 | public void TestGoodAssetStoreRequest() | ||
51 | { | ||
52 | TestHelpers.InMethod(); | ||
53 | |||
54 | UUID assetId = TestHelpers.ParseTail(0x1); | ||
55 | |||
56 | IConfigSource config = new IniConfigSource(); | ||
57 | config.AddConfig("AssetService"); | ||
58 | config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); | ||
59 | |||
60 | AssetService assetService = new AssetService(config); | ||
61 | |||
62 | AssetServerPostHandler asph = new AssetServerPostHandler(assetService); | ||
63 | |||
64 | AssetBase asset = AssetHelpers.CreateNotecardAsset(assetId, "Hello World"); | ||
65 | |||
66 | MemoryStream buffer = new MemoryStream(); | ||
67 | |||
68 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
69 | settings.Encoding = Encoding.UTF8; | ||
70 | |||
71 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
72 | { | ||
73 | XmlSerializer serializer = new XmlSerializer(typeof(AssetBase)); | ||
74 | serializer.Serialize(writer, asset); | ||
75 | writer.Flush(); | ||
76 | } | ||
77 | |||
78 | buffer.Position = 0; | ||
79 | asph.Handle(null, buffer, null, null); | ||
80 | |||
81 | AssetBase retrievedAsset = assetService.Get(assetId.ToString()); | ||
82 | |||
83 | Assert.That(retrievedAsset, Is.Not.Null); | ||
84 | } | ||
85 | |||
86 | [Test] | ||
87 | public void TestBadXmlAssetStoreRequest() | ||
88 | { | ||
89 | TestHelpers.InMethod(); | ||
90 | |||
91 | IConfigSource config = new IniConfigSource(); | ||
92 | config.AddConfig("AssetService"); | ||
93 | config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); | ||
94 | |||
95 | AssetService assetService = new AssetService(config); | ||
96 | |||
97 | AssetServerPostHandler asph = new AssetServerPostHandler(assetService); | ||
98 | |||
99 | MemoryStream buffer = new MemoryStream(); | ||
100 | byte[] badData = new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f }; | ||
101 | buffer.Write(badData, 0, badData.Length); | ||
102 | buffer.Position = 0; | ||
103 | |||
104 | TestOSHttpResponse response = new TestOSHttpResponse(); | ||
105 | asph.Handle(null, buffer, null, response); | ||
106 | |||
107 | Assert.That(response.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); | ||
108 | } | ||
109 | } | ||
110 | } \ No newline at end of file | ||