Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

integration
Justin Clark-Casey (justincc) 2012-10-24 02:04:26 +01:00
commit 326f1507fa
14 changed files with 534 additions and 390 deletions

View File

@ -105,7 +105,7 @@ public class BSCharacter : BSPhysObject
shapeData.Position = _position; shapeData.Position = _position;
shapeData.Rotation = _orientation; shapeData.Rotation = _orientation;
shapeData.Velocity = _velocity; shapeData.Velocity = _velocity;
shapeData.Size = Scale; shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1>
shapeData.Scale = Scale; shapeData.Scale = Scale;
shapeData.Mass = _mass; shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy; shapeData.Buoyancy = _buoyancy;
@ -144,7 +144,9 @@ public class BSCharacter : BSPhysObject
ForcePosition = _position; ForcePosition = _position;
// Set the velocity and compute the proper friction // Set the velocity and compute the proper friction
ForceVelocity = _velocity; ForceVelocity = _velocity;
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution); BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
if (PhysicsScene.Params.ccdMotionThreshold > 0f) if (PhysicsScene.Params.ccdMotionThreshold > 0f)
@ -156,16 +158,20 @@ public class BSCharacter : BSPhysObject
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
// Make so capsule does not fall over
BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION);
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
// Do this after the object has been added to the world // Do this after the object has been added to the world
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
(uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarFilter,
(uint)CollisionFilterGroups.AvatarMask); (uint)CollisionFilterGroups.AvatarMask);
} }
@ -175,11 +181,13 @@ public class BSCharacter : BSPhysObject
} }
// No one calls this method so I don't know what it could possibly mean // No one calls this method so I don't know what it could possibly mean
public override bool Stopped { get { return false; } } public override bool Stopped { get { return false; } }
public override OMV.Vector3 Size { public override OMV.Vector3 Size {
get get
{ {
// Avatar capsule size is kept in the scale parameter. // Avatar capsule size is kept in the scale parameter.
return _size; // return _size;
return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z);
} }
set { set {
@ -199,7 +207,9 @@ public class BSCharacter : BSPhysObject
} }
} }
public override OMV.Vector3 Scale { get; set; } public override OMV.Vector3 Scale { get; set; }
public override PrimitiveBaseShape Shape public override PrimitiveBaseShape Shape
{ {
set { BaseShape = value; } set { BaseShape = value; }
@ -264,12 +274,12 @@ public class BSCharacter : BSPhysObject
// Check that the current position is sane and, if not, modify the position to make it so. // Check that the current position is sane and, if not, modify the position to make it so.
// Check for being below terrain and being out of bounds. // Check for being below terrain or on water.
// Returns 'true' of the position was made sane by some action. // Returns 'true' of the position was made sane by some action.
private bool PositionSanityCheck() private bool PositionSanityCheck()
{ {
bool ret = false; bool ret = false;
// If below the ground, move the avatar up // If below the ground, move the avatar up
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
if (Position.Z < terrainHeight) if (Position.Z < terrainHeight)
@ -335,7 +345,7 @@ public class BSCharacter : BSPhysObject
} }
// Avatars don't do vehicles // Avatars don't do vehicles
public override int VehicleType { get { return 0; } set { return; } } public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
public override void VehicleFloatParam(int param, float value) { } public override void VehicleFloatParam(int param, float value) { }
public override void VehicleVectorParam(int param, OMV.Vector3 value) {} public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
@ -413,7 +423,7 @@ public class BSCharacter : BSPhysObject
}); });
} }
} }
// Go directly to Bullet to get/set the value. // Go directly to Bullet to get/set the value.
public override OMV.Quaternion ForceOrientation public override OMV.Quaternion ForceOrientation
{ {
get get
@ -478,7 +488,7 @@ public class BSCharacter : BSPhysObject
set { _collidingObj = value; } set { _collidingObj = value; }
} }
public override bool FloatOnWater { public override bool FloatOnWater {
set { set {
_floatOnWater = value; _floatOnWater = value;
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
{ {
@ -588,9 +598,8 @@ public class BSCharacter : BSPhysObject
newScale.X = PhysicsScene.Params.avatarCapsuleRadius; newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
// From the total height, remote the capsule half spheres that are at each end // From the total height, remove the capsule half spheres that are at each end
newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y); newScale.Z = size.Z- (newScale.X + newScale.Y);
// newScale.Z = (size.Z * 2f);
Scale = newScale; Scale = newScale;
} }
@ -636,7 +645,7 @@ public class BSCharacter : BSPhysObject
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel); BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
} }
// Tell the linkset about this // Tell the linkset about value changes
Linkset.UpdateProperties(this); Linkset.UpdateProperties(this);
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.

View File

