diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 0bac2470f5..3136ee82e9 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -307,7 +307,7 @@ namespace OpenSim.Framework.Monitoring if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); - if (request.ContainsKey("stat")) pStatName = request["cat"].ToString(); + if (request.ContainsKey("stat")) pStatName = request["stat"].ToString(); string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 9daf9d75ad..ff4afbf90e 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -66,6 +66,7 @@ public class ExtendedPhysics : INonSharedRegionModule public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType"; public const string PhysFunctGetLinkType = "BulletSim.GetLinkType"; public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams"; + public const string PhysFunctAxisLockLimits = "BulletSim.AxisLockLimits"; // ============================================================= @@ -176,6 +177,71 @@ public class ExtendedPhysics : INonSharedRegionModule return ret; } + // Code for specifying params. + // The choice if 14700 is arbitrary and only serves to catch parameter code misuse. + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR = 14700; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR_X = 14701; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_LINEAR_X = 14702; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR_Y = 14703; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_LINEAR_Y = 14704; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR_Z = 14705; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_LINEAR_Z = 14706; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR = 14707; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR_X = 14708; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_ANGULAR_X = 14709; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR_Y = 14710; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_ANGULAR_Y = 14711; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR_Z = 14712; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_ANGULAR_Z = 14713; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR = 14714; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR_X = 14715; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR_Y = 14716; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR_Z = 14717; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR = 14718; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR_X = 14719; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR_Y = 14720; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR_Z = 14721; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK = 14722; + // physAxisLockLimits() + [ScriptInvocation] + public int physAxisLock(UUID hostID, UUID scriptID, object[] parms) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + if (GetRootPhysActor(hostID, out rootPhysActor)) + { + object[] parms2 = AddToBeginningOfArray(rootPhysActor, null, parms); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctAxisLockLimits, parms2)); + } + + return ret; + } + [ScriptConstant] public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0; [ScriptConstant] @@ -187,7 +253,6 @@ public class ExtendedPhysics : INonSharedRegionModule public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) { int ret = -1; - if (!Enabled) return ret; // The part that is requesting the change. @@ -259,34 +324,11 @@ public class ExtendedPhysics : INonSharedRegionModule int ret = -1; if (!Enabled) return ret; - // The part that is requesting the change. - SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); - - if (requestingPart != null) + PhysicsActor rootPhysActor; + if (GetRootPhysActor(hostID, out rootPhysActor)) { - // The type is is always on the root of a linkset. - SceneObjectGroup containingGroup = requestingPart.ParentGroup; - SceneObjectPart rootPart = containingGroup.RootPart; - - if (rootPart != null) - { - PhysicsActor rootPhysActor = rootPart.PhysActor; - if (rootPhysActor != null) - { - object[] parms2 = { rootPhysActor, null }; - ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2)); - } - else - { - m_log.WarnFormat("{0} physGetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}", - LogHeader, rootPart.Name, hostID); - } - } - else - { - m_log.WarnFormat("{0} physGetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}", - LogHeader, requestingPart.Name, hostID); - } + object[] parms2 = { rootPhysActor, null }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2)); } else { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index 7e610075ee..48cab64b15 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs @@ -37,12 +37,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin public class BSActorLockAxis : BSActor { BSConstraint LockAxisConstraint = null; + // The lock access flags (which axises were locked) when the contraint was built. + // Used to see if locking has changed since when the constraint was built. + OMV.Vector3 LockAxisLinearFlags; + OMV.Vector3 LockAxisAngularFlags; public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); LockAxisConstraint = null; + + // we place our constraint just before the simulation step to make sure the linkset is complete + m_physicsScene.BeforeStep += PhysicsScene_BeforeStep; } // BSActor.isActive @@ -55,6 +62,7 @@ public class BSActorLockAxis : BSActor // BSActor.Dispose() public override void Dispose() { + m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep; RemoveAxisLockConstraint(); } @@ -63,10 +71,18 @@ public class BSActorLockAxis : BSActor // BSActor.Refresh() public override void Refresh() { - m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", - m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive); + // Since the axis logging is done with a constraint, Refresh() time is good for + // changing parameters but this needs to wait until the prim/linkset is physically + // constructed. Therefore, the constraint itself is placed at pre-step time. + /* + m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedLinear={1},lockedAngular={2},enabled={3},pActive={4}", + m_controllingPrim.LocalID, + m_controllingPrim.LockedLinearAxis, + m_controllingPrim.LockedAngularAxis, + Enabled, m_controllingPrim.IsPhysicallyActive); // If all the axis are free, we don't need to exist - if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree) + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree + && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) { Enabled = false; } @@ -74,12 +90,21 @@ public class BSActorLockAxis : BSActor // If the object is physically active, add the axis locking constraint if (isActive) { + // Check to see if the locking parameters have changed + if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags + || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags) + { + // The locking has changed. Remove the old constraint and build a new one + RemoveAxisLockConstraint(); + } + AddAxisLockConstraint(); } else { RemoveAxisLockConstraint(); } + */ } // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). @@ -88,15 +113,35 @@ public class BSActorLockAxis : BSActor // BSActor.RemoveDependencies() public override void RemoveDependencies() { - if (LockAxisConstraint != null) + RemoveAxisLockConstraint(); + // The pre-step action will restore the constraint of needed + } + + private void PhysicsScene_BeforeStep(float timestep) + { + // If all the axis are free, we don't need to exist + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree + && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) { - // If a constraint is set up, remove it from the physical scene - RemoveAxisLockConstraint(); - // Schedule a call before the next simulation step to restore the constraint. - m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate() + Enabled = false; + } + + // If the object is physically active, add the axis locking constraint + if (isActive) + { + // Check to see if the locking parameters have changed + if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags + || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags) { - Refresh(); - }); + // The locking has changed. Remove the old constraint and build a new one + RemoveAxisLockConstraint(); + } + + AddAxisLockConstraint(); + } + else + { + RemoveAxisLockConstraint(); } } @@ -118,56 +163,30 @@ public class BSActorLockAxis : BSActor LockAxisConstraint = axisConstrainer; m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); + // Remember the clocking being inforced so we can notice if they have changed + LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis; + LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis; + // The constraint is tied to the world and oriented to the prim. - // Free to move linearly in the region - // OMV.Vector3 linearLow = OMV.Vector3.Zero; - // OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; - OMV.Vector3 linearLow = new OMV.Vector3(-10000f, -10000f, -10000f); - OMV.Vector3 linearHigh = new OMV.Vector3(10000f, 10000f, 10000f); - if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis) + if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh)) { - linearLow.X = m_controllingPrim.RawPosition.X; - linearHigh.X = m_controllingPrim.RawPosition.X; + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits", + m_controllingPrim.LocalID); } - if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis) - { - linearLow.Y = m_controllingPrim.RawPosition.Y; - linearHigh.Y = m_controllingPrim.RawPosition.Y; - } - if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis) - { - linearLow.Z = m_controllingPrim.RawPosition.Z; - linearHigh.Z = m_controllingPrim.RawPosition.Z; - } - axisConstrainer.SetLinearLimits(linearLow, linearHigh); - // Angular with some axis locked - float fPI = (float)Math.PI; - OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); - OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); - if (m_controllingPrim.LockedAngularAxis.X != BSPhysObject.FreeAxis) + if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh)) { - angularLow.X = 0f; - angularHigh.X = 0f; - } - if (m_controllingPrim.LockedAngularAxis.Y != BSPhysObject.FreeAxis) - { - angularLow.Y = 0f; - angularHigh.Y = 0f; - } - if (m_controllingPrim.LockedAngularAxis.Z != BSPhysObject.FreeAxis) - { - angularLow.Z = 0f; - angularHigh.Z = 0f; - } - if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) - { - m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", + m_controllingPrim.LocalID); } m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", - m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); + m_controllingPrim.LocalID, + m_controllingPrim.LockedLinearAxisLow, + m_controllingPrim.LockedLinearAxisHigh, + m_controllingPrim.LockedAngularAxisLow, + m_controllingPrim.LockedAngularAxisHigh); // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index b444446010..22b3f3f066 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -201,7 +201,10 @@ public sealed class BSLinksetCompound : BSLinkset if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) { // Find the physical instance of the child - if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) + if (!RebuildScheduled // if rebuilding, let the rebuild do it + && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change + && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned + && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) { // It is possible that the linkset is still under construction and the child is not yet // inserted into the compound shape. A rebuild of the linkset in a pre-step action will diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 2b744a0899..d20d094cab 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -309,11 +309,20 @@ public abstract class BSPhysObject : PhysicsActor // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } - public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free. - public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free. + public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free. + public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free. public const float FreeAxis = 1f; + public const float LockedAxis = 0f; public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free + // If an axis is locked (flagged above) then the limits of that axis are specified here. + // Linear axis limits are relative to the object's starting coordinates. + // Angular limits are limited to -PI to +PI + public OMV.Vector3 LockedLinearAxisLow; + public OMV.Vector3 LockedLinearAxisHigh; + public OMV.Vector3 LockedAngularAxisLow; + public OMV.Vector3 LockedAngularAxisHigh; + // Enable physical actions. Bullet will keep sleeping non-moving physical objects so // they need waking up when parameters are changed. // Called in taint-time!! diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index c88a5c2a5e..5d359e8ffc 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -34,6 +34,7 @@ using OMV = OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.ConvexDecompositionDotNet; +using OpenSim.Region.OptionalModules.Scripting; // for ExtendedPhysics namespace OpenSim.Region.Physics.BulletSPlugin { @@ -95,11 +96,9 @@ public class BSPrim : BSPhysObject _isPhysical = pisPhysical; _isVolumeDetect = false; - // Add a dynamic vehicle to our set of actors that can move this prim. - // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); - _mass = CalculateMass(); + DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs)); // DetailLog("{0},BSPrim.constructor,call", LocalID); // do the actual object creation at taint time PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() @@ -167,6 +166,7 @@ public class BSPrim : BSPhysObject public override PrimitiveBaseShape Shape { set { BaseShape = value; + DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape)); PrimAssetState = PrimAssetCondition.Unknown; ForceBodyShapeRebuild(false); } @@ -285,23 +285,21 @@ public class BSPrim : BSPhysObject { DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); - // "1" means free, "0" means locked - OMV.Vector3 locking = LockedAxisFree; - if (axis.X != 1) locking.X = 0f; - if (axis.Y != 1) locking.Y = 0f; - if (axis.Z != 1) locking.Z = 0f; - LockedAngularAxis = locking; - - EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + if (axis.X != 1) { - return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); - }); - - // Update parameters so the new actor's Refresh() action is called at the right time. - PhysScene.TaintedObject(LocalID, "BSPrim.LockAngularMotion", delegate() + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f); + } + if (axis.Y != 1) { - UpdatePhysicalParameters(); - }); + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f); + } + if (axis.Z != 1) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f); + } + + InitializeAxisActor(); return; } @@ -533,6 +531,12 @@ public class BSPrim : BSPhysObject { return new BSActorSetForce(PhysScene, this, SetForceActorName); }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate() + { + UpdatePhysicalParameters(); + }); } } @@ -766,6 +770,12 @@ public class BSPrim : BSPhysObject return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); }); DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate() + { + UpdatePhysicalParameters(); + }); } } public override OMV.Vector3 Acceleration { @@ -1138,6 +1148,12 @@ public class BSPrim : BSPhysObject { return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate() + { + UpdatePhysicalParameters(); + }); } } @@ -1164,6 +1180,12 @@ public class BSPrim : BSPhysObject { return new BSActorHover(PhysScene, this, HoverActorName); }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate() + { + UpdatePhysicalParameters(); + }); } } @@ -1601,12 +1623,293 @@ public class BSPrim : BSPhysObject object ret = null; switch (pFunct) { + case ExtendedPhysics.PhysFunctAxisLockLimits: + ret = SetAxisLockLimitsExtension(pParams); + break; default: ret = base.Extension(pFunct, pParams); break; } return ret; } + + private void InitializeAxisActor() + { + EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree, + LockedAxisActorName, delegate() + { + return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); + }); + + // Update parameters so the new actor's Refresh() action is called at the right time. + PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate() + { + UpdatePhysicalParameters(); + }); + } + + // Passed an array of an array of parameters, set the axis locking. + // This expects an int (PHYS_AXIS_*) followed by none or two limit floats + // followed by another int and floats, etc. + private object SetAxisLockLimitsExtension(object[] pParams) + { + DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0)); + object ret = null; + try + { + if (pParams.GetLength(0) > 1) + { + int index = 2; + while (index < pParams.GetLength(0)) + { + var funct = pParams[index]; + DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index); + if (funct is Int32 || funct is Int64) + { + switch ((int)funct) + { + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z, 0f, 0f); + index += 1; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK, 0f, 0f); + index += 1; + break; + default: + m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct); + index += 1; + break; + } + } + } + InitializeAxisActor(); + ret = (object)index; + } + } + catch (Exception e) + { + m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e); + ret = null; + } + return ret; // not implemented yet + } + + // Set the locking parameters. + // If an axis is locked, the limits for the axis are set to zero, + // If the axis is being constrained, the high and low value are passed and set. + // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range. + protected void ApplyAxisLimits(int funct, float low, float high) + { + DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high); + float linearMax = 23000f; + float angularMax = (float)Math.PI; + + switch ((int)funct) + { + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: + this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); + this.LockedLinearAxisLow = OMV.Vector3.Zero; + this.LockedLinearAxisHigh = OMV.Vector3.Zero; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: + this.LockedLinearAxis.X = LockedAxis; + this.LockedLinearAxisLow.X = 0f; + this.LockedLinearAxisHigh.X = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: + this.LockedLinearAxis.X = LockedAxis; + this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: + this.LockedLinearAxis.Y = LockedAxis; + this.LockedLinearAxisLow.Y = 0f; + this.LockedLinearAxisHigh.Y = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: + this.LockedLinearAxis.Y = LockedAxis; + this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: + this.LockedLinearAxis.Z = LockedAxis; + this.LockedLinearAxisLow.Z = 0f; + this.LockedLinearAxisHigh.Z = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: + this.LockedLinearAxis.Z = LockedAxis; + this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: + this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); + this.LockedAngularAxisLow = OMV.Vector3.Zero; + this.LockedAngularAxisHigh = OMV.Vector3.Zero; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: + this.LockedAngularAxis.X = LockedAxis; + this.LockedAngularAxisLow.X = 0; + this.LockedAngularAxisHigh.X = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: + this.LockedAngularAxis.X = LockedAxis; + this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: + this.LockedAngularAxis.Y = LockedAxis; + this.LockedAngularAxisLow.Y = 0; + this.LockedAngularAxisHigh.Y = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: + this.LockedAngularAxis.Y = LockedAxis; + this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: + this.LockedAngularAxis.Z = LockedAxis; + this.LockedAngularAxisLow.Z = 0; + this.LockedAngularAxisHigh.Z = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: + this.LockedAngularAxis.Z = LockedAxis; + this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: + this.LockedLinearAxis = LockedAxisFree; + this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax); + this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: + this.LockedLinearAxis.X = FreeAxis; + this.LockedLinearAxisLow.X = -linearMax; + this.LockedLinearAxisHigh.X = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: + this.LockedLinearAxis.Y = FreeAxis; + this.LockedLinearAxisLow.Y = -linearMax; + this.LockedLinearAxisHigh.Y = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: + this.LockedLinearAxis.Z = FreeAxis; + this.LockedLinearAxisLow.Z = -linearMax; + this.LockedLinearAxisHigh.Z = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: + this.LockedAngularAxis = LockedAxisFree; + this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax); + this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: + this.LockedAngularAxis.X = FreeAxis; + this.LockedAngularAxisLow.X = -angularMax; + this.LockedAngularAxisHigh.X = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: + this.LockedAngularAxis.Y = FreeAxis; + this.LockedAngularAxisLow.Y = -angularMax; + this.LockedAngularAxisHigh.Y = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: + this.LockedAngularAxis.Z = FreeAxis; + this.LockedAngularAxisLow.Z = -angularMax; + this.LockedAngularAxisHigh.Z = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f); + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + break; + default: + break; + } + return; + } #endregion // Extension // The physics engine says that properties have updated. Update same and inform diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 414bc92a0b..238fcc2adf 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -947,6 +947,73 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters } #endregion // Extensions + public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs) + { + float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f; + float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f; + float pathBegin = (float)pbs.PathBegin * 2.0e-5f; + float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f; + float pathScaleX = (float)(pbs.PathScaleX - 100) * 0.01f; + float pathScaleY = (float)(pbs.PathScaleY - 100) * 0.01f; + + float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f; + float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f; + float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f; + if (profileHollow > 0.95f) + profileHollow = 0.95f; + + StringBuilder buff = new StringBuilder(); + buff.Append("shape="); + buff.Append(((ProfileShape)pbs.ProfileShape).ToString()); + buff.Append(","); + buff.Append("hollow="); + buff.Append(((HollowShape)pbs.HollowShape).ToString()); + buff.Append(","); + buff.Append("pathCurve="); + buff.Append(((Extrusion)pbs.PathCurve).ToString()); + buff.Append(","); + buff.Append("profCurve="); + buff.Append(((Extrusion)pbs.ProfileCurve).ToString()); + buff.Append(","); + buff.Append("profHollow="); + buff.Append(profileHollow.ToString()); + buff.Append(","); + buff.Append("pathBegEnd="); + buff.Append(pathBegin.ToString()); + buff.Append("/"); + buff.Append(pathEnd.ToString()); + buff.Append(","); + buff.Append("profileBegEnd="); + buff.Append(profileBegin.ToString()); + buff.Append("/"); + buff.Append(profileEnd.ToString()); + buff.Append(","); + buff.Append("scaleXY="); + buff.Append(pathScaleX.ToString()); + buff.Append("/"); + buff.Append(pathScaleY.ToString()); + buff.Append(","); + buff.Append("shearXY="); + buff.Append(pathShearX.ToString()); + buff.Append("/"); + buff.Append(pathShearY.ToString()); + buff.Append(","); + buff.Append("taperXY="); + buff.Append(pbs.PathTaperX.ToString()); + buff.Append("/"); + buff.Append(pbs.PathTaperY.ToString()); + buff.Append(","); + buff.Append("skew="); + buff.Append(pbs.PathSkew.ToString()); + buff.Append(","); + buff.Append("twist/Beg="); + buff.Append(pbs.PathTwist.ToString()); + buff.Append("/"); + buff.Append(pbs.PathTwistBegin.ToString()); + + return buff.ToString(); + } + #region Taints // The simulation execution order is: // Simulate() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 09f5bc44ba..aa04726109 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -38,6 +38,76 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { +// Information class that holds stats for the shape. Which values mean +// something depends on the type of shape. +// This information is used for debugging and stats and is not used +// for operational things. +public class ShapeInfoInfo +{ + public int Vertices { get; set; } + private int m_hullCount; + private int[] m_verticesPerHull; + public ShapeInfoInfo() + { + Vertices = 0; + m_hullCount = 0; + m_verticesPerHull = null; + } + public int HullCount + { + set + { + m_hullCount = value; + m_verticesPerHull = new int[m_hullCount]; + Array.Clear(m_verticesPerHull, 0, m_hullCount); + } + get { return m_hullCount; } + } + public void SetVerticesPerHull(int hullNum, int vertices) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + m_verticesPerHull[hullNum] = vertices; + } + } + public int GetVerticesPerHull(int hullNum) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + return m_verticesPerHull[hullNum]; + } + return 0; + } + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + // buff.Append("ShapeInfo=<"); + buff.Append("<"); + if (Vertices > 0) + { + buff.Append("verts="); + buff.Append(Vertices.ToString()); + } + + if (Vertices > 0 && HullCount > 0) buff.Append(","); + + if (HullCount > 0) + { + buff.Append("nHulls="); + buff.Append(HullCount.ToString()); + buff.Append(","); + buff.Append("hullVerts="); + for (int ii = 0; ii < HullCount; ii++) + { + if (ii != 0) buff.Append(","); + buff.Append(GetVerticesPerHull(ii).ToString()); + } + } + buff.Append(">"); + return buff.ToString(); + } +} + public abstract class BSShape { private static string LogHeader = "[BULLETSIM SHAPE]"; @@ -45,18 +115,21 @@ public abstract class BSShape public int referenceCount { get; set; } public DateTime lastReferenced { get; set; } public BulletShape physShapeInfo { get; set; } + public ShapeInfoInfo shapeInfo { get; private set; } public BSShape() { referenceCount = 1; lastReferenced = DateTime.Now; physShapeInfo = new BulletShape(); + shapeInfo = new ShapeInfoInfo(); } public BSShape(BulletShape pShape) { referenceCount = 1; lastReferenced = DateTime.Now; physShapeInfo = pShape; + shapeInfo = new ShapeInfoInfo(); } // Get another reference to this shape. @@ -283,6 +356,9 @@ public class BSShapeNull : BSShape } // ============================================================================================================ +// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere. +// They are odd in that they don't allocate meshes but are computated/procedural. +// This means allocation and freeing is different than meshes. public class BSShapeNative : BSShape { private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; @@ -361,6 +437,7 @@ public class BSShapeNative : BSShape } // ============================================================================================================ +// BSShapeMesh is a simple mesh. public class BSShapeMesh : BSShape { private static string LogHeader = "[BULLETSIM SHAPE MESH]"; @@ -457,7 +534,11 @@ public class BSShapeMesh : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, - (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) ); + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); + }); } // Code that uses the mesher to create the index/vertices info for a trimesh shape. @@ -545,6 +626,9 @@ public class BSShapeMesh : BSShape } // ============================================================================================================ +// BSShapeHull is a physical shape representation htat is made up of many convex hulls. +// The convex hulls are either supplied with the asset or are approximated by one of the +// convex hull creation routines (in OpenSim or in Bullet). public class BSShapeHull : BSShape { #pragma warning disable 414 @@ -553,6 +637,7 @@ public class BSShapeHull : BSShape public static Dictionary Hulls = new Dictionary(); + public BSShapeHull(BulletShape pShape) : base(pShape) { } @@ -615,6 +700,7 @@ public class BSShapeHull : BSShape // TODO: schedule aging and destruction of unused meshes. } } + List m_hulls; private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) @@ -647,6 +733,7 @@ public class BSShapeHull : BSShape if (allHulls != null && BSParam.ShouldUseAssetHulls) { int hullCount = allHulls.Count; + shapeInfo.HullCount = hullCount; int totalVertices = 1; // include one for the count of the hulls // Using the structure described for HACD hulls, create the memory sturcture // to pass the hull data to the creater. @@ -659,6 +746,7 @@ public class BSShapeHull : BSShape convHulls[0] = (float)hullCount; int jj = 1; + int hullIndex = 0; foreach (List hullVerts in allHulls) { convHulls[jj + 0] = hullVerts.Count; @@ -673,6 +761,8 @@ public class BSShapeHull : BSShape convHulls[jj + 2] = oneVert.Z; jj += 3; } + shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); + hullIndex++; } // create the hull data structure in Bullet @@ -708,6 +798,10 @@ public class BSShapeHull : BSShape physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); // Now done with the mesh shape. + shapeInfo.HullCount = 1; + BSShapeMesh maybeMesh = meshShape as BSShapeMesh; + if (maybeMesh != null) + shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); meshShape.Dereference(physicsScene); } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); @@ -857,6 +951,8 @@ public class BSShapeHull : BSShape } // ============================================================================================================ +// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate +// meshes. Used by BulletSim for complex shapes like linksets. public class BSShapeCompound : BSShape { private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; @@ -999,6 +1095,9 @@ public class BSShapeCompound : BSShape } // ============================================================================================================ +// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex +// hull shapes. This is used for simple prims that are convex and thus can be made into a simple +// collision shape (a single hull). More complex physical shapes will be BSShapeHull's. public class BSShapeConvexHull : BSShape { #pragma warning disable 414 @@ -1098,6 +1197,9 @@ public class BSShapeConvexHull : BSShape } } // ============================================================================================================ +// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that +// can handle concave as well as convex shapes. Much slower computationally but creates smoother +// shapes than multiple convex hull approximations. public class BSShapeGImpact : BSShape { #pragma warning disable 414 @@ -1151,7 +1253,11 @@ public class BSShapeGImpact : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, - (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) ); + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v); + }); } public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) @@ -1206,6 +1312,7 @@ public class BSShapeGImpact : BSShape } // ============================================================================================================ +// BSShapeAvatar is a specialized mesh shape for avatars. public class BSShapeAvatar : BSShape { #pragma warning disable 414 diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs index 28207a43ab..775bca213c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs @@ -28,15 +28,16 @@ using System; using System.IO; using System.Collections.Generic; -using System.Linq; using System.Text; using Nini.Config; using OpenSim.Framework; -using OpenSim.Region.Physics.BulletSPlugin; +using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Meshing; +using OpenMetaverse; + namespace OpenSim.Region.Physics.BulletSPlugin.Tests { // Utility functions for building up and tearing down the sample physics environments @@ -77,17 +78,21 @@ public static class BulletSimTestsUtil bulletSimConfig.Set("VehicleLoggingEnabled","True"); } - BSPlugin bsPlugin = new BSPlugin(); + PhysicsPluginManager physicsPluginManager; + physicsPluginManager = new PhysicsPluginManager(); + physicsPluginManager.LoadPluginsFromAssemblies("Physics"); - BSScene bsScene = (BSScene)bsPlugin.GetScene("BSTestRegion"); + Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + PhysicsScene pScene = physicsPluginManager.GetPhysicsScene( + "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent); + + BSScene bsScene = pScene as BSScene; // Since the asset requestor is not initialized, any mesh or sculptie will be a cube. // In the future, add a fake asset fetcher to get meshes and sculpts. // bsScene.RequestAssetMethod = ???; - Meshing.Meshmerizer mesher = new Meshmerizer(openSimINI); - bsScene.Initialise(mesher, openSimINI); - return bsScene; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs new file mode 100644 index 0000000000..4bec062fe7 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs @@ -0,0 +1,204 @@ +/* + * 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 copyright + * 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.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Framework; +using OpenSim.Region.Physics.BulletSPlugin; +using OpenSim.Region.Physics.Manager; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin.Tests +{ +[TestFixture] +public class HullCreation : OpenSimTestCase +{ + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene PhysicsScene { get; set; } + Vector3 ObjectInitPosition; + float simulationTimeStep = 0.089f; + + [TestFixtureSetUp] + public void Init() + { + + } + + [TestFixtureTearDown] + public void TearDown() + { + if (PhysicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + PhysicsScene.Dispose(); + PhysicsScene = null; + } + } + + [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */ + public void GeomHullConvexDecomp( int maxDepthSplit, + int maxDepthSplitForSimpleShapes, + float concavityThresholdPercent, + float volumeConservationThresholdPercent, + int maxVertices, + float maxSkinWidth) + { + // Setup the physics engine to use the C# version of convex decomp + Dictionary engineParams = new Dictionary(); + engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim + engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing + engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects + engineParams.Add("ShouldRemoveZeroWidthTriangles", "true"); + engineParams.Add("ShouldUseBulletHACD", "false"); + engineParams.Add("ShouldUseSingleConvexHullForPrims", "true"); + engineParams.Add("ShouldUseGImpactShapeForPrims", "false"); + engineParams.Add("ShouldUseAssetHulls", "true"); + + engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString()); + engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString()); + engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString()); + engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString()); + engineParams.Add("CSHullMaxVertices", maxVertices.ToString()); + engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString()); + + PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs; + Vector3 pos; + Vector3 size; + Quaternion rot; + bool isPhys; + + // Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pos = new Vector3(100.0f, 100.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint cylinderLocalID = 123; + PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID); + BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID]; + + // Hollow Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pbs.ProfileHollow = (ushort)(0.70f * 50000); + pos = new Vector3(110.0f, 110.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint hollowCylinderLocalID = 124; + PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID); + BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID]; + + // Torus + // ProfileCurve = Circle, PathCurve = Curve1 + pbs = PrimitiveBaseShape.CreateSphere(); + pbs.ProfileShape = (byte)ProfileShape.Circle; + pbs.PathCurve = (byte)Extrusion.Curve1; + pos = new Vector3(120.0f, 120.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 4f, 4f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint torusLocalID = 125; + PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID); + BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID]; + + // The actual prim shape creation happens at taint time + PhysicsScene.ProcessTaints(); + + // Check out the created hull shapes and report their characteristics + ReportShapeGeom(primTypeCylinder); + ReportShapeGeom(primTypeHollowCylinder); + ReportShapeGeom(primTypeTorus); + } + + [TestCase] + public void GeomHullBulletHACD() + { + // Cylinder + // Hollow Cylinder + // Torus + } + + private void ReportShapeGeom(BSPrim prim) + { + if (prim != null) + { + if (prim.PhysShape.HasPhysicalShape) + { + BSShape physShape = prim.PhysShape; + string shapeType = physShape.GetType().ToString(); + switch (shapeType) + { + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative": + BSShapeNative nShape = physShape as BSShapeNative; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh": + BSShapeMesh mShape = physShape as BSShapeMesh; + prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull": + // BSShapeHull hShape = physShape as BSShapeHull; + // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull": + BSShapeConvexHull chShape = physShape as BSShapeConvexHull; + prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound": + BSShapeCompound cShape = physShape as BSShapeCompound; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + default: + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + } + } + } + } +} +} \ No newline at end of file