Merge branch 'master' into careminster
Conflicts: OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.csavinationmerge
commit
95d0a7d4fa
|
@ -33,6 +33,7 @@ using System.Threading;
|
|||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Capabilities;
|
||||
using OpenSim.Framework.Client;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
|
@ -77,6 +78,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
/// </remarks>
|
||||
public bool DisableInterRegionTeleportCancellation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of times inter-region teleport was attempted.
|
||||
/// </summary>
|
||||
private Stat m_interRegionTeleportAttempts;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times inter-region teleport was aborted (due to simultaneous client logout).
|
||||
/// </summary>
|
||||
private Stat m_interRegionTeleportAborts;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times inter-region teleport was successfully cancelled by the client.
|
||||
/// </summary>
|
||||
private Stat m_interRegionTeleportCancels;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
|
||||
/// connect with destination region).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
|
||||
/// destination simulator is unknown.
|
||||
/// </remarks>
|
||||
private Stat m_interRegionTeleportFailures;
|
||||
|
||||
protected bool m_Enabled = false;
|
||||
|
||||
public Scene Scene { get; private set; }
|
||||
|
@ -156,6 +182,60 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
Scene = scene;
|
||||
|
||||
m_interRegionTeleportAttempts =
|
||||
new Stat(
|
||||
"InterRegionTeleportAttempts",
|
||||
"Number of inter-region teleports attempted.",
|
||||
"This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
|
||||
+ "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
|
||||
"",
|
||||
"entitytransfer",
|
||||
Scene.Name,
|
||||
StatType.Push,
|
||||
null,
|
||||
StatVerbosity.Debug);
|
||||
|
||||
m_interRegionTeleportAborts =
|
||||
new Stat(
|
||||
"InterRegionTeleportAborts",
|
||||
"Number of inter-region teleports aborted due to client actions.",
|
||||
"The chief action is simultaneous logout whilst teleporting.",
|
||||
"",
|
||||
"entitytransfer",
|
||||
Scene.Name,
|
||||
StatType.Push,
|
||||
null,
|
||||
StatVerbosity.Debug);
|
||||
|
||||
m_interRegionTeleportCancels =
|
||||
new Stat(
|
||||
"InterRegionTeleportCancels",
|
||||
"Number of inter-region teleports cancelled by the client.",
|
||||
null,
|
||||
"",
|
||||
"entitytransfer",
|
||||
Scene.Name,
|
||||
StatType.Push,
|
||||
null,
|
||||
StatVerbosity.Debug);
|
||||
|
||||
m_interRegionTeleportFailures =
|
||||
new Stat(
|
||||
"InterRegionTeleportFailures",
|
||||
"Number of inter-region teleports that failed due to server/client/network issues.",
|
||||
"This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
|
||||
"",
|
||||
"entitytransfer",
|
||||
Scene.Name,
|
||||
StatType.Push,
|
||||
null,
|
||||
StatVerbosity.Debug);
|
||||
|
||||
StatsManager.RegisterStat(m_interRegionTeleportAttempts);
|
||||
StatsManager.RegisterStat(m_interRegionTeleportAborts);
|
||||
StatsManager.RegisterStat(m_interRegionTeleportCancels);
|
||||
StatsManager.RegisterStat(m_interRegionTeleportFailures);
|
||||
|
||||
scene.RegisterModuleInterface<IEntityTransferModule>(this);
|
||||
scene.EventManager.OnNewClient += OnNewClient;
|
||||
}
|
||||
|
@ -173,7 +253,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
public virtual void Close() {}
|
||||
|
||||
public virtual void RemoveRegion(Scene scene) {}
|
||||
public virtual void RemoveRegion(Scene scene)
|
||||
{
|
||||
StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
|
||||
StatsManager.DeregisterStat(m_interRegionTeleportAborts);
|
||||
StatsManager.DeregisterStat(m_interRegionTeleportCancels);
|
||||
StatsManager.DeregisterStat(m_interRegionTeleportFailures);
|
||||
}
|
||||
|
||||
public virtual void RegionLoaded(Scene scene)
|
||||
{
|
||||
|
@ -548,6 +634,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
return;
|
||||
}
|
||||
|
||||
// Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
|
||||
// simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
|
||||
// as server attempts.
|
||||
m_interRegionTeleportAttempts.Value++;
|
||||
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
|
||||
|
||||
// Fixing a bug where teleporting while sitting results in the avatar ending up removed from
|
||||
|
@ -600,6 +691,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
bool logout = false;
|
||||
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
|
||||
{
|
||||
m_interRegionTeleportFailures.Value++;
|
||||
|
||||
sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
|
||||
|
||||
m_log.DebugFormat(
|
||||
|
@ -611,6 +704,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
|
||||
{
|
||||
m_interRegionTeleportCancels.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
@ -619,6 +714,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
}
|
||||
else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
|
||||
{
|
||||
m_interRegionTeleportAborts.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
@ -688,6 +785,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
// establish th econnection to the destination which makes it return true.
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
|
||||
{
|
||||
m_interRegionTeleportAborts.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
@ -703,6 +802,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
{
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
|
||||
{
|
||||
m_interRegionTeleportAborts.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
@ -720,6 +821,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
|
||||
{
|
||||
m_interRegionTeleportCancels.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
@ -755,6 +858,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
{
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
|
||||
{
|
||||
m_interRegionTeleportAborts.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
@ -767,6 +872,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
|
||||
|
||||
Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -808,15 +914,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
// now we have a child agent in this region.
|
||||
sp.Reset();
|
||||
}
|
||||
|
||||
// Commented pending deletion since this method no longer appears to do anything at all
|
||||
// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
|
||||
// if (sp.Scene.NeedSceneCacheClear(sp.UUID))
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
|
||||
// sp.UUID);
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -852,6 +949,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
{
|
||||
CleanupFailedInterRegionTeleport(sp, finalDestination);
|
||||
|
||||
m_interRegionTeleportFailures.Value++;
|
||||
|
||||
sp.ControllingClient.SendTeleportFailed(
|
||||
string.Format(
|
||||
"Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
|
||||
|
|
|
@ -321,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
}
|
||||
}
|
||||
|
||||
internal void ProcessTypeChange(Vehicle pType)
|
||||
public void ProcessTypeChange(Vehicle pType)
|
||||
{
|
||||
VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
|
||||
// Set Defaults For Type
|
||||
|
@ -1301,14 +1301,52 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
// efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
|
||||
public void ComputeAngularVerticalAttraction()
|
||||
{
|
||||
|
||||
// If vertical attaction timescale is reasonable
|
||||
if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
|
||||
{
|
||||
// Possible solution derived from a discussion at:
|
||||
// http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
|
||||
|
||||
// Create a rotation that is only the vehicle's rotation around Z
|
||||
Vector3 currentEuler = Vector3.Zero;
|
||||
VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
|
||||
Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
|
||||
|
||||
// Create the axis that is perpendicular to the up vector and the rotated up vector.
|
||||
Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
|
||||
// Compute the angle between those to vectors.
|
||||
double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
|
||||
// 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
|
||||
|
||||
// Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
|
||||
// TODO: add 'efficiency'.
|
||||
differenceAngle /= m_verticalAttractionTimescale;
|
||||
|
||||
// Create the quaterian representing the correction angle
|
||||
Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
|
||||
|
||||
// Turn that quaternion into Euler values to make it into velocities to apply.
|
||||
Vector3 vertContributionV = Vector3.Zero;
|
||||
correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
|
||||
vertContributionV *= -1f;
|
||||
|
||||
VehicleRotationalVelocity += vertContributionV;
|
||||
|
||||
VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
|
||||
Prim.LocalID,
|
||||
differenceAxis,
|
||||
differenceAngle,
|
||||
correctionRotation,
|
||||
vertContributionV);
|
||||
|
||||
// ===================================================================
|
||||
/*
|
||||
Vector3 vertContributionV = Vector3.Zero;
|
||||
Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
|
||||
|
||||
// Take a vector pointing up and convert it from world to vehicle relative coords.
|
||||
Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
|
||||
Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
|
||||
|
||||
// If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
|
||||
// is now:
|
||||
|
@ -1334,13 +1372,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
// 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
|
||||
// Correction happens over a number of seconds.
|
||||
Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
|
||||
|
||||
// The correction happens over the user's time period
|
||||
vertContributionV /= m_verticalAttractionTimescale;
|
||||
|
||||
VehicleRotationalVelocity += vertContributionV;
|
||||
// Rotate the vehicle rotation to the world coordinates.
|
||||
VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
|
||||
|
||||
VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
|
||||
Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
|
||||
m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -142,6 +142,14 @@ public static class BSParam
|
|||
public static float VehicleAngularBankingTimescaleFudge { get; private set; }
|
||||
public static bool VehicleDebuggingEnabled { get; private set; }
|
||||
|
||||
// Convex Hulls
|
||||
public static int CSHullMaxDepthSplit { get; private set; }
|
||||
public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
|
||||
public static float CSHullConcavityThresholdPercent { get; private set; }
|
||||
public static float CSHullVolumeConservationThresholdPercent { get; private set; }
|
||||
public static int CSHullMaxVertices { get; private set; }
|
||||
public static float CSHullMaxSkinWidth { get; private set; }
|
||||
|
||||
// Linkset implementation parameters
|
||||
public static float LinksetImplementation { get; private set; }
|
||||
public static bool LinkConstraintUseFrameOffset { get; private set; }
|
||||
|
@ -195,10 +203,10 @@ public static class BSParam
|
|||
public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
|
||||
public sealed class ParameterDefn<T> : ParameterDefnBase
|
||||
{
|
||||
T defaultValue;
|
||||
PSetValue<T> setter;
|
||||
PGetValue<T> getter;
|
||||
PSetOnObject<T> objectSet;
|
||||
private T defaultValue;
|
||||
private PSetValue<T> setter;
|
||||
private PGetValue<T> getter;
|
||||
private PSetOnObject<T> objectSet;
|
||||
public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
|
||||
: base(pName, pDesc)
|
||||
{
|
||||
|
@ -215,13 +223,23 @@ public static class BSParam
|
|||
getter = pGetter;
|
||||
objectSet = pObjSetter;
|
||||
}
|
||||
/* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work
|
||||
public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc)
|
||||
: base(pName, pDesc)
|
||||
{
|
||||
defaultValue = pDefault;
|
||||
setter = (s, v) => { loc = v; };
|
||||
getter = (s) => { return loc; };
|
||||
objectSet = null;
|
||||
}
|
||||
*/
|
||||
public override void AssignDefault(BSScene s)
|
||||
{
|
||||
setter(s, defaultValue);
|
||||
}
|
||||
public override string GetValue(BSScene s)
|
||||
{
|
||||
return String.Format("{0}", getter(s));
|
||||
return getter(s).ToString();
|
||||
}
|
||||
public override void SetValue(BSScene s, string valAsString)
|
||||
{
|
||||
|
@ -244,6 +262,7 @@ public static class BSParam
|
|||
try
|
||||
{
|
||||
T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
|
||||
// Store the parsed value
|
||||
setter(s, setValue);
|
||||
// s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
|
||||
}
|
||||
|
@ -623,6 +642,31 @@ public static class BSParam
|
|||
(s) => { return GlobalContactBreakingThreshold; },
|
||||
(s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
|
||||
|
||||
new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
|
||||
7,
|
||||
(s) => { return CSHullMaxDepthSplit; },
|
||||
(s,v) => { CSHullMaxDepthSplit = v; } ),
|
||||
new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
|
||||
2,
|
||||
(s) => { return CSHullMaxDepthSplitForSimpleShapes; },
|
||||
(s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
|
||||
new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
|
||||
5f,
|
||||
(s) => { return CSHullConcavityThresholdPercent; },
|
||||
(s,v) => { CSHullConcavityThresholdPercent = v; } ),
|
||||
new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
|
||||
5f,
|
||||
(s) => { return CSHullVolumeConservationThresholdPercent; },
|
||||
(s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
|
||||
new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
|
||||
32,
|
||||
(s) => { return CSHullMaxVertices; },
|
||||
(s,v) => { CSHullMaxVertices = v; } ),
|
||||
new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
|
||||
0,
|
||||
(s) => { return CSHullMaxSkinWidth; },
|
||||
(s,v) => { CSHullMaxSkinWidth = v; } ),
|
||||
|
||||
new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
|
||||
(float)BSLinkset.LinksetImplementation.Compound,
|
||||
(s) => { return LinksetImplementation; },
|
||||
|
|
|
@ -86,7 +86,7 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
PhysBody = new BulletBody(localID);
|
||||
PhysShape = new BulletShape();
|
||||
|
||||
LastAssetBuildFailed = false;
|
||||
PrimAssetState = PrimAssetCondition.Unknown;
|
||||
|
||||
// Default material type. Also sets Friction, Restitution and Density.
|
||||
SetMaterial((int)MaterialAttributes.Material.Wood);
|
||||
|
@ -133,9 +133,13 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// Reference to the physical shape (btCollisionShape) of this object
|
||||
public BulletShape PhysShape;
|
||||
|
||||
// 'true' if the mesh's underlying asset failed to build.
|
||||
// This will keep us from looping after the first time the build failed.
|
||||
public bool LastAssetBuildFailed { get; set; }
|
||||
// The physical representation of the prim might require an asset fetch.
|
||||
// The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
|
||||
public enum PrimAssetCondition
|
||||
{
|
||||
Unknown, Waiting, Failed, Fetched
|
||||
}
|
||||
public PrimAssetCondition PrimAssetState { get; set; }
|
||||
|
||||
// The objects base shape information. Null if not a prim type shape.
|
||||
public PrimitiveBaseShape BaseShape { get; protected set; }
|
||||
|
|
|
@ -155,7 +155,7 @@ public class BSPrim : BSPhysObject
|
|||
public override PrimitiveBaseShape Shape {
|
||||
set {
|
||||
BaseShape = value;
|
||||
LastAssetBuildFailed = false;
|
||||
PrimAssetState = PrimAssetCondition.Unknown;
|
||||
ForceBodyShapeRebuild(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -447,17 +447,10 @@ public sealed class BSShapeCollection : IDisposable
|
|||
|
||||
// If the prim attributes are simple, this could be a simple Bullet native shape
|
||||
if (!haveShape
|
||||
&& nativeShapePossible
|
||||
&& pbs != null
|
||||
&& !pbs.SculptEntry
|
||||
&& nativeShapePossible
|
||||
&& ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
|
||||
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||
&& pbs.ProfileHollow == 0
|
||||
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
|
||||
&& pbs.PathBegin == 0 && pbs.PathEnd == 0
|
||||
&& pbs.PathTaperX == 0 && pbs.PathTaperY == 0
|
||||
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
|
||||
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
|
||||
&& ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
|
||||
{
|
||||
// Get the scale of any existing shape so we can see if the new shape is same native type and same size.
|
||||
OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
|
||||
|
@ -508,6 +501,18 @@ public sealed class BSShapeCollection : IDisposable
|
|||
return ret;
|
||||
}
|
||||
|
||||
// return 'true' if this shape description does not include any cutting or twisting.
|
||||
private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
|
||||
{
|
||||
return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||
&& pbs.ProfileHollow == 0
|
||||
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
|
||||
&& pbs.PathBegin == 0 && pbs.PathEnd == 0
|
||||
&& pbs.PathTaperX == 0 && pbs.PathTaperY == 0
|
||||
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
|
||||
&& pbs.PathShearX == 0 && pbs.PathShearY == 0;
|
||||
}
|
||||
|
||||
// return 'true' if the prim's shape was changed.
|
||||
public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
|
@ -518,7 +523,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
|
||||
{
|
||||
// Update prim.BSShape to reference a hull of this shape.
|
||||
ret = GetReferenceToHull(prim,shapeCallback);
|
||||
ret = GetReferenceToHull(prim, shapeCallback);
|
||||
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
||||
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||
}
|
||||
|
@ -699,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
|
||||
// See that hull shape exists in the physical world and update prim.BSShape.
|
||||
// We could be creating the hull because scale changed or whatever.
|
||||
// Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
|
||||
private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
@ -717,6 +723,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
DereferenceShape(prim.PhysShape, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
|
||||
// It might not have been created if we're waiting for an asset.
|
||||
newShape = VerifyMeshCreated(newShape, prim);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
@ -735,13 +742,13 @@ public sealed class BSShapeCollection : IDisposable
|
|||
HullDesc hullDesc;
|
||||
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||
{
|
||||
// If the hull shape already is created, just use it.
|
||||
// If the hull shape already has been created, just use the one shared instance.
|
||||
newShape = hullDesc.shape.Clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Build a new hull in the physical world
|
||||
// Pass true for physicalness as this creates some sort of bounding box which we don't need
|
||||
// Build a new hull in the physical world.
|
||||
// Pass true for physicalness as this prevents the creation of bounding box which is not needed
|
||||
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
|
||||
if (meshData != null)
|
||||
{
|
||||
|
@ -761,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
|
|||
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||
}
|
||||
|
||||
uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
|
||||
if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
|
||||
{
|
||||
// Simple primitive shapes we know are convex so they are better implemented with
|
||||
// fewer hulls.
|
||||
// Check for simple shape (prim without cuts) and reduce split parameter if so.
|
||||
if (PrimHasNoCuts(pbs))
|
||||
{
|
||||
maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
|
||||
}
|
||||
}
|
||||
|
||||
// setup and do convex hull conversion
|
||||
m_hulls = new List<ConvexResult>();
|
||||
DecompDesc dcomp = new DecompDesc();
|
||||
dcomp.mIndices = convIndices;
|
||||
dcomp.mVertices = convVertices;
|
||||
dcomp.mDepth = maxDepthSplit;
|
||||
dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
|
||||
dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
|
||||
dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
|
||||
dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
|
||||
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
||||
// create the hull into the _hulls variable
|
||||
convexBuilder.process(dcomp);
|
||||
|
||||
DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
|
||||
BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
|
||||
|
||||
// Convert the vertices and indices for passing to unmanaged.
|
||||
// The hull information is passed as a large floating point array.
|
||||
// The format is:
|
||||
|
@ -905,11 +932,15 @@ public sealed class BSShapeCollection : IDisposable
|
|||
return newShape;
|
||||
|
||||
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
|
||||
if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
|
||||
if (prim.BaseShape.SculptEntry
|
||||
&& prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
|
||||
&& prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
|
||||
&& prim.BaseShape.SculptTexture != OMV.UUID.Zero
|
||||
)
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed);
|
||||
// This will prevent looping through this code as we keep trying to get the failed shape
|
||||
prim.LastAssetBuildFailed = true;
|
||||
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
|
||||
// Multiple requestors will know we're waiting for this asset
|
||||
prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
|
||||
|
||||
BSPhysObject xprim = prim;
|
||||
Util.FireAndForget(delegate
|
||||
|
@ -920,7 +951,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
|
||||
assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
|
||||
{
|
||||
bool assetFound = false; // DEBUG DEBUG
|
||||
bool assetFound = false;
|
||||
string mismatchIDs = String.Empty; // DEBUG DEBUG
|
||||
if (asset != null && yprim.BaseShape.SculptEntry)
|
||||
{
|
||||
|
@ -938,6 +969,10 @@ public sealed class BSShapeCollection : IDisposable
|
|||
mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
|
||||
}
|
||||
}
|
||||
if (assetFound)
|
||||
yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
|
||||
else
|
||||
yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
|
||||
DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
|
||||
yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
|
||||
|
||||
|
@ -945,6 +980,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
}
|
||||
else
|
||||
{
|
||||
xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
|
||||
PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
|
||||
LogHeader, PhysicsScene.Name);
|
||||
}
|
||||
|
@ -952,7 +988,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
}
|
||||
else
|
||||
{
|
||||
if (prim.LastAssetBuildFailed)
|
||||
if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
|
||||
{
|
||||
PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
|
||||
LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
|
||||
|
|
Loading…
Reference in New Issue