@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public abstract class BSConstraint : IDisposable public abstract class BSConstraint : IDisposable
{ {
private static string LogHeader = "[BULLETSIM CONSTRAINT]";
protected BulletSim m_world; protected BulletSim m_world;
protected BulletBody m_body1; protected BulletBody m_body1;
protected BulletBody m_body2; protected BulletBody m_body2;
@ -53,7 +55,7 @@ public abstract class BSConstraint : IDisposable
{ {
bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
BSScene.DetailLogZero, BSScene.DetailLogZero,
m_body1.ID, m_body1.ptr.ToString("X"), m_body1.ID, m_body1.ptr.ToString("X"),
m_body2.ID, m_body2.ptr.ToString("X"), m_body2.ID, m_body2.ptr.ToString("X"),
success); success);
@ -124,7 +126,7 @@ public abstract class BSConstraint : IDisposable
} }
else else
{ {
m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
} }
} }
return ret; return ret;

View File

@ -23,7 +23,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ *
/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
* call the BulletSim system. * call the BulletSim system.
@ -352,7 +352,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_bankingMix = 1; // m_bankingMix = 1;
// m_bankingTimescale = 1; // m_bankingTimescale = 1;
// m_referenceFrame = Quaternion.Identity; // m_referenceFrame = Quaternion.Identity;
m_flags |= (VehicleFlag.NO_DEFLECTION_UP m_flags |= (VehicleFlag.NO_DEFLECTION_UP
| VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.LIMIT_MOTOR_UP); | VehicleFlag.LIMIT_MOTOR_UP);
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
@ -382,7 +382,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_bankingTimescale = 1; // m_bankingTimescale = 1;
// m_referenceFrame = Quaternion.Identity; // m_referenceFrame = Quaternion.Identity;
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
| VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_GLOBAL_HEIGHT
| VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.HOVER_UP_ONLY); | VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@ -458,14 +458,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Do any updating needed for a vehicle // Do any updating needed for a vehicle
public void Refresh() public void Refresh()
{ {
if (!IsActive) if (!IsActive)
return; return;
// Set the prim's inertia to zero. The vehicle code handles that and this // Set the prim's inertia to zero. The vehicle code handles that and this
// removes the motion and torque actions introduced by Bullet. // removes the motion and torque actions introduced by Bullet.
Vector3 inertia = Vector3.Zero; Vector3 inertia = Vector3.Zero;
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); // comment out for DEBUG test
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
// BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
} }
// One step of the vehicle properties for the next 'pTimestep' seconds. // One step of the vehicle properties for the next 'pTimestep' seconds.
@ -791,7 +792,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Sum velocities // Sum velocities
m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{ {
m_lastAngularVelocity.X = 0; m_lastAngularVelocity.X = 0;

View File

@ -32,10 +32,27 @@ using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSLinkset public abstract class BSLinkset
{ {
// private static string LogHeader = "[BULLETSIM LINKSET]"; // private static string LogHeader = "[BULLETSIM LINKSET]";
// Create the correct type of linkset for this child
public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
{
BSLinkset ret = null;
/*
if (parent.IsPhysical)
ret = new BSLinksetConstraints(physScene, parent);
else
ret = new BSLinksetManual(physScene, parent);
*/
// at the moment, there is only one
ret = new BSLinksetConstraints(physScene, parent);
return ret;
}
public BSPhysObject LinksetRoot { get; protected set; } public BSPhysObject LinksetRoot { get; protected set; }
public BSScene PhysicsScene { get; private set; } public BSScene PhysicsScene { get; private set; }
@ -52,16 +69,16 @@ public class BSLinkset
// the physical 'taint' children separately. // the physical 'taint' children separately.
// After taint processing and before the simulation step, these // After taint processing and before the simulation step, these
// two lists must be the same. // two lists must be the same.
private HashSet<BSPhysObject> m_children; protected HashSet<BSPhysObject> m_children;
private HashSet<BSPhysObject> m_taintChildren; protected HashSet<BSPhysObject> m_taintChildren;
// We lock the diddling of linkset classes to prevent any badness. // We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes // This locks the modification of the instances of this class. Changes
// to the physical representation is done via the tainting mechenism. // to the physical representation is done via the tainting mechenism.
private object m_linksetActivityLock = new Object(); protected object m_linksetActivityLock = new Object();
// We keep the prim's mass in the linkset structure since it could be dependent on other prims // We keep the prim's mass in the linkset structure since it could be dependent on other prims
private float m_mass; protected float m_mass;
public float LinksetMass public float LinksetMass
{ {
get get
@ -81,7 +98,7 @@ public class BSLinkset
get { return ComputeLinksetGeometricCenter(); } get { return ComputeLinksetGeometricCenter(); }
} }
public BSLinkset(BSScene scene, BSPhysObject parent) protected void Initialize(BSScene scene, BSPhysObject parent)
{ {
// A simple linkset of one (no children) // A simple linkset of one (no children)
LinksetID = m_nextLinksetID++; LinksetID = m_nextLinksetID++;
@ -128,7 +145,7 @@ public class BSLinkset
} }
// The child is down to a linkset of just itself // The child is down to a linkset of just itself
return new BSLinkset(PhysicsScene, child); return BSLinkset.Factory(PhysicsScene, child);
} }
// Return 'true' if the passed object is the root object of this linkset // Return 'true' if the passed object is the root object of this linkset
@ -148,6 +165,9 @@ public class BSLinkset
bool ret = false; bool ret = false;
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
if (m_children.Contains(child))
ret = true;
/*
foreach (BSPhysObject bp in m_children) foreach (BSPhysObject bp in m_children)
{ {
if (child.LocalID == bp.LocalID) if (child.LocalID == bp.LocalID)
@ -156,6 +176,7 @@ public class BSLinkset
break; break;
} }
} }
*/
} }
return ret; return ret;
} }
@ -163,24 +184,7 @@ public class BSLinkset
// When physical properties are changed the linkset needs to recalculate // When physical properties are changed the linkset needs to recalculate
// its internal properties. // its internal properties.
// May be called at runtime or taint-time (just pass the appropriate flag). // May be called at runtime or taint-time (just pass the appropriate flag).
public void Refresh(BSPhysObject requestor, bool inTaintTime) public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
{
// If there are no children, not physical or not root, I am not the one that recomputes the constraints
// (For the moment, static linksets do create constraints so remove the test for physical.)
if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
return;
BSScene.TaintCallback refreshOperation = delegate()
{
RecomputeLinksetConstraintVariables();
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
};
if (inTaintTime)
refreshOperation();
else
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
}
// The object is going dynamic (physical). Do any setup necessary // The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset. // for a dynamic linkset.
@ -188,102 +192,35 @@ public class BSLinkset
// has not yet been fully constructed. // has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object. // Return 'true' if any properties updated on the passed object.
// Called at taint-time! // Called at taint-time!
public bool MakeDynamic(BSPhysObject child) public abstract bool MakeDynamic(BSPhysObject child);
{
// What is done for each object in BSPrim is what we want.
return false;
}
// The object is going static (non-physical). Do any setup necessary // The object is going static (non-physical). Do any setup necessary
// for a static linkset. // for a static linkset.
// Return 'true' if any properties updated on the passed object. // Return 'true' if any properties updated on the passed object.
// Called at taint-time! // Called at taint-time!
public bool MakeStatic(BSPhysObject child) public abstract bool MakeStatic(BSPhysObject child);
{
// What is done for each object in BSPrim is what we want.
return false;
}
// If the software is handling the movement of all the objects in a linkset // Called when a parameter update comes from the physics engine for any object
// (like if one doesn't use constraints for static linksets), this is called // of the linkset is received.
// when an update for the root of the linkset is received.
// Called at taint-time!! // Called at taint-time!!
public void UpdateProperties(BSPhysObject physObject) public abstract void UpdateProperties(BSPhysObject physObject);
{
// The root local properties have been updated. Apply to the children if appropriate.
if (IsRoot(physObject) && HasAnyChildren)
{
if (!physObject.IsPhysical)
{
// TODO: implement software linkset update for static object linksets
}
}
}
// Routine used when rebuilding the body of the root of the linkset // Routine used when rebuilding the body of the root of the linkset
// Destroy all the constraints have have been made to root. // Destroy all the constraints have have been made to root.
// This is called when the root body is changing. // This is called when the root body is changing.
// Returns 'true' of something eas actually removed and would need restoring // Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!! // Called at taint-time!!
public bool RemoveBodyDependencies(BSPrim child) public abstract bool RemoveBodyDependencies(BSPrim child);
{
bool ret = false;
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
// If the one with the dependency is root, must undo all children
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
}
else
{
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
child.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
// ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
// Despite the function name, this removes any link to the specified object.
ret = PhysicallyUnlinkAllChildrenFromRoot(child);
}
}
return ret;
}
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints. // this routine will restore the removed constraints.
// Called at taint-time!! // Called at taint-time!!
public void RestoreBodyDependencies(BSPrim child) public abstract void RestoreBodyDependencies(BSPrim child);
{
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{
PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
}
}
else
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
LinksetRoot.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
PhysicallyLinkAChildToRoot(LinksetRoot, child);
}
}
}
// ================================================================ // ================================================================
// Below this point is internal magic // Below this point is internal magic
private float ComputeLinksetMass() protected virtual float ComputeLinksetMass()
{ {
float mass; float mass;
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
@ -297,7 +234,7 @@ public class BSLinkset
return mass; return mass;
} }
private OMV.Vector3 ComputeLinksetCenterOfMass() protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
{ {
OMV.Vector3 com; OMV.Vector3 com;
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
@ -317,7 +254,7 @@ public class BSLinkset
return com; return com;
} }
private OMV.Vector3 ComputeLinksetGeometricCenter() protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
{ {
OMV.Vector3 com; OMV.Vector3 com;
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
@ -336,236 +273,21 @@ public class BSLinkset
// I am the root of a linkset and a new child is being added // I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked. // Called while LinkActivity is locked.
private void AddChildToLinkset(BSPhysObject child) protected abstract void AddChildToLinkset(BSPhysObject child);
{
if (!HasChild(child))
{
m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{
DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
rootx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
// Since this is taint-time, the body and shape could have changed for the child
rootx.ForcePosition = rootx.Position; // DEBUG
childx.ForcePosition = childx.Position; // DEBUG
PhysicallyLinkAChildToRoot(rootx, childx);
m_taintChildren.Add(child);
});
}
return;
}
// Forcefully removing a child from a linkset. // Forcefully removing a child from a linkset.
// This is not being called by the child so we have to make sure the child doesn't think // This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset. // it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information // Normal OpenSimulator operation will never do this because other SceneObjectPart information
// also has to be updated (like pointer to prim's parent). // also has to be updated (like pointer to prim's parent).
private void RemoveChildFromOtherLinkset(BSPhysObject pchild) protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
{
pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
RemoveChildFromLinkset(pchild);
}
// I am the root of a linkset and one of my children is being removed. // I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset. // Safe to call even if the child is not really in my linkset.
private void RemoveChildFromLinkset(BSPhysObject child) protected abstract void RemoveChildFromLinkset(BSPhysObject child);
{
if (m_children.Remove(child))
{
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BSPhysObject childx = child;
DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
childx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{
m_taintChildren.Remove(child);
PhysicallyUnlinkAChildFromRoot(rootx, childx);
RecomputeLinksetConstraintVariables();
});
}
else
{
// This will happen if we remove the root of the linkset first. Non-fatal occurance.
// PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
}
return;
}
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
// Relative position normalized to the root prim
// Essentually a vector pointing from center of rootPrim to center of childPrim
OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
// real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
* of the objects.
* Code left as a warning to future programmers.
// ==================================================================================
// relative position normalized to the root prim
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
// relative rotation of the child to the parent
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.Body, childPrim.Body,
OMV.Vector3.Zero,
OMV.Quaternion.Inverse(rootPrim.Orientation),
OMV.Vector3.Zero,
OMV.Quaternion.Inverse(childPrim.Orientation),
// A point half way between the parent and child
// childRelativePosition/2,
// childRelativeRotation,
// childRelativePosition/2,
// inverseChildRelativeRotation,
true,
true
);
// ==================================================================================
*/
PhysicsScene.Constraints.AddConstraint(constrain);
// zero linear and angular limits makes the objects unable to move in relation to each other
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
// tweek the constraint to increase stability
constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
PhysicsScene.Params.linkConstraintTransMotorMaxVel,
PhysicsScene.Params.linkConstraintTransMotorMaxForce);
constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
{
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
}
}
// Remove linkage between myself and a particular child
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time.
// Called at taint time!
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
bool ret = false;
DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
{
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
ret = true;
}
return ret;
}
// Remove linkage between myself and any possible children I might have.
// Called at taint time!
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{
DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
bool ret = false;
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
{
ret = true;
}
return ret;
}
// Call each of the constraints that make up this linkset and recompute the
// various transforms and variables. Used when objects are added or removed
// from a linkset to make sure the constraints know about the new mass and
// geometry.
// Must only be called at taint time!!
private void RecomputeLinksetConstraintVariables()
{
float linksetMass = LinksetMass;
foreach (BSPhysObject child in m_taintChildren)
{
BSConstraint constrain;
if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
{
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
constrain.RecomputeConstraintVariables(linksetMass);
}
else
{
// Non-fatal error that happens when children are being added to the linkset but
// their constraints have not been created yet.
break;
}
}
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values
if (m_children.Count == m_taintChildren.Count)
{
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
foreach (BSPhysObject child in m_taintChildren)
{
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
}
// BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
}
return;
}
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args) protected void DetailLog(string msg, params Object[] args)
{ {
if (PhysicsScene.PhysicsLogging.Enabled) if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args); PhysicsScene.DetailLog(msg, args);

View File

@ -0,0 +1,385 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSLinksetConstraints : BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
{
base.Initialize(scene, parent);
}
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// May be called at runtime or taint-time (just pass the appropriate flag).
public override void Refresh(BSPhysObject requestor, bool inTaintTime)
{
// If there are no children or not root, I am not the one that recomputes the constraints
if (!HasAnyChildren || !IsRoot(requestor))
return;
BSScene.TaintCallback refreshOperation = delegate()
{
RecomputeLinksetConstraintVariables();
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
};
if (inTaintTime)
refreshOperation();
else
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
}
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset
// has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public override bool MakeDynamic(BSPhysObject child)
{
// What is done for each object in BSPrim is what we want.
return false;
}
// The object is going static (non-physical). Do any setup necessary
// for a static linkset.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public override bool MakeStatic(BSPhysObject child)
{
// What is done for each object in BSPrim is what we want.
return false;
}
// Called at taint-time!!
public override void UpdateProperties(BSPhysObject updated)
{
// Nothing to do for constraints on property updates
}
// Routine used when rebuilding the body of the root of the linkset
// Destroy all the constraints have have been made to root.
// This is called when the root body is changing.
// Returns 'true' of something eas actually removed and would need restoring
// Called at taint-time!!
public override bool RemoveBodyDependencies(BSPrim child)
{
bool ret = false;
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
// If the one with the dependency is root, must undo all children
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
}
else
{
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
child.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
// ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
// Despite the function name, this removes any link to the specified object.
ret = PhysicallyUnlinkAllChildrenFromRoot(child);
}
}
return ret;
}
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints.
// Called at taint-time!!
public override void RestoreBodyDependencies(BSPrim child)
{
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{
PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
}
}
else
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
LinksetRoot.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
PhysicallyLinkAChildToRoot(LinksetRoot, child);
}
}
}
// ================================================================
// Below this point is internal magic
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
protected override void AddChildToLinkset(BSPhysObject child)
{
if (!HasChild(child))
{
m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{
DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
rootx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
// Since this is taint-time, the body and shape could have changed for the child
rootx.ForcePosition = rootx.Position; // DEBUG
childx.ForcePosition = childx.Position; // DEBUG
PhysicallyLinkAChildToRoot(rootx, childx);
m_taintChildren.Add(child);
});
}
return;
}
// Forcefully removing a child from a linkset.
// This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
// also has to be updated (like pointer to prim's parent).
protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
{
pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
RemoveChildFromLinkset(pchild);
}
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
{
if (m_children.Remove(child))
{
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BSPhysObject childx = child;
DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
childx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{
m_taintChildren.Remove(child);
PhysicallyUnlinkAChildFromRoot(rootx, childx);
RecomputeLinksetConstraintVariables();
});
}
else
{
// This will happen if we remove the root of the linkset first. Non-fatal occurance.
// PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
}
return;
}
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
// Relative position normalized to the root prim
// Essentually a vector pointing from center of rootPrim to center of childPrim
OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
// real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
* of the objects.
* Code left as a warning to future programmers.
// ==================================================================================
// relative position normalized to the root prim
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
// relative rotation of the child to the parent
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.Body, childPrim.Body,
OMV.Vector3.Zero,
OMV.Quaternion.Inverse(rootPrim.Orientation),
OMV.Vector3.Zero,
OMV.Quaternion.Inverse(childPrim.Orientation),
// A point half way between the parent and child
// childRelativePosition/2,
// childRelativeRotation,
// childRelativePosition/2,
// inverseChildRelativeRotation,
true,
true
);
// ==================================================================================
*/
PhysicsScene.Constraints.AddConstraint(constrain);
// zero linear and angular limits makes the objects unable to move in relation to each other
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
// tweek the constraint to increase stability
constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
PhysicsScene.Params.linkConstraintTransMotorMaxVel,
PhysicsScene.Params.linkConstraintTransMotorMaxForce);
constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
{
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
}
}
// Remove linkage between myself and a particular child
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time.
// Called at taint time!
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
bool ret = false;
DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
{
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
ret = true;
}
return ret;
}
// Remove linkage between myself and any possible children I might have.
// Called at taint time!
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{
DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
bool ret = false;
if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
{
ret = true;
}
return ret;
}
// Call each of the constraints that make up this linkset and recompute the
// various transforms and variables. Used when objects are added or removed
// from a linkset to make sure the constraints know about the new mass and
// geometry.
// Must only be called at taint time!!
private void RecomputeLinksetConstraintVariables()
{
float linksetMass = LinksetMass;
foreach (BSPhysObject child in m_taintChildren)
{
BSConstraint constrain;
if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
{
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
constrain.RecomputeConstraintVariables(linksetMass);
}
else
{
// Non-fatal error that happens when children are being added to the linkset but
// their constraints have not been created yet.
break;
}
}
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values
if (m_children.Count == m_taintChildren.Count)
{
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
foreach (BSPhysObject child in m_taintChildren)
{
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
}
// BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
}
return;
}
}
}

View File

@ -46,7 +46,7 @@ public abstract class BSPhysObject : PhysicsActor
PhysObjectName = name; PhysObjectName = name;
TypeName = typeName; TypeName = typeName;
Linkset = new BSLinkset(PhysicsScene, this); Linkset = BSLinkset.Factory(PhysicsScene, this);
LastAssetBuildFailed = false; LastAssetBuildFailed = false;
CollisionCollection = new CollisionEventUpdate(); CollisionCollection = new CollisionEventUpdate();
@ -78,7 +78,7 @@ public abstract class BSPhysObject : PhysicsActor
public PrimitiveBaseShape BaseShape { get; protected set; } public PrimitiveBaseShape BaseShape { get; protected set; }
// When the physical properties are updated, an EntityProperty holds the update values. // When the physical properties are updated, an EntityProperty holds the update values.
// Keep the current and last EntityProperties to enable computation of differences // Keep the current and last EntityProperties to enable computation of differences
// between the current update and the previous values. // between the current update and the previous values.
public EntityProperties CurrentEntityProperties { get; set; } public EntityProperties CurrentEntityProperties { get; set; }
public EntityProperties LastEntityProperties { get; set; } public EntityProperties LastEntityProperties { get; set; }
@ -213,7 +213,7 @@ public abstract class BSPhysObject : PhysicsActor
UnSubscribeEvents(); UnSubscribeEvents();
} }
} }
public override void UnSubscribeEvents() { public override void UnSubscribeEvents() {
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
SubscribedEventsMs = 0; SubscribedEventsMs = 0;
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
@ -222,7 +222,7 @@ public abstract class BSPhysObject : PhysicsActor
}); });
} }
// Return 'true' if the simulator wants collision events // Return 'true' if the simulator wants collision events
public override bool SubscribedEvents() { public override bool SubscribedEvents() {
return (SubscribedEventsMs > 0); return (SubscribedEventsMs > 0);
} }

View File

@ -173,6 +173,7 @@ public sealed class BSPrim : BSPhysObject
} }
public override bool ForceBodyShapeRebuild(bool inTaintTime) public override bool ForceBodyShapeRebuild(bool inTaintTime)
{ {
LastAssetBuildFailed = false;
BSScene.TaintCallback rebuildOperation = delegate() BSScene.TaintCallback rebuildOperation = delegate()
{ {
_mass = CalculateMass(); // changing the shape changes the mass _mass = CalculateMass(); // changing the shape changes the mass
@ -295,7 +296,7 @@ public sealed class BSPrim : BSPhysObject
private bool PositionSanityCheck() private bool PositionSanityCheck()
{ {
bool ret = false; bool ret = false;
// If totally below the ground, move the prim up // If totally below the ground, move the prim up
// TODO: figure out the right solution for this... only for dynamic objects? // TODO: figure out the right solution for this... only for dynamic objects?
/* /*
@ -398,7 +399,7 @@ public sealed class BSPrim : BSPhysObject
{ {
// Done at taint time so we're sure the physics engine is not using the variables // Done at taint time so we're sure the physics engine is not using the variables
// Vehicle code changes the parameters for this vehicle type. // Vehicle code changes the parameters for this vehicle type.
this._vehicle.ProcessTypeChange(type); _vehicle.ProcessTypeChange(type);
}); });
} }
} }
@ -510,7 +511,7 @@ public sealed class BSPrim : BSPhysObject
}); });
} }
} }
// Go directly to Bullet to get/set the value. // Go directly to Bullet to get/set the value.
public override OMV.Quaternion ForceOrientation public override OMV.Quaternion ForceOrientation
{ {
get get
@ -768,7 +769,7 @@ public sealed class BSPrim : BSPhysObject
} }
} }
public override bool FloatOnWater { public override bool FloatOnWater {
set { set {
_floatOnWater = value; _floatOnWater = value;
PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
{ {
@ -971,7 +972,7 @@ public sealed class BSPrim : BSPhysObject
if (hollowAmount > 0.0) if (hollowAmount > 0.0)
{ {
hollowVolume *= hollowAmount; hollowVolume *= hollowAmount;
switch (BaseShape.HollowShape) switch (BaseShape.HollowShape)
{ {
case HollowShape.Square: case HollowShape.Square:
@ -1245,13 +1246,14 @@ public sealed class BSPrim : BSPhysObject
FillShapeInfo(out shapeData); FillShapeInfo(out shapeData);
// If this prim is part of a linkset, we must remove and restore the physical // If this prim is part of a linkset, we must remove and restore the physical
// links of the body is rebuilt. // links if the body is rebuilt.
bool needToRestoreLinkset = false; bool needToRestoreLinkset = false;
// Create the correct physical representation for this type of object. // Create the correct physical representation for this type of object.
// Updates BSBody and BSShape with the new information. // Updates BSBody and BSShape with the new information.
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, // Returns 'true' if either the body or the shape was changed.
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
null, delegate(BulletBody dBody) null, delegate(BulletBody dBody)
{ {
// Called if the current prim body is about to be destroyed. // Called if the current prim body is about to be destroyed.
@ -1354,7 +1356,7 @@ public sealed class BSPrim : BSPhysObject
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
// BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr); // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
base.RequestPhysicsterseUpdate(); base.RequestPhysicsterseUpdate();
} }
@ -1367,8 +1369,8 @@ public sealed class BSPrim : BSPhysObject
entprop.Acceleration, entprop.RotationalVelocity); entprop.Acceleration, entprop.RotationalVelocity);
} }
*/ */
// The linkset implimentation might want to know about this.
// The linkset implimentation might want to know about this.
Linkset.UpdateProperties(this); Linkset.UpdateProperties(this);
} }
} }

View File

@ -320,7 +320,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
m_log.Debug("[BULLETS UNMANAGED]:" + msg); m_log.Debug("[BULLETS UNMANAGED]:" + msg);
} }
// Called directly from unmanaged code so don't do much // Called directly from unmanaged code so don't do much
private void BulletLoggerPhysLog(string msg) private void BulletLoggerPhysLog(string msg)
{ {
@ -545,7 +545,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
// This is a kludge to get avatar movement updates. // This is a kludge to get avatar movement updates.
// The simulator expects collisions for avatars even if there are have been no collisions. // The simulator expects collisions for avatars even if there are have been no collisions.
// The event updates avatar animations and stuff. // The event updates avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen. // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
foreach (BSPhysObject bsp in m_avatars) foreach (BSPhysObject bsp in m_avatars)
@ -692,7 +692,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
{ {
// swizzle a new list into the list location so we can process what's there
int taintCount = m_taintsToProcessPerStep; int taintCount = m_taintsToProcessPerStep;
TaintCallbackEntry oneCallback = new TaintCallbackEntry(); TaintCallbackEntry oneCallback = new TaintCallbackEntry();
while (_taintedObjects.Count > 0 && taintCount-- > 0) while (_taintedObjects.Count > 0 && taintCount-- > 0)
@ -711,11 +710,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
try try
{ {
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
oneCallback.callback(); oneCallback.callback();
} }
catch (Exception e) catch (Exception e)
{ {
DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
} }
} }
@ -1333,7 +1333,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Add the Flush() if debugging crashes to get all the messages written out. // Add the Flush() if debugging crashes to get all the messages written out.
// PhysicsLogging.Flush(); // PhysicsLogging.Flush();
} }
// used to fill in the LocalID when there isn't one // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
public const string DetailLogZero = "0000000000"; public const string DetailLogZero = "0000000000";
} }

View File

@ -36,7 +36,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSShapeCollection : IDisposable public class BSShapeCollection : IDisposable
{ {
// private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
protected BSScene PhysicsScene { get; set; } protected BSScene PhysicsScene { get; set; }
@ -89,7 +89,7 @@ public class BSShapeCollection : IDisposable
// higher level dependencies on the shape or body. Mostly used for LinkSets to // higher level dependencies on the shape or body. Mostly used for LinkSets to
// remove the physical constraints before the body is destroyed. // remove the physical constraints before the body is destroyed.
// Called at taint-time!! // Called at taint-time!!
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
ShapeData shapeData, PrimitiveBaseShape pbs, ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
{ {
@ -105,7 +105,7 @@ public class BSShapeCollection : IDisposable
// If we had to select a new shape geometry for the object, // If we had to select a new shape geometry for the object,
// rebuild the body around it. // rebuild the body around it.
// Updates prim.BSBody with information/pointers to requested body // Updates prim.BSBody with information/pointers to requested body
bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
prim.BSShape, shapeData, bodyCallback); prim.BSShape, shapeData, bodyCallback);
ret = newGeom || newBody; ret = newGeom || newBody;
} }
@ -325,7 +325,7 @@ public class BSShapeCollection : IDisposable
// Info in prim.BSShape is updated to the new shape. // Info in prim.BSShape is updated to the new shape.
// Returns 'true' if the geometry was rebuilt. // Returns 'true' if the geometry was rebuilt.
// Called at taint-time! // Called at taint-time!
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
{ {
bool ret = false; bool ret = false;
@ -335,9 +335,10 @@ public class BSShapeCollection : IDisposable
if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{ {
// an avatar capsule is close to a native shape (it is not shared) // an avatar capsule is close to a native shape (it is not shared)
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
ret = true;
haveShape = true; haveShape = true;
} }
// If the prim attributes are simple, this could be a simple Bullet native shape // If the prim attributes are simple, this could be a simple Bullet native shape
@ -362,7 +363,7 @@ public class BSShapeCollection : IDisposable
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
) )
{ {
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape); prim.LocalID, forceRebuild, prim.BSShape);
@ -376,7 +377,7 @@ public class BSShapeCollection : IDisposable
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
) )
{ {
ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape); prim.LocalID, forceRebuild, prim.BSShape);
@ -411,39 +412,49 @@ public class BSShapeCollection : IDisposable
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
ShapeDestructionCallback shapeCallback) ShapeDestructionCallback shapeCallback)
{ {
// release any previous shape
DereferenceShape(prim.BSShape, true, shapeCallback);
shapeData.Type = shapeType; shapeData.Type = shapeType;
// Bullet native objects are scaled by the Bullet engine so pass the size in // Bullet native objects are scaled by the Bullet engine so pass the size in
prim.Scale = shapeData.Size; prim.Scale = shapeData.Size;
shapeData.Scale = shapeData.Size; shapeData.Scale = shapeData.Size;
// release any previous shape
DereferenceShape(prim.BSShape, true, shapeCallback);
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared. // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
shapeData.ID, newShape, shapeData.Scale); shapeData.ID, newShape, shapeData.Scale);
prim.BSShape = newShape; prim.BSShape = newShape;
return true; return true;
} }
private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
{ {
BulletShape newShape; BulletShape newShape;
// Need to make sure the passed shape information is for the native type.
ShapeData nativeShapeData = shapeData;
nativeShapeData.Type = shapeType;
nativeShapeData.MeshKey = (ulong)shapeKey;
nativeShapeData.HullKey = (ulong)shapeKey;
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
{ {
newShape = new BulletShape( newShape = new BulletShape(
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
shapeType); , shapeType);
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
} }
else else
{ {
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
}
if (newShape.ptr == IntPtr.Zero)
{
PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
LogHeader, nativeShapeData.ID, nativeShapeData.Type);
} }
newShape.shapeKey = (System.UInt64)shapeKey; newShape.shapeKey = (System.UInt64)shapeKey;
newShape.isNativeShape = true; newShape.isNativeShape = true;
@ -698,19 +709,26 @@ public class BSShapeCollection : IDisposable
return ComputeShapeKey(shapeData, pbs, out lod); return ComputeShapeKey(shapeData, pbs, out lod);
} }
// The creation of a mesh or hull can fail if an underlying asset is not available.
// There are two cases: 1) the asset is not in the cache and it needs to be fetched;
// and 2) the asset cannot be converted (like decompressing JPEG2000s).
// The first case causes the asset to be fetched. The second case just requires
// us to not loop forever.
// Called after creating a physical mesh or hull. If the physical shape was created,
// just return.
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
{ {
// If the shape was successfully created, nothing more to do // If the shape was successfully created, nothing more to do
if (newShape.ptr != IntPtr.Zero) if (newShape.ptr != IntPtr.Zero)
return newShape; return newShape;
// The most common reason for failure is that an underlying asset is not available
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
{ {
prim.LastAssetBuildFailed = true; prim.LastAssetBuildFailed = true;
BSPhysObject xprim = prim; BSPhysObject xprim = prim;
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
Util.FireAndForget(delegate Util.FireAndForget(delegate
{ {
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@ -724,20 +742,28 @@ public class BSShapeCollection : IDisposable
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
return; return;
yprim.BaseShape.SculptData = new byte[asset.Data.Length]; yprim.BaseShape.SculptData = asset.Data;
asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
// This will cause the prim to see that the filler shape is not the right // This will cause the prim to see that the filler shape is not the right
// one and try again to build the object. // one and try again to build the object.
// No race condition with the native sphere setting since the rebuild is at taint time.
yprim.ForceBodyShapeRebuild(false); yprim.ForceBodyShapeRebuild(false);
}); });
} }
}); });
} }
else
{
if (prim.LastAssetBuildFailed)
{
PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
LogHeader, shapeData.ID, pbs.SculptTexture);
}
}
// While we figure out the real problem, stick a simple native shape on the object. // While we figure out the real problem, stick a simple native shape on the object.
BulletShape fillinShape = BulletShape fillinShape =
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
return fillinShape; return fillinShape;
} }
@ -746,7 +772,7 @@ public class BSShapeCollection : IDisposable
// Updates prim.BSBody with the information about the new body if one is created. // Updates prim.BSBody with the information about the new body if one is created.
// Returns 'true' if an object was actually created. // Returns 'true' if an object was actually created.
// Called at taint-time. // Called at taint-time.
private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
ShapeData shapeData, BodyDestructionCallback bodyCallback) ShapeData shapeData, BodyDestructionCallback bodyCallback)
{ {
bool ret = false; bool ret = false;
@ -765,7 +791,6 @@ public class BSShapeCollection : IDisposable
// If the collisionObject is not the correct type for solidness, rebuild what's there // If the collisionObject is not the correct type for solidness, rebuild what's there
mustRebuild = true; mustRebuild = true;
} }
} }
if (mustRebuild || forceRebuild) if (mustRebuild || forceRebuild)

View File

@ -201,9 +201,7 @@ public class BSTerrainManager
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
// terrain shape is created and added to the body. // terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain. // This call is most often used to update the heightMap and parameters of the terrain.
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when // (The above does suggest that some simplification/refactoring is in order.)
// calling this routine from initialization or taint-time routines) or whether to delay
// all the unmanaged activities to taint-time.
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{ {
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
@ -335,8 +333,8 @@ public class BSTerrainManager
// Make sure the new shape is processed. // Make sure the new shape is processed.
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING); // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
// BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
m_terrainModified = true; m_terrainModified = true;
}; };

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.