Merge branch 'ubitwork' into avination

avinationmerge
Melanie 2012-10-17 20:46:38 +02:00
commit 0ca9666932
22 changed files with 2411 additions and 1226 deletions

View File

@ -706,9 +706,10 @@ namespace OpenSim.Framework
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
int tickdata = 0; // int tickdata = 0;
int tickdiff = 0;
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl); // m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
Type type = typeof(TRequest); Type type = typeof(TRequest);
@ -751,8 +752,8 @@ namespace OpenSim.Framework
requestStream.Close(); requestStream.Close();
// capture how much time was spent writing // capture how much time was spent writing
tickdata = Util.EnvironmentTickCountSubtract(tickstart); // useless in this async
// tickdata = Util.EnvironmentTickCountSubtract(tickstart);
request.BeginGetResponse(delegate(IAsyncResult ar) request.BeginGetResponse(delegate(IAsyncResult ar)
{ {
response = request.EndGetResponse(ar); response = request.EndGetResponse(ar);
@ -769,7 +770,8 @@ namespace OpenSim.Framework
finally finally
{ {
// Let's not close this // Let's not close this
//buffer.Close(); // yes do close it
buffer.Close();
respStream.Close(); respStream.Close();
response.Close(); response.Close();
} }
@ -837,7 +839,6 @@ namespace OpenSim.Framework
} }
// m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
try try
{ {
action(deserial); action(deserial);
@ -852,9 +853,10 @@ namespace OpenSim.Framework
}, null); }, null);
} }
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime) if (tickdiff > WebUtil.LongCallTime)
{ {
/*
string originalRequest = null; string originalRequest = null;
if (buffer != null) if (buffer != null)
@ -873,6 +875,13 @@ namespace OpenSim.Framework
tickdiff, tickdiff,
tickdata, tickdata,
originalRequest); originalRequest);
*/
m_log.InfoFormat(
"[ASYNC REQUEST]: Slow WebRequest SETUP <{0}> {1} {2} took {3}ms",
reqnum,
verb,
requestUrl,
tickdiff);
} }
} }
} }
@ -903,6 +912,8 @@ namespace OpenSim.Framework
request.Method = verb; request.Method = verb;
string respstring = String.Empty; string respstring = String.Empty;
int tickset = Util.EnvironmentTickCountSubtract(tickstart);
using (MemoryStream buffer = new MemoryStream()) using (MemoryStream buffer = new MemoryStream())
{ {
if ((verb == "POST") || (verb == "PUT")) if ((verb == "POST") || (verb == "PUT"))
@ -979,11 +990,12 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime) if (tickdiff > WebUtil.LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[FORMS]: Slow request to <{0}> {1} {2} took {3}ms {4}ms writing {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
tickdiff, tickdiff,
tickset,
tickdata, tickdata,
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);

View File

@ -525,7 +525,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
{ {
for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
{ {
for (int j = 0; j < appearance.Wearables[j].Count; j++) for (int j = 0; j < appearance.Wearables[i].Count; j++)
{ {
if (appearance.Wearables[i][j].ItemID == UUID.Zero) if (appearance.Wearables[i][j].ItemID == UUID.Zero)
continue; continue;

View File

@ -575,6 +575,7 @@ namespace OpenSim.Region.Framework.Scenes
Quaternion current = m_group.GroupRotation; Quaternion current = m_group.GroupRotation;
Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete);
step.Normalize();
/* use simpler change detection /* use simpler change detection
* float angle = 0; * float angle = 0;

View File

@ -4314,8 +4314,8 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectPart[] parts = m_parts.GetArray(); SceneObjectPart[] parts = m_parts.GetArray();
for (int i = 0; i < parts.Length; i++) // for (int i = 0; i < parts.Length; i++)
parts[i].CheckSculptAndLoad(); // parts[i].CheckSculptAndLoad();
} }
/// <summary> /// <summary>

View File

@ -1095,9 +1095,9 @@ namespace OpenSim.Region.Framework.Scenes
{ {
actor.Size = m_shape.Scale; actor.Size = m_shape.Scale;
if (Shape.SculptEntry) // if (Shape.SculptEntry)
CheckSculptAndLoad(); // CheckSculptAndLoad();
else // else
ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
} }
} }
@ -1583,7 +1583,9 @@ namespace OpenSim.Region.Framework.Scenes
float cost = 0.1f; float cost = 0.1f;
if (PhysActor != null) if (PhysActor != null)
// cost += PhysActor.Cost; cost = PhysActor.PhysicsCost;
else
cost = 0.1f;
if ((Flags & PrimFlags.Physics) != 0) if ((Flags & PrimFlags.Physics) != 0)
cost *= (1.0f + 0.01333f * Scale.LengthSquared()); // 0.01333 == 0.04/3 cost *= (1.0f + 0.01333f * Scale.LengthSquared()); // 0.01333 == 0.04/3
@ -1596,9 +1598,12 @@ namespace OpenSim.Region.Framework.Scenes
{ {
get get
{ {
float cost;
if (PhysActor != null)
return 0.1f; cost = PhysActor.StreamCost;
else
cost = 1.0f;
return 1.0f;
} }
} }
@ -1654,8 +1659,8 @@ namespace OpenSim.Region.Framework.Scenes
else else
{ {
PhysActor.PhysicsShapeType = m_physicsShapeType; PhysActor.PhysicsShapeType = m_physicsShapeType;
if (Shape.SculptEntry) // if (Shape.SculptEntry)
CheckSculptAndLoad(); // CheckSculptAndLoad();
} }
if (ParentGroup != null) if (ParentGroup != null)
@ -2115,12 +2120,13 @@ namespace OpenSim.Region.Framework.Scenes
if (userExposed) if (userExposed)
{ {
/*
if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero) if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero)
{ {
ParentGroup.Scene.AssetService.Get( ParentGroup.Scene.AssetService.Get(
dupe.m_shape.SculptTexture.ToString(), dupe, dupe.AssetReceived); dupe.m_shape.SculptTexture.ToString(), dupe, dupe.AssetReceived);
} }
*/
bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0); bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0);
dupe.DoPhysicsPropertyUpdate(UsePhysics, true); dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
// dupe.UpdatePhysicsSubscribedEvents(); // not sure... // dupe.UpdatePhysicsSubscribedEvents(); // not sure...
@ -2142,6 +2148,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="id">ID of asset received</param> /// <param name="id">ID of asset received</param>
/// <param name="sender">Register</param> /// <param name="sender">Register</param>
/// <param name="asset"></param> /// <param name="asset"></param>
/*
protected void AssetReceived(string id, Object sender, AssetBase asset) protected void AssetReceived(string id, Object sender, AssetBase asset)
{ {
if (asset != null) if (asset != null)
@ -2151,7 +2158,7 @@ namespace OpenSim.Region.Framework.Scenes
// "[SCENE OBJECT PART]: Part {0} {1} requested mesh/sculpt data for asset id {2} from asset service but received no data", // "[SCENE OBJECT PART]: Part {0} {1} requested mesh/sculpt data for asset id {2} from asset service but received no data",
// Name, UUID, id); // Name, UUID, id);
} }
*/
/// <summary> /// <summary>
/// Do a physics property update for a NINJA joint. /// Do a physics property update for a NINJA joint.
/// </summary> /// </summary>
@ -2341,9 +2348,9 @@ namespace OpenSim.Region.Framework.Scenes
// If this part is a sculpt then delay the physics update until we've asynchronously loaded the // If this part is a sculpt then delay the physics update until we've asynchronously loaded the
// mesh data. // mesh data.
if (Shape.SculptEntry) // if (Shape.SculptEntry)
CheckSculptAndLoad(); // CheckSculptAndLoad();
else // else
ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
} }
} }
@ -3125,6 +3132,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Set sculpt and mesh data, and tell the physics engine to process the change. /// Set sculpt and mesh data, and tell the physics engine to process the change.
/// </summary> /// </summary>
/// <param name="texture">The mesh itself.</param> /// <param name="texture">The mesh itself.</param>
/*
public void SculptTextureCallback(AssetBase texture) public void SculptTextureCallback(AssetBase texture)
{ {
if (m_shape.SculptEntry) if (m_shape.SculptEntry)
@ -3152,7 +3160,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
*/
/// <summary> /// <summary>
/// Send a full update to the client for the given part /// Send a full update to the client for the given part
/// </summary> /// </summary>
@ -4377,7 +4385,7 @@ namespace OpenSim.Region.Framework.Scenes
public void UpdateExtraParam(ushort type, bool inUse, byte[] data) public void UpdateExtraParam(ushort type, bool inUse, byte[] data)
{ {
m_shape.ReadInUpdateExtraParam(type, inUse, data); m_shape.ReadInUpdateExtraParam(type, inUse, data);
/*
if (type == 0x30) if (type == 0x30)
{ {
if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero) if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero)
@ -4385,7 +4393,7 @@ namespace OpenSim.Region.Framework.Scenes
ParentGroup.Scene.AssetService.Get(m_shape.SculptTexture.ToString(), this, AssetReceived); ParentGroup.Scene.AssetService.Get(m_shape.SculptTexture.ToString(), this, AssetReceived);
} }
} }
*/
if (ParentGroup != null) if (ParentGroup != null)
{ {
ParentGroup.HasGroupChanged = true; ParentGroup.HasGroupChanged = true;
@ -4793,9 +4801,9 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
if (Shape.SculptEntry) // if (Shape.SculptEntry)
CheckSculptAndLoad(); // CheckSculptAndLoad();
else // else
ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
if (!building) if (!building)
@ -4898,10 +4906,13 @@ namespace OpenSim.Region.Framework.Scenes
/// <remarks> /// <remarks>
/// When the physics engine has finished with it, the sculpt data is discarded to save memory. /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
/// </remarks> /// </remarks>
/*
public void CheckSculptAndLoad() public void CheckSculptAndLoad()
{ {
// m_log.DebugFormat("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); // m_log.DebugFormat("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
return;
if (ParentGroup.IsDeleted) if (ParentGroup.IsDeleted)
return; return;
@ -4923,7 +4934,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
*/
/// <summary> /// <summary>
/// Update the texture entry for this part. /// Update the texture entry for this part.
/// </summary> /// </summary>
@ -5191,6 +5202,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
Quaternion rot = Quaternion.Slerp(RotationOffset,APIDTarget,1.0f/(float)m_APIDIterations); Quaternion rot = Quaternion.Slerp(RotationOffset,APIDTarget,1.0f/(float)m_APIDIterations);
rot.Normalize();
UpdateRotation(rot); UpdateRotation(rot);
m_APIDIterations--; m_APIDIterations--;

View File

@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin
convex = false; convex = false;
try try
{ {
_mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex); _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex,false);
} }
catch catch
{ {
@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin
try try
{ {
mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex); mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex,false);
} }
catch catch
{ {

View File

@ -37,9 +37,11 @@ namespace OpenSim.Region.Physics.Manager
{ {
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical,bool convex); IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde);
IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex);
void ReleaseMesh(IMesh mesh); void ReleaseMesh(IMesh mesh);
void ExpireReleaseMeshs(); void ExpireReleaseMeshs();
void ExpireFileCache();
} }
// Values for level of detail to be passed to the mesher. // Values for level of detail to be passed to the mesher.
@ -57,6 +59,7 @@ namespace OpenSim.Region.Physics.Manager
{ {
} }
[Serializable()]
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct AMeshKey public struct AMeshKey
{ {
@ -66,6 +69,13 @@ namespace OpenSim.Region.Physics.Manager
public ulong hashA; public ulong hashA;
[FieldOffset(8)] [FieldOffset(8)]
public ulong hashB; public ulong hashB;
[FieldOffset(16)]
public ulong hashC;
public override string ToString()
{
return uuid.ToString() + "-" + hashC.ToString("x") ;
}
} }
public interface IMesh public interface IMesh
@ -81,5 +91,6 @@ namespace OpenSim.Region.Physics.Manager
void Append(IMesh newMesh); void Append(IMesh newMesh);
void TransformLinear(float[,] matrix, float[] offset); void TransformLinear(float[,] matrix, float[] offset);
Vector3 GetCentroid(); Vector3 GetCentroid();
Vector3 GetOBB();
} }
} }

View File

@ -315,6 +315,23 @@ namespace OpenSim.Region.Physics.Manager
} }
} }
public virtual float PhysicsCost
{
get
{
return 0.1f;
}
}
public virtual float StreamCost
{
get
{
return 1.0f;
}
}
/// <summary> /// <summary>
/// Velocity of this actor. /// Velocity of this actor.
/// </summary> /// </summary>

View File

@ -106,7 +106,7 @@ namespace OpenSim.Region.Physics.Manager
get { return new NullPhysicsScene(); } get { return new NullPhysicsScene(); }
} }
public RequestAssetDelegate RequestAssetMethod { private get; set; } public RequestAssetDelegate RequestAssetMethod { get; set; }
public virtual void TriggerPhysicsBasedRestart() public virtual void TriggerPhysicsBasedRestart()
{ {
@ -246,6 +246,9 @@ namespace OpenSim.Region.Physics.Manager
public abstract void AddPhysicsActorTaint(PhysicsActor prim); public abstract void AddPhysicsActorTaint(PhysicsActor prim);
public virtual void PrepareSimulation() { }
/// <summary> /// <summary>
/// Perform a simulation of the current physics scene over the given timestep. /// Perform a simulation of the current physics scene over the given timestep.
/// </summary> /// </summary>

View File

@ -67,7 +67,7 @@ namespace OpenSim.Region.Physics.Manager
return CreateMesh(primName, primShape, size, lod, false); return CreateMesh(primName, primShape, size, lod, false);
} }
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex,bool forOde)
{ {
return CreateMesh(primName, primShape, size, lod, false); return CreateMesh(primName, primShape, size, lod, false);
} }
@ -79,7 +79,14 @@ namespace OpenSim.Region.Physics.Manager
return null; return null;
} }
public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
{
return null;
}
public void ReleaseMesh(IMesh mesh) { } public void ReleaseMesh(IMesh mesh) { }
public void ExpireReleaseMeshs() { } public void ExpireReleaseMeshs() { }
public void ExpireFileCache() { }
} }
} }

View File

@ -148,6 +148,12 @@ namespace OpenSim.Region.Physics.Meshing
return Vector3.Zero; return Vector3.Zero;
} }
// not functional
public Vector3 GetOBB()
{
return new Vector3(0.5f, 0.5f, 0.5f);
}
public void CalcNormals() public void CalcNormals()
{ {
int iTriangles = m_triangles.Count; int iTriangles = m_triangles.Count;
@ -253,6 +259,7 @@ namespace OpenSim.Region.Physics.Meshing
public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount)
{ {
// A vertex is 3 floats // A vertex is 3 floats
vertexStride = 3 * sizeof(float); vertexStride = 3 * sizeof(float);
// If there isn't an unmanaged array allocated yet, do it now // If there isn't an unmanaged array allocated yet, do it now

View File

@ -74,8 +74,6 @@ namespace OpenSim.Region.Physics.Meshing
#endif #endif
private bool cacheSculptMaps = true; private bool cacheSculptMaps = true;
private bool cacheSculptAlphaMaps = true;
private string decodedSculptMapPath = null; private string decodedSculptMapPath = null;
private bool useMeshiesPhysicsMesh = false; private bool useMeshiesPhysicsMesh = false;
@ -89,16 +87,7 @@ namespace OpenSim.Region.Physics.Meshing
IConfig mesh_config = config.Configs["Mesh"]; IConfig mesh_config = config.Configs["Mesh"];
decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
cacheSculptAlphaMaps = false;
}
else
cacheSculptAlphaMaps = cacheSculptMaps;
if(mesh_config != null) if(mesh_config != null)
useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
@ -279,18 +268,15 @@ namespace OpenSim.Region.Physics.Meshing
{ {
if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
return null; return null;
// Remove the reference to any JPEG2000 sculpt data so it can be GCed
// don't loose it
// primShape.SculptData = Utils.EmptyBytes;
} }
// primShape.SculptDataLoaded = true;
} }
else else
{ {
if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces)) if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
return null; return null;
} }
// keep compatible
// Remove the reference to any JPEG2000 sculpt data so it can be GCed
primShape.SculptData = Utils.EmptyBytes; primShape.SculptData = Utils.EmptyBytes;
int numCoords = coords.Count; int numCoords = coords.Count;
@ -335,7 +321,7 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0) if (primShape.SculptData.Length <= 0)
{ {
m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName); // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
return false; return false;
} }
@ -496,8 +482,7 @@ namespace OpenSim.Region.Physics.Meshing
//idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData);
if (cacheSculptMaps && (cacheSculptAlphaMaps || (((ImageFlags)(idata.Flags) & ImageFlags.HasAlpha) ==0))) if (cacheSculptMaps)
// don't cache images with alpha channel in linux since mono can't load them correctly)
{ {
try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
@ -717,7 +702,7 @@ namespace OpenSim.Region.Physics.Meshing
return CreateMesh(primName, primShape, size, lod, false); return CreateMesh(primName, primShape, size, lod, false);
} }
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde)
{ {
return CreateMesh(primName, primShape, size, lod, false); return CreateMesh(primName, primShape, size, lod, false);
} }
@ -763,7 +748,13 @@ namespace OpenSim.Region.Physics.Meshing
return mesh; return mesh;
} }
public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
{
return null;
}
public void ReleaseMesh(IMesh imesh) { } public void ReleaseMesh(IMesh imesh) { }
public void ExpireReleaseMeshs() { } public void ExpireReleaseMeshs() { }
public void ExpireFileCache() { }
} }
} }

View File

@ -63,6 +63,9 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool m_isphysical; private bool m_isphysical;
public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } }
private int m_expectedCollisionContacts = 0;
/// <summary> /// <summary>
/// Is this prim subject to physics? Even if not, it's still solid for collision purposes. /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
/// </summary> /// </summary>
@ -97,6 +100,9 @@ namespace OpenSim.Region.Physics.OdePlugin
private Vector3 m_taintAngularLock = Vector3.One; private Vector3 m_taintAngularLock = Vector3.One;
private IntPtr Amotor = IntPtr.Zero; private IntPtr Amotor = IntPtr.Zero;
private object m_assetsLock = new object();
private bool m_assetFailed = false;
private Vector3 m_PIDTarget; private Vector3 m_PIDTarget;
private float m_PIDTau; private float m_PIDTau;
private float PID_D = 35f; private float PID_D = 35f;
@ -279,6 +285,7 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
m_taintadd = true; m_taintadd = true;
m_assetFailed = false;
_parent_scene.AddPhysicsActorTaint(this); _parent_scene.AddPhysicsActorTaint(this);
} }
@ -601,8 +608,8 @@ namespace OpenSim.Region.Physics.OdePlugin
break; break;
case HollowShape.Circle: case HollowShape.Circle:
// Hollow shape is a perfect cylinder in respect to the cube's scale // Hollow shape is a perfect cyllinder in respect to the cube's scale
// Cylinder hollow volume calculation // Cyllinder hollow volume calculation
hollowVolume *= 0.1963495f * 3.07920140172638f; hollowVolume *= 0.1963495f * 3.07920140172638f;
break; break;
@ -840,7 +847,7 @@ namespace OpenSim.Region.Physics.OdePlugin
int vertexStride, triStride; int vertexStride, triStride;
mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
m_expectedCollisionContacts = indexCount;
mesh.releaseSourceMeshData(); // free up the original mesh data to save memory mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
// We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at
@ -1377,6 +1384,7 @@ Console.WriteLine("CreateGeom:");
{ {
//Console.WriteLine(" CreateGeom 1"); //Console.WriteLine(" CreateGeom 1");
SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
m_expectedCollisionContacts = 3;
} }
catch (AccessViolationException) catch (AccessViolationException)
{ {
@ -1391,6 +1399,7 @@ Console.WriteLine("CreateGeom:");
{ {
//Console.WriteLine(" CreateGeom 2"); //Console.WriteLine(" CreateGeom 2");
SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
m_expectedCollisionContacts = 4;
} }
catch (AccessViolationException) catch (AccessViolationException)
{ {
@ -1406,6 +1415,7 @@ Console.WriteLine("CreateGeom:");
{ {
//Console.WriteLine(" CreateGeom 3"); //Console.WriteLine(" CreateGeom 3");
SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
m_expectedCollisionContacts = 4;
} }
catch (AccessViolationException) catch (AccessViolationException)
{ {
@ -1421,6 +1431,7 @@ Console.WriteLine("CreateGeom:");
{ {
//Console.WriteLine(" CreateGeom 4"); //Console.WriteLine(" CreateGeom 4");
SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
m_expectedCollisionContacts = 4;
} }
catch (AccessViolationException) catch (AccessViolationException)
{ {
@ -1446,11 +1457,13 @@ Console.WriteLine("CreateGeom:");
_parent_scene.geom_name_map.Remove(prim_geom); _parent_scene.geom_name_map.Remove(prim_geom);
_parent_scene.actor_name_map.Remove(prim_geom); _parent_scene.actor_name_map.Remove(prim_geom);
d.GeomDestroy(prim_geom); d.GeomDestroy(prim_geom);
m_expectedCollisionContacts = 0;
prim_geom = IntPtr.Zero; prim_geom = IntPtr.Zero;
} }
catch (System.AccessViolationException) catch (System.AccessViolationException)
{ {
prim_geom = IntPtr.Zero; prim_geom = IntPtr.Zero;
m_expectedCollisionContacts = 0;
m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
return false; return false;
@ -1489,6 +1502,8 @@ Console.WriteLine("CreateGeom:");
mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
// createmesh returns null when it's a shape that isn't a cube. // createmesh returns null when it's a shape that isn't a cube.
// m_log.Debug(m_localID); // m_log.Debug(m_localID);
if (mesh == null)
CheckMeshAsset();
} }
#if SPAM #if SPAM
@ -1988,7 +2003,12 @@ Console.WriteLine(" JointCreateFixed");
// Don't need to re-enable body.. it's done in SetMesh // Don't need to re-enable body.. it's done in SetMesh
if (_parent_scene.needsMeshing(_pbs)) if (_parent_scene.needsMeshing(_pbs))
{
mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
if (mesh == null)
CheckMeshAsset();
}
} }
CreateGeom(m_targetSpace, mesh); CreateGeom(m_targetSpace, mesh);
@ -2048,6 +2068,8 @@ Console.WriteLine(" JointCreateFixed");
/// </summary> /// </summary>
private void changeshape() private void changeshape()
{ {
m_taintshape = false;
// Cleanup of old prim geometry and Bodies // Cleanup of old prim geometry and Bodies
if (IsPhysical && Body != IntPtr.Zero) if (IsPhysical && Body != IntPtr.Zero)
{ {
@ -2075,6 +2097,7 @@ Console.WriteLine(" JointCreateFixed");
IMesh mesh = null; IMesh mesh = null;
if (_parent_scene.needsMeshing(_pbs)) if (_parent_scene.needsMeshing(_pbs))
{ {
// Don't need to re-enable body.. it's done in CreateMesh // Don't need to re-enable body.. it's done in CreateMesh
@ -2085,6 +2108,8 @@ Console.WriteLine(" JointCreateFixed");
// createmesh returns null when it doesn't mesh. // createmesh returns null when it doesn't mesh.
mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
if (mesh == null)
CheckMeshAsset();
} }
CreateGeom(m_targetSpace, mesh); CreateGeom(m_targetSpace, mesh);
@ -2121,7 +2146,7 @@ Console.WriteLine(" JointCreateFixed");
} }
resetCollisionAccounting(); resetCollisionAccounting();
m_taintshape = false; // m_taintshape = false;
} }
/// <summary> /// <summary>
@ -2387,6 +2412,7 @@ Console.WriteLine(" JointCreateFixed");
set set
{ {
_pbs = value; _pbs = value;
m_assetFailed = false;
m_taintshape = true; m_taintshape = true;
} }
} }
@ -2395,15 +2421,15 @@ Console.WriteLine(" JointCreateFixed");
{ {
get get
{ {
// Averate previous velocity with the new one so // Average previous velocity with the new one so
// client object interpolation works a 'little' better // client object interpolation works a 'little' better
if (_zeroFlag) if (_zeroFlag)
return Vector3.Zero; return Vector3.Zero;
Vector3 returnVelocity = Vector3.Zero; Vector3 returnVelocity = Vector3.Zero;
returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2; returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2'
returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2; returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f;
returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2; returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f;
return returnVelocity; return returnVelocity;
} }
set set
@ -2600,6 +2626,7 @@ Console.WriteLine(" JointCreateFixed");
{ {
Vector3 pv = Vector3.Zero; Vector3 pv = Vector3.Zero;
bool lastZeroFlag = _zeroFlag; bool lastZeroFlag = _zeroFlag;
float m_minvelocity = 0;
if (Body != (IntPtr)0) // FIXME -> or if it is a joint if (Body != (IntPtr)0) // FIXME -> or if it is a joint
{ {
d.Vector3 vec = d.BodyGetPosition(Body); d.Vector3 vec = d.BodyGetPosition(Body);
@ -2752,8 +2779,21 @@ Console.WriteLine(" JointCreateFixed");
_acceleration = ((_velocity - m_lastVelocity) / 0.1f); _acceleration = ((_velocity - m_lastVelocity) / 0.1f);
_acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f);
//m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString());
// Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing...
// it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large.
// reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles
// adding these logical exclusion situations to maintain this where I think it was intended to be.
if (m_throttleUpdates || m_usePID || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero))
{
m_minvelocity = 0.5f;
}
else
{
m_minvelocity = 0.02f;
}
if (_velocity.ApproxEquals(pv, 0.5f)) if (_velocity.ApproxEquals(pv, m_minvelocity))
{ {
m_rotationalVelocity = pv; m_rotationalVelocity = pv;
} }
@ -3211,5 +3251,37 @@ Console.WriteLine(" JointCreateFixed");
{ {
m_material = pMaterial; m_material = pMaterial;
} }
private void CheckMeshAsset()
{
if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero)
{
m_assetFailed = true;
Util.FireAndForget(delegate
{
RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod;
if (assetProvider != null)
assetProvider(_pbs.SculptTexture, MeshAssetReveived);
});
}
}
void MeshAssetReveived(AssetBase asset)
{
if (asset.Data != null && asset.Data.Length > 0)
{
if (!_pbs.SculptEntry)
return;
if (_pbs.SculptTexture.ToString() != asset.ID)
return;
_pbs.SculptData = new byte[asset.Data.Length];
asset.Data.CopyTo(_pbs.SculptData, 0);
m_assetFailed = false;
m_taintshape = true;
_parent_scene.AddPhysicsActorTaint(this);
}
}
} }
} }

View File

@ -137,15 +137,8 @@ namespace OpenSim.Region.Physics.OdePlugin
ODERayCastRequest[] reqs = m_PendingRequests.ToArray(); ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
for (int i = 0; i < reqs.Length; i++) for (int i = 0; i < reqs.Length; i++)
{ {
try if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
{ RayCast(reqs[i]); // if there isn't anyone to send results
if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
RayCast(reqs[i]); // if there isn't anyone to send results
}
catch
{
//Fail silently
}
} }
m_PendingRequests.Clear(); m_PendingRequests.Clear();

View File

@ -336,6 +336,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public int geomContactPointsStartthrottle = 3; public int geomContactPointsStartthrottle = 3;
public int geomUpdatesPerThrottledUpdate = 15; public int geomUpdatesPerThrottledUpdate = 15;
private const int avatarExpectedContacts = 3;
public float bodyPIDD = 35f; public float bodyPIDD = 35f;
public float bodyPIDG = 25; public float bodyPIDG = 25;
@ -474,6 +475,8 @@ namespace OpenSim.Region.Physics.OdePlugin
private OdePrim cp1; private OdePrim cp1;
private OdeCharacter cc2; private OdeCharacter cc2;
private OdePrim cp2; private OdePrim cp2;
private int p1ExpectedPoints = 0;
private int p2ExpectedPoints = 0;
//private int cStartStop = 0; //private int cStartStop = 0;
//private string cDictKey = ""; //private string cDictKey = "";
@ -498,6 +501,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public int physics_logging_interval = 0; public int physics_logging_interval = 0;
public bool physics_logging_append_existing_logfile = false; public bool physics_logging_append_existing_logfile = false;
public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
@ -644,7 +648,7 @@ namespace OpenSim.Region.Physics.OdePlugin
contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
@ -1064,7 +1068,10 @@ namespace OpenSim.Region.Physics.OdePlugin
PhysicsActor p1; PhysicsActor p1;
PhysicsActor p2; PhysicsActor p2;
p1ExpectedPoints = 0;
p2ExpectedPoints = 0;
if (!actor_name_map.TryGetValue(g1, out p1)) if (!actor_name_map.TryGetValue(g1, out p1))
{ {
p1 = PANull; p1 = PANull;
@ -1121,9 +1128,13 @@ namespace OpenSim.Region.Physics.OdePlugin
switch (p1.PhysicsActorType) switch (p1.PhysicsActorType)
{ {
case (int)ActorTypes.Agent: case (int)ActorTypes.Agent:
p1ExpectedPoints = avatarExpectedContacts;
p2.CollidingObj = true; p2.CollidingObj = true;
break; break;
case (int)ActorTypes.Prim: case (int)ActorTypes.Prim:
if (p1 != null && p1 is OdePrim)
p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
if (p2.Velocity.LengthSquared() > 0.0f) if (p2.Velocity.LengthSquared() > 0.0f)
p2.CollidingObj = true; p2.CollidingObj = true;
break; break;
@ -1319,6 +1330,7 @@ namespace OpenSim.Region.Physics.OdePlugin
if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
(Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
{ {
p2ExpectedPoints = avatarExpectedContacts;
// Avatar is moving on terrain, use the movement terrain contact // Avatar is moving on terrain, use the movement terrain contact
AvatarMovementTerrainContact.geom = curContact; AvatarMovementTerrainContact.geom = curContact;
@ -1332,6 +1344,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{ {
if (p2.PhysicsActorType == (int)ActorTypes.Agent) if (p2.PhysicsActorType == (int)ActorTypes.Agent)
{ {
p2ExpectedPoints = avatarExpectedContacts;
// Avatar is standing on terrain, use the non moving terrain contact // Avatar is standing on terrain, use the non moving terrain contact
TerrainContact.geom = curContact; TerrainContact.geom = curContact;
@ -1356,9 +1369,18 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
if (p2 is OdePrim) if (p2 is OdePrim)
material = ((OdePrim)p2).m_material; {
material = ((OdePrim) p2).m_material;
p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
}
// Unnessesary because p1 is defined above
//if (p1 is OdePrim)
// {
// p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
// }
//m_log.DebugFormat("Material: {0}", material); //m_log.DebugFormat("Material: {0}", material);
m_materialContacts[material, movintYN].geom = curContact; m_materialContacts[material, movintYN].geom = curContact;
if (m_global_contactcount < maxContactsbeforedeath) if (m_global_contactcount < maxContactsbeforedeath)
@ -1379,7 +1401,10 @@ namespace OpenSim.Region.Physics.OdePlugin
int material = (int)Material.Wood; int material = (int)Material.Wood;
if (p2 is OdePrim) if (p2 is OdePrim)
{
material = ((OdePrim)p2).m_material; material = ((OdePrim)p2).m_material;
p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
}
//m_log.DebugFormat("Material: {0}", material); //m_log.DebugFormat("Material: {0}", material);
m_materialContacts[material, movintYN].geom = curContact; m_materialContacts[material, movintYN].geom = curContact;
@ -1429,6 +1454,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{ {
if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
{ {
p2ExpectedPoints = avatarExpectedContacts;
if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
{ {
// Avatar is moving on a prim, use the Movement prim contact // Avatar is moving on a prim, use the Movement prim contact
@ -1458,7 +1484,10 @@ namespace OpenSim.Region.Physics.OdePlugin
int material = (int)Material.Wood; int material = (int)Material.Wood;
if (p2 is OdePrim) if (p2 is OdePrim)
{
material = ((OdePrim)p2).m_material; material = ((OdePrim)p2).m_material;
p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
}
//m_log.DebugFormat("Material: {0}", material); //m_log.DebugFormat("Material: {0}", material);
m_materialContacts[material, 0].geom = curContact; m_materialContacts[material, 0].geom = curContact;
@ -1479,8 +1508,8 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
collision_accounting_events(p1, p2, maxDepthContact); collision_accounting_events(p1, p2, maxDepthContact);
if (count > geomContactPointsStartthrottle) if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
{ {
// If there are more then 3 contact points, it's likely // If there are more then 3 contact points, it's likely
// that we've got a pile of objects, so ... // that we've got a pile of objects, so ...

View File

@ -32,24 +32,49 @@ using System.Runtime.InteropServices;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
using PrimMesher; using PrimMesher;
using OpenMetaverse; using OpenMetaverse;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace OpenSim.Region.Physics.Meshing namespace OpenSim.Region.Physics.Meshing
{ {
public class MeshBuildingData
{
public Dictionary<Vertex, int> m_vertices;
public List<Triangle> m_triangles;
public float m_obbXmin;
public float m_obbXmax;
public float m_obbYmin;
public float m_obbYmax;
public float m_obbZmin;
public float m_obbZmax;
public Vector3 m_centroid;
public int m_centroidDiv;
}
[Serializable()]
public class Mesh : IMesh public class Mesh : IMesh
{ {
float[] vertices;
private Dictionary<Vertex, int> m_vertices; int[] indexes;
private List<Triangle> m_triangles; Vector3 m_obb;
GCHandle m_pinnedVertexes; Vector3 m_obboffset;
GCHandle m_pinnedIndex; [NonSerialized()]
MeshBuildingData m_bdata;
[NonSerialized()]
GCHandle vhandler;
[NonSerialized()]
GCHandle ihandler;
[NonSerialized()]
IntPtr m_verticesPtr = IntPtr.Zero; IntPtr m_verticesPtr = IntPtr.Zero;
int m_vertexCount = 0; [NonSerialized()]
IntPtr m_indicesPtr = IntPtr.Zero; IntPtr m_indicesPtr = IntPtr.Zero;
[NonSerialized()]
int m_vertexCount = 0;
[NonSerialized()]
int m_indexCount = 0; int m_indexCount = 0;
public float[] m_normals;
Vector3 m_centroid;
int m_centroidDiv;
public int RefCount { get; set; }
public AMeshKey Key { get; set; }
private class vertexcomp : IEqualityComparer<Vertex> private class vertexcomp : IEqualityComparer<Vertex>
{ {
@ -73,43 +98,119 @@ namespace OpenSim.Region.Physics.Meshing
{ {
vertexcomp vcomp = new vertexcomp(); vertexcomp vcomp = new vertexcomp();
m_vertices = new Dictionary<Vertex, int>(vcomp); m_bdata = new MeshBuildingData();
m_triangles = new List<Triangle>(); m_bdata.m_vertices = new Dictionary<Vertex, int>(vcomp);
m_centroid = Vector3.Zero; m_bdata.m_triangles = new List<Triangle>();
m_centroidDiv = 0; m_bdata.m_centroid = Vector3.Zero;
m_bdata.m_centroidDiv = 0;
m_bdata.m_obbXmin = float.MaxValue;
m_bdata.m_obbXmax = float.MinValue;
m_bdata.m_obbYmin = float.MaxValue;
m_bdata.m_obbYmax = float.MinValue;
m_bdata.m_obbZmin = float.MaxValue;
m_bdata.m_obbZmax = float.MinValue;
m_obb = new Vector3(0.5f, 0.5f, 0.5f);
m_obboffset = Vector3.Zero;
} }
public int RefCount { get; set; }
public AMeshKey Key { get; set; } public Mesh Scale(Vector3 scale)
public void Scale(Vector3 scale)
{ {
if (m_verticesPtr == null || m_indicesPtr == null)
return null;
Mesh result = new Mesh();
float x = scale.X;
float y = scale.Y;
float z = scale.Z;
result.m_obb.X = m_obb.X * x;
result.m_obb.Y = m_obb.Y * y;
result.m_obb.Z = m_obb.Z * z;
result.m_obboffset.X = m_obboffset.X * x;
result.m_obboffset.Y = m_obboffset.Y * y;
result.m_obboffset.Z = m_obboffset.Z * z;
result.vertices = new float[vertices.Length];
int j = 0;
for (int i = 0; i < m_vertexCount; i++)
{
result.vertices[j] = vertices[j] * x;
j++;
result.vertices[j] = vertices[j] * y;
j++;
result.vertices[j] = vertices[j] * z;
j++;
}
result.indexes = new int[indexes.Length];
indexes.CopyTo(result.indexes,0);
result.pinMemory();
return result;
} }
public Mesh Clone() public Mesh Clone()
{ {
Mesh result = new Mesh(); Mesh result = new Mesh();
foreach (Triangle t in m_triangles) if (m_bdata != null)
{ {
result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); result.m_bdata = new MeshBuildingData();
foreach (Triangle t in m_bdata.m_triangles)
{
result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
}
result.m_bdata.m_centroid = m_bdata.m_centroid;
result.m_bdata.m_centroidDiv = m_bdata.m_centroidDiv;
result.m_bdata.m_obbXmin = m_bdata.m_obbXmin;
result.m_bdata.m_obbXmax = m_bdata.m_obbXmax;
result.m_bdata.m_obbYmin = m_bdata.m_obbYmin;
result.m_bdata.m_obbYmax = m_bdata.m_obbYmax;
result.m_bdata.m_obbZmin = m_bdata.m_obbZmin;
result.m_bdata.m_obbZmax = m_bdata.m_obbZmax;
} }
result.m_centroid = m_centroid; result.m_obb = m_obb;
result.m_centroidDiv = m_centroidDiv; result.m_obboffset = m_obboffset;
return result; return result;
} }
public void addVertexLStats(Vertex v)
{
float x = v.X;
float y = v.Y;
float z = v.Z;
m_bdata.m_centroid.X += x;
m_bdata.m_centroid.Y += y;
m_bdata.m_centroid.Z += z;
m_bdata.m_centroidDiv++;
if (x > m_bdata.m_obbXmax)
m_bdata.m_obbXmax = x;
else if (x < m_bdata.m_obbXmin)
m_bdata.m_obbXmin = x;
if (y > m_bdata.m_obbYmax)
m_bdata.m_obbYmax = y;
else if (y < m_bdata.m_obbYmin)
m_bdata.m_obbYmin = y;
if (z > m_bdata.m_obbZmax)
m_bdata.m_obbZmax = z;
else if (z < m_bdata.m_obbZmin)
m_bdata.m_obbZmin = z;
}
public void Add(Triangle triangle) public void Add(Triangle triangle)
{ {
if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
throw new NotSupportedException("Attempt to Add to a pinned Mesh"); throw new NotSupportedException("Attempt to Add to a pinned Mesh");
// If a vertex of the triangle is not yet in the vertices list,
// add it and set its index to the current index count
// vertex == seems broken
// skip colapsed triangles
if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z == triangle.v2.Z) if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z == triangle.v2.Z)
|| (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z == triangle.v3.Z) || (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z == triangle.v3.Z)
|| (triangle.v2.X == triangle.v3.X && triangle.v2.Y == triangle.v3.Y && triangle.v2.Z == triangle.v3.Z) || (triangle.v2.X == triangle.v3.X && triangle.v2.Y == triangle.v3.Y && triangle.v2.Z == triangle.v3.Z)
@ -118,113 +219,59 @@ namespace OpenSim.Region.Physics.Meshing
return; return;
} }
if (m_vertices.Count == 0) if (m_bdata.m_vertices.Count == 0)
{ {
m_centroidDiv = 0; m_bdata.m_centroidDiv = 0;
m_centroid = Vector3.Zero; m_bdata.m_centroid = Vector3.Zero;
} }
if (!m_vertices.ContainsKey(triangle.v1)) if (!m_bdata.m_vertices.ContainsKey(triangle.v1))
{ {
m_vertices[triangle.v1] = m_vertices.Count; m_bdata.m_vertices[triangle.v1] = m_bdata.m_vertices.Count;
m_centroid.X += triangle.v1.X; addVertexLStats(triangle.v1);
m_centroid.Y += triangle.v1.Y;
m_centroid.Z += triangle.v1.Z;
m_centroidDiv++;
} }
if (!m_vertices.ContainsKey(triangle.v2)) if (!m_bdata.m_vertices.ContainsKey(triangle.v2))
{ {
m_vertices[triangle.v2] = m_vertices.Count; m_bdata.m_vertices[triangle.v2] = m_bdata.m_vertices.Count;
m_centroid.X += triangle.v2.X; addVertexLStats(triangle.v2);
m_centroid.Y += triangle.v2.Y;
m_centroid.Z += triangle.v2.Z;
m_centroidDiv++;
} }
if (!m_vertices.ContainsKey(triangle.v3)) if (!m_bdata.m_vertices.ContainsKey(triangle.v3))
{ {
m_vertices[triangle.v3] = m_vertices.Count; m_bdata.m_vertices[triangle.v3] = m_bdata.m_vertices.Count;
m_centroid.X += triangle.v3.X; addVertexLStats(triangle.v3);
m_centroid.Y += triangle.v3.Y;
m_centroid.Z += triangle.v3.Z;
m_centroidDiv++;
} }
m_triangles.Add(triangle); m_bdata.m_triangles.Add(triangle);
} }
public Vector3 GetCentroid() public Vector3 GetCentroid()
{ {
if (m_centroidDiv > 0) return m_obboffset;
return new Vector3(m_centroid.X / m_centroidDiv, m_centroid.Y / m_centroidDiv, m_centroid.Z / m_centroidDiv);
else
return Vector3.Zero;
} }
public void CalcNormals() public Vector3 GetOBB()
{ {
int iTriangles = m_triangles.Count; return m_obb;
float x, y, z;
this.m_normals = new float[iTriangles * 3]; if (m_bdata.m_centroidDiv > 0)
int i = 0;
foreach (Triangle t in m_triangles)
{ {
float ux, uy, uz; x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f;
float vx, vy, vz; y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f;
float wx, wy, wz; z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f;
ux = t.v1.X;
uy = t.v1.Y;
uz = t.v1.Z;
vx = t.v2.X;
vy = t.v2.Y;
vz = t.v2.Z;
wx = t.v3.X;
wy = t.v3.Y;
wz = t.v3.Z;
// Vectors for edges
float e1x, e1y, e1z;
float e2x, e2y, e2z;
e1x = ux - vx;
e1y = uy - vy;
e1z = uz - vz;
e2x = ux - wx;
e2y = uy - wy;
e2z = uz - wz;
// Cross product for normal
float nx, ny, nz;
nx = e1y * e2z - e1z * e2y;
ny = e1z * e2x - e1x * e2z;
nz = e1x * e2y - e1y * e2x;
// Length
float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz);
float lReciprocal = 1.0f / l;
// Normalized "normal"
//nx /= l;
//ny /= l;
//nz /= l;
m_normals[i] = nx * lReciprocal;
m_normals[i + 1] = ny * lReciprocal;
m_normals[i + 2] = nz * lReciprocal;
i += 3;
} }
else // ??
{
x = 0.5f;
y = 0.5f;
z = 0.5f;
}
return new Vector3(x, y, z);
} }
public List<Vector3> getVertexList() public List<Vector3> getVertexList()
{ {
List<Vector3> result = new List<Vector3>(); List<Vector3> result = new List<Vector3>();
foreach (Vertex v in m_vertices.Keys) foreach (Vertex v in m_bdata.m_vertices.Keys)
{ {
result.Add(new Vector3(v.X, v.Y, v.Z)); result.Add(new Vector3(v.X, v.Y, v.Z));
} }
@ -233,10 +280,10 @@ namespace OpenSim.Region.Physics.Meshing
private float[] getVertexListAsFloat() private float[] getVertexListAsFloat()
{ {
if (m_vertices == null) if (m_bdata.m_vertices == null)
throw new NotSupportedException(); throw new NotSupportedException();
float[] result = new float[m_vertices.Count * 3]; float[] result = new float[m_bdata.m_vertices.Count * 3];
foreach (KeyValuePair<Vertex, int> kvp in m_vertices) foreach (KeyValuePair<Vertex, int> kvp in m_bdata.m_vertices)
{ {
Vertex v = kvp.Key; Vertex v = kvp.Key;
int i = kvp.Value; int i = kvp.Value;
@ -249,48 +296,39 @@ namespace OpenSim.Region.Physics.Meshing
public float[] getVertexListAsFloatLocked() public float[] getVertexListAsFloatLocked()
{ {
if (m_pinnedVertexes.IsAllocated) return null;
return (float[])(m_pinnedVertexes.Target);
float[] result = getVertexListAsFloat();
m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned);
// Inform the garbage collector of this unmanaged allocation so it can schedule
// the next GC round more intelligently
GC.AddMemoryPressure(Buffer.ByteLength(result));
return result;
} }
public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) public void getVertexListAsPtrToFloatArray(out IntPtr _vertices, out int vertexStride, out int vertexCount)
{ {
// A vertex is 3 floats // A vertex is 3 floats
vertexStride = 3 * sizeof(float); vertexStride = 3 * sizeof(float);
// If there isn't an unmanaged array allocated yet, do it now // If there isn't an unmanaged array allocated yet, do it now
if (m_verticesPtr == IntPtr.Zero) if (m_verticesPtr == IntPtr.Zero && m_bdata != null)
{ {
float[] vertexList = getVertexListAsFloat(); vertices = getVertexListAsFloat();
// Each vertex is 3 elements (floats) // Each vertex is 3 elements (floats)
m_vertexCount = vertexList.Length / 3; m_vertexCount = vertices.Length / 3;
int byteCount = m_vertexCount * vertexStride; vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); m_verticesPtr = vhandler.AddrOfPinnedObject();
System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); GC.AddMemoryPressure(Buffer.ByteLength(vertices));
} }
vertices = m_verticesPtr; _vertices = m_verticesPtr;
vertexCount = m_vertexCount; vertexCount = m_vertexCount;
} }
public int[] getIndexListAsInt() public int[] getIndexListAsInt()
{ {
if (m_triangles == null) if (m_bdata.m_triangles == null)
throw new NotSupportedException(); throw new NotSupportedException();
int[] result = new int[m_triangles.Count * 3]; int[] result = new int[m_bdata.m_triangles.Count * 3];
for (int i = 0; i < m_triangles.Count; i++) for (int i = 0; i < m_bdata.m_triangles.Count; i++)
{ {
Triangle t = m_triangles[i]; Triangle t = m_bdata.m_triangles[i];
result[3 * i + 0] = m_vertices[t.v1]; result[3 * i + 0] = m_bdata.m_vertices[t.v1];
result[3 * i + 1] = m_vertices[t.v2]; result[3 * i + 1] = m_bdata.m_vertices[t.v2];
result[3 * i + 2] = m_vertices[t.v3]; result[3 * i + 2] = m_bdata.m_vertices[t.v3];
} }
return result; return result;
} }
@ -301,28 +339,19 @@ namespace OpenSim.Region.Physics.Meshing
/// <returns></returns> /// <returns></returns>
public int[] getIndexListAsIntLocked() public int[] getIndexListAsIntLocked()
{ {
if (m_pinnedIndex.IsAllocated) return null;
return (int[])(m_pinnedIndex.Target);
int[] result = getIndexListAsInt();
m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned);
// Inform the garbage collector of this unmanaged allocation so it can schedule
// the next GC round more intelligently
GC.AddMemoryPressure(Buffer.ByteLength(result));
return result;
} }
public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount)
{ {
// If there isn't an unmanaged array allocated yet, do it now // If there isn't an unmanaged array allocated yet, do it now
if (m_indicesPtr == IntPtr.Zero) if (m_indicesPtr == IntPtr.Zero && m_bdata != null)
{ {
int[] indexList = getIndexListAsInt(); indexes = getIndexListAsInt();
m_indexCount = indexList.Length; m_indexCount = indexes.Length;
int byteCount = m_indexCount * sizeof(int); ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); m_indicesPtr = ihandler.AddrOfPinnedObject();
System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); GC.AddMemoryPressure(Buffer.ByteLength(indexes));
} }
// A triangle is 3 ints (indices) // A triangle is 3 ints (indices)
triStride = 3 * sizeof(int); triStride = 3 * sizeof(int);
@ -332,18 +361,16 @@ namespace OpenSim.Region.Physics.Meshing
public void releasePinned() public void releasePinned()
{ {
if (m_pinnedVertexes.IsAllocated)
m_pinnedVertexes.Free();
if (m_pinnedIndex.IsAllocated)
m_pinnedIndex.Free();
if (m_verticesPtr != IntPtr.Zero) if (m_verticesPtr != IntPtr.Zero)
{ {
System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); vhandler.Free();
vertices = null;
m_verticesPtr = IntPtr.Zero; m_verticesPtr = IntPtr.Zero;
} }
if (m_indicesPtr != IntPtr.Zero) if (m_indicesPtr != IntPtr.Zero)
{ {
System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); ihandler.Free();
indexes = null;
m_indicesPtr = IntPtr.Zero; m_indicesPtr = IntPtr.Zero;
} }
} }
@ -353,29 +380,42 @@ namespace OpenSim.Region.Physics.Meshing
/// </summary> /// </summary>
public void releaseSourceMeshData() public void releaseSourceMeshData()
{ {
m_triangles = null; if (m_bdata != null)
m_vertices = null; {
m_bdata.m_triangles = null;
m_bdata.m_vertices = null;
}
}
public void releaseBuildingMeshData()
{
if (m_bdata != null)
{
m_bdata.m_triangles = null;
m_bdata.m_vertices = null;
m_bdata = null;
}
} }
public void Append(IMesh newMesh) public void Append(IMesh newMesh)
{ {
if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
throw new NotSupportedException("Attempt to Append to a pinned Mesh"); throw new NotSupportedException("Attempt to Append to a pinned Mesh");
if (!(newMesh is Mesh)) if (!(newMesh is Mesh))
return; return;
foreach (Triangle t in ((Mesh)newMesh).m_triangles) foreach (Triangle t in ((Mesh)newMesh).m_bdata.m_triangles)
Add(t); Add(t);
} }
// Do a linear transformation of mesh. // Do a linear transformation of mesh.
public void TransformLinear(float[,] matrix, float[] offset) public void TransformLinear(float[,] matrix, float[] offset)
{ {
if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh");
foreach (Vertex v in m_vertices.Keys) foreach (Vertex v in m_bdata.m_vertices.Keys)
{ {
if (v == null) if (v == null)
continue; continue;
@ -393,10 +433,12 @@ namespace OpenSim.Region.Physics.Meshing
{ {
if (path == null) if (path == null)
return; return;
if (m_bdata == null)
return;
String fileName = name + "_" + title + ".raw"; String fileName = name + "_" + title + ".raw";
String completePath = System.IO.Path.Combine(path, fileName); String completePath = System.IO.Path.Combine(path, fileName);
StreamWriter sw = new StreamWriter(completePath); StreamWriter sw = new StreamWriter(completePath);
foreach (Triangle t in m_triangles) foreach (Triangle t in m_bdata.m_triangles)
{ {
String s = t.ToStringRaw(); String s = t.ToStringRaw();
sw.WriteLine(s); sw.WriteLine(s);
@ -406,7 +448,144 @@ namespace OpenSim.Region.Physics.Meshing
public void TrimExcess() public void TrimExcess()
{ {
m_triangles.TrimExcess(); m_bdata.m_triangles.TrimExcess();
}
public void pinMemory()
{
m_vertexCount = vertices.Length / 3;
vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
m_verticesPtr = vhandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(vertices));
m_indexCount = indexes.Length;
ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
m_indicesPtr = ihandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(indexes));
}
public void PrepForOde()
{
// If there isn't an unmanaged array allocated yet, do it now
if (m_verticesPtr == IntPtr.Zero)
vertices = getVertexListAsFloat();
// If there isn't an unmanaged array allocated yet, do it now
if (m_indicesPtr == IntPtr.Zero)
indexes = getIndexListAsInt();
pinMemory();
float x, y, z;
if (m_bdata.m_centroidDiv > 0)
{
m_obboffset = new Vector3(m_bdata.m_centroid.X / m_bdata.m_centroidDiv, m_bdata.m_centroid.Y / m_bdata.m_centroidDiv, m_bdata.m_centroid.Z / m_bdata.m_centroidDiv);
x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f;
y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f;
z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f;
}
else
{
m_obboffset = Vector3.Zero;
x = 0.5f;
y = 0.5f;
z = 0.5f;
}
m_obb = new Vector3(x, y, z);
releaseBuildingMeshData();
}
public bool ToStream(Stream st)
{
if (m_indicesPtr == IntPtr.Zero || m_verticesPtr == IntPtr.Zero)
return false;
BinaryWriter bw = new BinaryWriter(st);
bool ok = true;
try
{
bw.Write(m_vertexCount);
bw.Write(m_indexCount);
for (int i = 0; i < 3 * m_vertexCount; i++)
bw.Write(vertices[i]);
for (int i = 0; i < m_indexCount; i++)
bw.Write(indexes[i]);
bw.Write(m_obb.X);
bw.Write(m_obb.Y);
bw.Write(m_obb.Z);
bw.Write(m_obboffset.X);
bw.Write(m_obboffset.Y);
bw.Write(m_obboffset.Z);
}
catch
{
ok = false;
}
if (bw != null)
{
bw.Flush();
bw.Close();
}
return ok;
}
public static Mesh FromStream(Stream st, AMeshKey key)
{
Mesh mesh = new Mesh();
mesh.releaseBuildingMeshData();
BinaryReader br = new BinaryReader(st);
bool ok = true;
try
{
mesh.m_vertexCount = br.ReadInt32();
mesh.m_indexCount = br.ReadInt32();
int n = 3 * mesh.m_vertexCount;
mesh.vertices = new float[n];
for (int i = 0; i < n; i++)
mesh.vertices[i] = br.ReadSingle();
mesh.indexes = new int[mesh.m_indexCount];
for (int i = 0; i < mesh.m_indexCount; i++)
mesh.indexes[i] = br.ReadInt32();
mesh.m_obb.X = br.ReadSingle();
mesh.m_obb.Y = br.ReadSingle();
mesh.m_obb.Z = br.ReadSingle();
mesh.m_obboffset.X = br.ReadSingle();
mesh.m_obboffset.Y = br.ReadSingle();
mesh.m_obboffset.Z = br.ReadSingle();
}
catch
{
ok = false;
}
br.Close();
if (ok)
{
mesh.pinMemory();
mesh.Key = key;
mesh.RefCount = 1;
return mesh;
}
mesh.vertices = null;
mesh.indexes = null;
return null;
} }
} }
} }

View File

@ -42,6 +42,8 @@ using System.Reflection;
using System.IO; using System.IO;
using ComponentAce.Compression.Libs.zlib; using ComponentAce.Compression.Libs.zlib;
using OpenSim.Region.Physics.ConvexDecompositionDotNet; using OpenSim.Region.Physics.ConvexDecompositionDotNet;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace OpenSim.Region.Physics.Meshing namespace OpenSim.Region.Physics.Meshing
{ {
@ -68,22 +70,22 @@ namespace OpenSim.Region.Physics.Meshing
// Setting baseDir to a path will enable the dumping of raw files // Setting baseDir to a path will enable the dumping of raw files
// raw files can be imported by blender so a visual inspection of the results can be done // raw files can be imported by blender so a visual inspection of the results can be done
#if SPAM
const string baseDir = "rawFiles"; public object diskLock = new object();
#else
public bool doMeshFileCache = true;
public string cachePath = "MeshCache";
public TimeSpan CacheExpire;
public bool doCacheExpire = true;
// const string baseDir = "rawFiles";
private const string baseDir = null; //"rawFiles"; private const string baseDir = null; //"rawFiles";
#endif
private bool cacheSculptMaps = true;
private bool cacheSculptAlphaMaps = true;
private string decodedSculptMapPath = null;
private bool useMeshiesPhysicsMesh = false; private bool useMeshiesPhysicsMesh = false;
private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
// private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
// private Dictionary<ulong, Mesh> m_uniqueReleasedMeshes = new Dictionary<ulong, Mesh>();
private Dictionary<AMeshKey, Mesh> m_uniqueMeshes = new Dictionary<AMeshKey, Mesh>(); private Dictionary<AMeshKey, Mesh> m_uniqueMeshes = new Dictionary<AMeshKey, Mesh>();
private Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes = new Dictionary<AMeshKey, Mesh>(); private Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes = new Dictionary<AMeshKey, Mesh>();
@ -92,29 +94,29 @@ namespace OpenSim.Region.Physics.Meshing
IConfig start_config = config.Configs["Startup"]; IConfig start_config = config.Configs["Startup"];
IConfig mesh_config = config.Configs["Mesh"]; IConfig mesh_config = config.Configs["Mesh"];
decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); float fcache = 48.0f;
// float fcache = 0.02f;
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
cacheSculptAlphaMaps = false;
}
else
cacheSculptAlphaMaps = cacheSculptMaps;
if(mesh_config != null) if(mesh_config != null)
{
useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
if (useMeshiesPhysicsMesh)
{
doMeshFileCache = mesh_config.GetBoolean("MeshFileCache", doMeshFileCache);
cachePath = mesh_config.GetString("MeshFileCachePath", cachePath);
fcache = mesh_config.GetFloat("MeshFileCacheExpireHours", fcache);
doCacheExpire = mesh_config.GetBoolean("MeshFileCacheDoExpire", doCacheExpire);
}
else
{
doMeshFileCache = false;
doCacheExpire = false;
}
}
CacheExpire = TimeSpan.FromHours(fcache);
try
{
if (!Directory.Exists(decodedSculptMapPath))
Directory.CreateDirectory(decodedSculptMapPath);
}
catch (Exception e)
{
m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
}
} }
/// <summary> /// <summary>
@ -212,7 +214,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="size">Size of entire object</param> /// <param name="size">Size of entire object</param>
/// <param name="coords"></param> /// <param name="coords"></param>
/// <param name="faces"></param> /// <param name="faces"></param>
private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces) private void AddSubMesh(OSDMap subMeshData, List<Coord> coords, List<Face> faces)
{ {
// Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap)); // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
@ -245,9 +247,9 @@ namespace OpenSim.Region.Physics.Meshing
ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
Coord c = new Coord( Coord c = new Coord(
Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X, Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y, Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z); Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));
coords.Add(c); coords.Add(c);
} }
@ -271,7 +273,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="size"></param> /// <param name="size"></param>
/// <param name="lod"></param> /// <param name="lod"></param>
/// <returns></returns> /// <returns></returns>
private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool convex) private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, float lod, bool convex)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[MESH]: Creating physics proxy for {0}, shape {1}", // "[MESH]: Creating physics proxy for {0}, shape {1}",
@ -287,18 +289,18 @@ namespace OpenSim.Region.Physics.Meshing
if (!useMeshiesPhysicsMesh) if (!useMeshiesPhysicsMesh)
return null; return null;
if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces, convex)) if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, out coords, out faces, convex))
return null; return null;
} }
else else
{ {
if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, lod, out coords, out faces))
return null; return null;
} }
} }
else else
{ {
if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces)) if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, out coords, out faces))
return null; return null;
} }
@ -333,7 +335,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="faces">Faces are added to this list by the method.</param> /// <param name="faces">Faces are added to this list by the method.</param>
/// <returns>true if coords and faces were successfully generated, false if not</returns> /// <returns>true if coords and faces were successfully generated, false if not</returns>
private bool GenerateCoordsAndFacesFromPrimMeshData( private bool GenerateCoordsAndFacesFromPrimMeshData(
string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces, bool convex) string primName, PrimitiveBaseShape primShape, out List<Coord> coords, out List<Face> faces, bool convex)
{ {
// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); // m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
@ -345,7 +347,7 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0) if (primShape.SculptData.Length <= 0)
{ {
m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName); // m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName);
return false; return false;
} }
@ -406,7 +408,7 @@ namespace OpenSim.Region.Physics.Meshing
OSD decodedMeshOsd = new OSD(); OSD decodedMeshOsd = new OSD();
byte[] meshBytes = new byte[physSize]; byte[] meshBytes = new byte[physSize];
System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
// byte[] decompressed = new byte[physSize * 5];
try try
{ {
using (MemoryStream inMs = new MemoryStream(meshBytes)) using (MemoryStream inMs = new MemoryStream(meshBytes))
@ -444,13 +446,13 @@ namespace OpenSim.Region.Physics.Meshing
// physics_shape is an array of OSDMaps, one for each submesh // physics_shape is an array of OSDMaps, one for each submesh
if (decodedMeshOsd is OSDArray) if (decodedMeshOsd is OSDArray)
{ {
// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
decodedMeshOsdArray = (OSDArray)decodedMeshOsd; decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
foreach (OSD subMeshOsd in decodedMeshOsdArray) foreach (OSD subMeshOsd in decodedMeshOsdArray)
{ {
if (subMeshOsd is OSDMap) if (subMeshOsd is OSDMap)
AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); AddSubMesh(subMeshOsd as OSDMap, coords, faces);
} }
} }
} }
@ -522,9 +524,9 @@ namespace OpenSim.Region.Physics.Meshing
t3 = data[ptr++]; t3 = data[ptr++];
t3 += data[ptr++] << 8; t3 += data[ptr++] << 8;
f3 = new float3((t1 * range.X + min.X) * size.X, f3 = new float3((t1 * range.X + min.X),
(t2 * range.Y + min.Y) * size.Y, (t2 * range.Y + min.Y),
(t3 * range.Z + min.Z) * size.Z); (t3 * range.Z + min.Z));
vs.Add(f3); vs.Add(f3);
} }
@ -621,9 +623,9 @@ namespace OpenSim.Region.Physics.Meshing
t3 = data[i++]; t3 = data[i++];
t3 += data[i++] << 8; t3 += data[i++] << 8;
f3 = new float3((t1 * range.X + min.X) * size.X, f3 = new float3((t1 * range.X + min.X),
(t2 * range.Y + min.Y) * size.Y, (t2 * range.Y + min.Y),
(t3 * range.Z + min.Z) * size.Z); (t3 * range.Z + min.Z));
vs.Add(f3); vs.Add(f3);
} }
@ -711,35 +713,13 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="faces">Faces are added to this list by the method.</param> /// <param name="faces">Faces are added to this list by the method.</param>
/// <returns>true if coords and faces were successfully generated, false if not</returns> /// <returns>true if coords and faces were successfully generated, false if not</returns>
private bool GenerateCoordsAndFacesFromPrimSculptData( private bool GenerateCoordsAndFacesFromPrimSculptData(
string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces)
{ {
coords = new List<Coord>(); coords = new List<Coord>();
faces = new List<Face>(); faces = new List<Face>();
PrimMesher.SculptMesh sculptMesh; PrimMesher.SculptMesh sculptMesh;
Image idata = null; Image idata = null;
string decodedSculptFileName = "";
if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero)
{
decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString());
try
{
if (File.Exists(decodedSculptFileName))
{
idata = Image.FromFile(decodedSculptFileName);
}
}
catch (Exception e)
{
m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
}
//if (idata != null)
// m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
}
if (idata == null)
{
if (primShape.SculptData == null || primShape.SculptData.Length == 0) if (primShape.SculptData == null || primShape.SculptData.Length == 0)
return false; return false;
@ -748,25 +728,15 @@ namespace OpenSim.Region.Physics.Meshing
OpenMetaverse.Imaging.ManagedImage unusedData; OpenMetaverse.Imaging.ManagedImage unusedData;
OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
unusedData = null;
if (idata == null) if (idata == null)
{ {
// In some cases it seems that the decode can return a null bitmap without throwing // In some cases it seems that the decode can return a null bitmap without throwing
// an exception // an exception
m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
return false; return false;
} }
unusedData = null;
//idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData);
if (cacheSculptMaps && (cacheSculptAlphaMaps || (((ImageFlags)(idata.Flags) & ImageFlags.HasAlpha) ==0)))
// don't cache images with alpha channel in linux since mono can't load them correctly)
{
try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
}
} }
catch (DllNotFoundException) catch (DllNotFoundException)
{ {
@ -783,7 +753,6 @@ namespace OpenSim.Region.Physics.Meshing
m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
return false; return false;
} }
}
PrimMesher.SculptMesh.SculptType sculptType; PrimMesher.SculptMesh.SculptType sculptType;
// remove mirror and invert bits // remove mirror and invert bits
@ -814,9 +783,7 @@ namespace OpenSim.Region.Physics.Meshing
idata.Dispose(); idata.Dispose();
sculptMesh.DumpRaw(baseDir, primName, "primMesh"); // sculptMesh.DumpRaw(baseDir, primName, "primMesh");
sculptMesh.Scale(size.X, size.Y, size.Z);
coords = sculptMesh.coords; coords = sculptMesh.coords;
faces = sculptMesh.faces; faces = sculptMesh.faces;
@ -834,7 +801,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="faces">Faces are added to this list by the method.</param> /// <param name="faces">Faces are added to this list by the method.</param>
/// <returns>true if coords and faces were successfully generated, false if not</returns> /// <returns>true if coords and faces were successfully generated, false if not</returns>
private bool GenerateCoordsAndFacesFromPrimShapeData( private bool GenerateCoordsAndFacesFromPrimShapeData(
string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces)
{ {
PrimMesh primMesh; PrimMesh primMesh;
coords = new List<Coord>(); coords = new List<Coord>();
@ -969,9 +936,7 @@ namespace OpenSim.Region.Physics.Meshing
} }
} }
primMesh.DumpRaw(baseDir, primName, "primMesh"); // primMesh.DumpRaw(baseDir, primName, "primMesh");
primMesh.Scale(size.X, size.Y, size.Z);
coords = primMesh.coords; coords = primMesh.coords;
faces = primMesh.faces; faces = primMesh.faces;
@ -985,12 +950,14 @@ namespace OpenSim.Region.Physics.Meshing
Byte[] someBytes; Byte[] someBytes;
key.hashB = 5181; key.hashB = 5181;
key.hashC = 5181;
ulong hash = 5381; ulong hash = 5381;
if (primShape.SculptEntry) if (primShape.SculptEntry)
{ {
key.uuid = primShape.SculptTexture; key.uuid = primShape.SculptTexture;
key.hashB = mdjb2(key.hashB, primShape.SculptType); key.hashC = mdjb2(key.hashC, primShape.SculptType);
key.hashC = mdjb2(key.hashC, primShape.PCode);
} }
else else
{ {
@ -1002,6 +969,8 @@ namespace OpenSim.Region.Physics.Meshing
hash = mdjb2(hash, primShape.PathScaleX); hash = mdjb2(hash, primShape.PathScaleX);
hash = mdjb2(hash, primShape.PathScaleY); hash = mdjb2(hash, primShape.PathScaleY);
hash = mdjb2(hash, primShape.PathShearX); hash = mdjb2(hash, primShape.PathShearX);
key.hashA = hash;
hash = key.hashB;
hash = mdjb2(hash, primShape.PathShearY); hash = mdjb2(hash, primShape.PathShearY);
hash = mdjb2(hash, (byte)primShape.PathTwist); hash = mdjb2(hash, (byte)primShape.PathTwist);
hash = mdjb2(hash, (byte)primShape.PathTwistBegin); hash = mdjb2(hash, (byte)primShape.PathTwistBegin);
@ -1013,26 +982,38 @@ namespace OpenSim.Region.Physics.Meshing
hash = mdjb2(hash, primShape.ProfileBegin); hash = mdjb2(hash, primShape.ProfileBegin);
hash = mdjb2(hash, primShape.ProfileEnd); hash = mdjb2(hash, primShape.ProfileEnd);
hash = mdjb2(hash, primShape.ProfileHollow); hash = mdjb2(hash, primShape.ProfileHollow);
key.hashA = hash; hash = mdjb2(hash, primShape.PCode);
key.hashB = hash;
} }
hash = key.hashB; hash = key.hashC;
someBytes = size.GetBytes();
for (int i = 0; i < someBytes.Length; i++)
hash = mdjb2(hash, someBytes[i]);
hash = mdjb2(hash, lod); hash = mdjb2(hash, lod);
hash &= 0x3fffffffffffffff; if (size == m_MeshUnitSize)
{
hash = hash << 8;
hash |= 8;
}
else
{
someBytes = size.GetBytes();
for (int i = 0; i < someBytes.Length; i++)
hash = mdjb2(hash, someBytes[i]);
hash = hash << 8;
}
if (convex) if (convex)
hash |= 0x4000000000000000; hash |= 4;
if (primShape.SculptEntry) if (primShape.SculptEntry)
hash |= 0x8000000000000000; {
hash |= 1;
if (primShape.SculptType == (byte)SculptType.Mesh)
hash |= 2;
}
key.hashB = hash; key.hashC = hash;
return key; return key;
} }
@ -1048,35 +1029,74 @@ namespace OpenSim.Region.Physics.Meshing
return ((hash << 5) + hash) + (ulong)(c >> 8); return ((hash << 5) + hash) + (ulong)(c >> 8);
} }
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
{ {
return CreateMesh(primName, primShape, size, lod, false,false); return CreateMesh(primName, primShape, size, lod, false,false,false);
} }
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
{ {
return CreateMesh(primName, primShape, size, lod, false,false); return CreateMesh(primName, primShape, size, lod, false,false,false);
} }
private static Vector3 m_MeshUnitSize = new Vector3(0.5f, 0.5f, 0.5f); public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
{
Mesh mesh = null;
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) if (size.X < 0.01f) size.X = 0.01f;
if (size.Y < 0.01f) size.Y = 0.01f;
if (size.Z < 0.01f) size.Z = 0.01f;
AMeshKey key = GetMeshUniqueKey(primShape, size, (byte)lod, convex);
lock (m_uniqueMeshes)
{
m_uniqueMeshes.TryGetValue(key, out mesh);
if (mesh != null)
{
mesh.RefCount++;
return mesh;
}
}
// try to find a identical mesh on meshs recently released
lock (m_uniqueReleasedMeshes)
{
m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
if (mesh != null)
{
m_uniqueReleasedMeshes.Remove(key);
lock (m_uniqueMeshes)
{
try
{
m_uniqueMeshes.Add(key, mesh);
}
catch { }
}
mesh.RefCount = 1;
return mesh;
}
}
return null;
}
private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f);
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde)
{ {
#if SPAM #if SPAM
m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
#endif #endif
Mesh mesh = null; Mesh mesh = null;
// ulong key = 0;
if (size.X < 0.01f) size.X = 0.01f; if (size.X < 0.01f) size.X = 0.01f;
if (size.Y < 0.01f) size.Y = 0.01f; if (size.Y < 0.01f) size.Y = 0.01f;
if (size.Z < 0.01f) size.Z = 0.01f; if (size.Z < 0.01f) size.Z = 0.01f;
// try to find a identical mesh on meshs in use // try to find a identical mesh on meshs in use
// key = primShape.GetMeshKey(size, lod, convex);
AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex); AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex);
lock (m_uniqueMeshes) lock (m_uniqueMeshes)
@ -1098,35 +1118,78 @@ namespace OpenSim.Region.Physics.Meshing
{ {
m_uniqueReleasedMeshes.Remove(key); m_uniqueReleasedMeshes.Remove(key);
lock (m_uniqueMeshes) lock (m_uniqueMeshes)
m_uniqueMeshes.Add(key, mesh); {
try
{
m_uniqueMeshes.Add(key, mesh);
}
catch { }
}
mesh.RefCount = 1; mesh.RefCount = 1;
return mesh; return mesh;
} }
} }
mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod,convex); Mesh UnitMesh = null;
AMeshKey unitKey = GetMeshUniqueKey(primShape, m_MeshUnitSize, (byte)lod, convex);
if (mesh != null) lock (m_uniqueReleasedMeshes)
{ {
if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh) m_uniqueReleasedMeshes.TryGetValue(unitKey, out UnitMesh);
if (UnitMesh != null)
{ {
#if SPAM UnitMesh.RefCount = 1;
m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " +
minSizeForComplexMesh.ToString() + " - creating simple bounding box");
#endif
mesh = CreateBoundingBoxMesh(mesh);
mesh.DumpRaw(baseDir, primName, "Z extruded");
} }
// trim the vertex and triangle lists to free up memory
mesh.TrimExcess();
mesh.Key = key;
mesh.RefCount = 1;
lock(m_uniqueMeshes)
m_uniqueMeshes.Add(key, mesh);
} }
if (UnitMesh == null && primShape.SculptEntry && doMeshFileCache)
UnitMesh = GetFromFileCache(unitKey);
if (UnitMesh == null)
{
UnitMesh = CreateMeshFromPrimMesher(primName, primShape, lod, convex);
if (UnitMesh == null)
return null;
UnitMesh.DumpRaw(baseDir, unitKey.ToString(), "Z");
if (forOde)
{
// force pinned mem allocation
UnitMesh.PrepForOde();
}
else
UnitMesh.TrimExcess();
UnitMesh.Key = unitKey;
UnitMesh.RefCount = 1;
if (doMeshFileCache && primShape.SculptEntry)
StoreToFileCache(unitKey, UnitMesh);
lock (m_uniqueReleasedMeshes)
{
try
{
m_uniqueReleasedMeshes.Add(unitKey, UnitMesh);
}
catch { }
}
}
mesh = UnitMesh.Scale(size);
mesh.Key = key;
mesh.RefCount = 1;
lock (m_uniqueMeshes)
{
try
{
m_uniqueMeshes.Add(key, mesh);
}
catch { }
}
return mesh; return mesh;
} }
@ -1137,21 +1200,27 @@ namespace OpenSim.Region.Physics.Meshing
Mesh mesh = (Mesh)imesh; Mesh mesh = (Mesh)imesh;
int curRefCount = mesh.RefCount;
curRefCount--;
if (curRefCount > 0)
{
mesh.RefCount = curRefCount;
return;
}
lock (m_uniqueMeshes) lock (m_uniqueMeshes)
{ {
int curRefCount = mesh.RefCount;
curRefCount--;
if (curRefCount > 0)
{
mesh.RefCount = curRefCount;
return;
}
mesh.RefCount = 0; mesh.RefCount = 0;
m_uniqueMeshes.Remove(mesh.Key); m_uniqueMeshes.Remove(mesh.Key);
lock (m_uniqueReleasedMeshes) lock (m_uniqueReleasedMeshes)
m_uniqueReleasedMeshes.Add(mesh.Key, mesh); {
try
{
m_uniqueReleasedMeshes.Add(mesh.Key, mesh);
}
catch { }
}
} }
} }
@ -1178,10 +1247,170 @@ namespace OpenSim.Region.Physics.Meshing
foreach (Mesh m in meshstodelete) foreach (Mesh m in meshstodelete)
{ {
m_uniqueReleasedMeshes.Remove(m.Key); m_uniqueReleasedMeshes.Remove(m.Key);
m.releaseSourceMeshData(); m.releaseBuildingMeshData();
m.releasePinned(); m.releasePinned();
} }
} }
} }
public void FileNames(AMeshKey key, out string dir,out string fullFileName)
{
string id = key.ToString();
string init = id.Substring(0, 1);
dir = System.IO.Path.Combine(cachePath, init);
fullFileName = System.IO.Path.Combine(dir, id);
}
public string FullFileName(AMeshKey key)
{
string id = key.ToString();
string init = id.Substring(0,1);
id = System.IO.Path.Combine(init, id);
id = System.IO.Path.Combine(cachePath, id);
return id;
}
private Mesh GetFromFileCache(AMeshKey key)
{
Mesh mesh = null;
string filename = FullFileName(key);
bool ok = true;
lock (diskLock)
{
if (File.Exists(filename))
{
FileStream stream = null;
try
{
stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryFormatter bformatter = new BinaryFormatter();
mesh = Mesh.FromStream(stream, key);
}
catch (Exception e)
{
ok = false;
m_log.ErrorFormat(
"[MESH CACHE]: Failed to get file {0}. Exception {1} {2}",
filename, e.Message, e.StackTrace);
}
if (stream != null)
stream.Close();
if (mesh == null || !ok)
File.Delete(filename);
else
File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
}
}
return mesh;
}
private void StoreToFileCache(AMeshKey key, Mesh mesh)
{
Stream stream = null;
bool ok = false;
// Make sure the target cache directory exists
string dir = String.Empty;
string filename = String.Empty;
FileNames(key, out dir, out filename);
lock (diskLock)
{
try
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
stream = File.Open(filename, FileMode.Create);
ok = mesh.ToStream(stream);
}
catch (IOException e)
{
m_log.ErrorFormat(
"[MESH CACHE]: Failed to write file {0}. Exception {1} {2}.",
filename, e.Message, e.StackTrace);
ok = false;
}
if (stream != null)
stream.Close();
if (File.Exists(filename))
{
if (ok)
File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
else
File.Delete(filename);
}
}
}
public void ExpireFileCache()
{
if (!doCacheExpire)
return;
string controlfile = System.IO.Path.Combine(cachePath, "cntr");
lock (diskLock)
{
try
{
if (File.Exists(controlfile))
{
int ndeleted = 0;
int totalfiles = 0;
int ndirs = 0;
DateTime OlderTime = File.GetLastAccessTimeUtc(controlfile) - CacheExpire;
File.SetLastAccessTimeUtc(controlfile, DateTime.UtcNow);
foreach (string dir in Directory.GetDirectories(cachePath))
{
try
{
foreach (string file in Directory.GetFiles(dir))
{
try
{
if (File.GetLastAccessTimeUtc(file) < OlderTime)
{
File.Delete(file);
ndeleted++;
}
}
catch { }
totalfiles++;
}
}
catch { }
ndirs++;
}
if (ndeleted == 0)
m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, no expires",
totalfiles,ndirs);
else
m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, expired {2} files accessed before {3}",
totalfiles,ndirs, ndeleted, OlderTime.ToString());
}
else
{
m_log.Info("[MESH CACHE]: Expire delayed to next startup");
FileStream fs = File.Create(controlfile,4096,FileOptions.WriteThrough);
fs.Close();
}
}
catch { }
}
}
} }
} }

View File

@ -172,7 +172,6 @@ namespace OpenSim.Region.Physics.OdePlugin
// force lower density for testing // force lower density for testing
m_density = 3.0f; m_density = 3.0f;
mu = parent_scene.AvatarFriction; mu = parent_scene.AvatarFriction;
walkDivisor = walk_divisor; walkDivisor = walk_divisor;

View File

@ -0,0 +1,931 @@
/*
* AJLDuarte 2012
*/
using System;
using System.Threading;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OdeAPI;
using log4net;
using Nini.Config;
using OpenMetaverse;
namespace OpenSim.Region.Physics.OdePlugin
{
public enum MeshState : byte
{
noNeed = 0,
loadingAsset = 1,
AssetOK = 0x0f, // 00001111
NeedMask = 0x30, // 00110000
needMesh = 0x10, // 00010000
needAsset = 0x20, // 00100000
FailMask = 0xC0, // 11000000
AssetFailed = 0x40, // 01000000
MeshFailed = 0x80, // 10000000
MeshNoColide = FailMask | needAsset
}
public enum meshWorkerCmnds : byte
{
nop = 0,
addnew,
changefull,
changesize,
changeshapetype,
getmesh,
}
public class ODEPhysRepData
{
public PhysicsActor actor;
public PrimitiveBaseShape pbs;
public IMesh mesh;
public Vector3 size;
public Vector3 OBB;
public Vector3 OBBOffset;
public float volume;
public byte shapetype;
public bool hasOBB;
public bool hasMeshVolume;
public MeshState meshState;
public UUID? assetID;
public meshWorkerCmnds comand;
}
public class ODEMeshWorker
{
private ILog m_log;
private OdeScene m_scene;
private IMesher m_mesher;
public bool meshSculptedPrim = true;
public bool forceSimplePrimMeshing = false;
public float meshSculptLOD = 32;
public float MeshSculptphysicalLOD = 32;
private OpenSim.Framework.BlockingQueue<ODEPhysRepData> createqueue = new OpenSim.Framework.BlockingQueue<ODEPhysRepData>();
private bool m_running;
private Thread m_thread;
public ODEMeshWorker(OdeScene pScene, ILog pLog, IMesher pMesher, IConfig pConfig)
{
m_scene = pScene;
m_log = pLog;
m_mesher = pMesher;
if (pConfig != null)
{
forceSimplePrimMeshing = pConfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
meshSculptedPrim = pConfig.GetBoolean("mesh_sculpted_prim", meshSculptedPrim);
meshSculptLOD = pConfig.GetFloat("mesh_lod", meshSculptLOD);
MeshSculptphysicalLOD = pConfig.GetFloat("mesh_physical_lod", MeshSculptphysicalLOD);
}
m_running = true;
m_thread = new Thread(DoWork);
m_thread.Start();
}
private void DoWork()
{
m_mesher.ExpireFileCache();
while(m_running)
{
ODEPhysRepData nextRep = createqueue.Dequeue();
if(!m_running)
return;
if (nextRep == null)
continue;
if (m_scene.haveActor(nextRep.actor))
{
switch (nextRep.comand)
{
case meshWorkerCmnds.changefull:
case meshWorkerCmnds.changeshapetype:
case meshWorkerCmnds.changesize:
GetMesh(nextRep);
if (CreateActorPhysRep(nextRep) && m_scene.haveActor(nextRep.actor))
m_scene.AddChange(nextRep.actor, changes.PhysRepData, nextRep);
break;
case meshWorkerCmnds.getmesh:
DoRepDataGetMesh(nextRep);
break;
}
}
}
}
public void Stop()
{
try
{
m_thread.Abort();
createqueue.Clear();
}
catch
{
}
}
public void ChangeActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs,
Vector3 size, byte shapetype)
{
ODEPhysRepData repData = new ODEPhysRepData();
repData.actor = actor;
repData.pbs = pbs;
repData.size = size;
repData.shapetype = shapetype;
CheckMesh(repData);
CalcVolumeData(repData);
m_scene.AddChange(actor, changes.PhysRepData, repData);
return;
}
public ODEPhysRepData NewActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs,
Vector3 size, byte shapetype)
{
ODEPhysRepData repData = new ODEPhysRepData();
repData.actor = actor;
repData.pbs = pbs;
repData.size = size;
repData.shapetype = shapetype;
CheckMesh(repData);
CalcVolumeData(repData);
m_scene.AddChange(actor, changes.AddPhysRep, repData);
return repData;
}
public void RequestMesh(ODEPhysRepData repData)
{
repData.mesh = null;
if (repData.meshState == MeshState.needAsset)
{
PrimitiveBaseShape pbs = repData.pbs;
// check if we got outdated
if (!pbs.SculptEntry || pbs.SculptTexture == UUID.Zero)
{
repData.meshState = MeshState.noNeed;
return;
}
repData.assetID = pbs.SculptTexture;
repData.meshState = MeshState.loadingAsset;
repData.comand = meshWorkerCmnds.getmesh;
createqueue.Enqueue(repData);
}
}
// creates and prepares a mesh to use and calls parameters estimation
public bool CreateActorPhysRep(ODEPhysRepData repData)
{
IMesh mesh = repData.mesh;
if (mesh != null)
{
IntPtr vertices, indices;
int vertexCount, indexCount;
int vertexStride, triStride;
mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount);
mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount);
if (vertexCount == 0 || indexCount == 0)
{
m_log.WarnFormat("[PHYSICS]: Invalid mesh data on prim {0} mesh UUID {1}",
repData.actor.Name, repData.pbs.SculptTexture.ToString());
repData.meshState = MeshState.MeshFailed;
repData.hasOBB = false;
repData.mesh = null;
m_scene.mesher.ReleaseMesh(mesh);
}
else
{
repData.OBBOffset = mesh.GetCentroid();
repData.OBB = mesh.GetOBB();
repData.hasOBB = true;
mesh.releaseSourceMeshData();
}
}
CalcVolumeData(repData);
return true;
}
public void AssetLoaded(ODEPhysRepData repData)
{
if (m_scene.haveActor(repData.actor))
{
if (needsMeshing(repData.pbs)) // no need for pbs now?
{
repData.comand = meshWorkerCmnds.changefull;
createqueue.Enqueue(repData);
}
}
else
repData.pbs.SculptData = Utils.EmptyBytes;
}
public void DoRepDataGetMesh(ODEPhysRepData repData)
{
if (!repData.pbs.SculptEntry)
return;
if (repData.meshState != MeshState.loadingAsset)
return;
if (repData.assetID == null || repData.assetID == UUID.Zero)
return;
if (repData.assetID != repData.pbs.SculptTexture)
return;
// check if it is in cache
GetMesh(repData);
if (repData.meshState != MeshState.needAsset)
{
CreateActorPhysRep(repData);
m_scene.AddChange(repData.actor, changes.PhysRepData, repData);
return;
}
RequestAssetDelegate assetProvider = m_scene.RequestAssetMethod;
if (assetProvider == null)
return;
ODEAssetRequest asr = new ODEAssetRequest(this, assetProvider, repData, m_log);
}
/// <summary>
/// Routine to figure out if we need to mesh this prim with our mesher
/// </summary>
/// <param name="pbs"></param>
/// <returns></returns>
public bool needsMeshing(PrimitiveBaseShape pbs)
{
// check sculpts or meshs
if (pbs.SculptEntry)
{
if (meshSculptedPrim)
return true;
if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs
return true;
return false;
}
if (forceSimplePrimMeshing)
return true;
// if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
|| (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
{
if (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 false;
}
}
// following code doesn't give meshs to boxes and spheres ever
// and it's odd.. so for now just return true if asked to force meshs
// hopefully mesher will fail if doesn't suport so things still get basic boxes
int iPropertiesNotSupportedDefault = 0;
if (pbs.ProfileHollow != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
iPropertiesNotSupportedDefault++;
if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
iPropertiesNotSupportedDefault++;
if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
iPropertiesNotSupportedDefault++;
// test for torus
if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
{
if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
{
if (pbs.PathCurve == (byte)Extrusion.Straight)
{
iPropertiesNotSupportedDefault++;
}
// ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
else if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
{
if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
{
if (pbs.PathCurve == (byte)Extrusion.Straight)
{
iPropertiesNotSupportedDefault++;
}
else if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
if (iPropertiesNotSupportedDefault == 0)
{
return false;
}
return true;
}
// see if we need a mesh and if so if we have a cached one
// called with a new repData
public void CheckMesh(ODEPhysRepData repData)
{
PhysicsActor actor = repData.actor;
PrimitiveBaseShape pbs = repData.pbs;
if (!needsMeshing(pbs))
{
repData.meshState = MeshState.noNeed;
return;
}
IMesh mesh = null;
Vector3 size = repData.size;
byte shapetype = repData.shapetype;
bool convex;
int clod = (int)LevelOfDetail.High;
if (shapetype == 0)
convex = false;
else
{
convex = true;
if (pbs.SculptType != (byte)SculptType.Mesh)
clod = (int)LevelOfDetail.Low;
}
mesh = m_mesher.GetMesh(actor.Name, pbs, size, clod, true, convex);
if (mesh == null)
{
if (pbs.SculptEntry)
{
if (pbs.SculptTexture != null && pbs.SculptTexture != UUID.Zero)
{
repData.assetID = pbs.SculptTexture;
repData.meshState = MeshState.needAsset;
}
else
repData.meshState = MeshState.MeshFailed;
return;
}
else
{
repData.meshState = MeshState.needMesh;
mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true);
if (mesh == null)
{
repData.meshState = MeshState.MeshFailed;
return;
}
}
}
repData.meshState = MeshState.AssetOK;
repData.mesh = mesh;
if (pbs.SculptEntry)
{
repData.assetID = pbs.SculptTexture;
}
pbs.SculptData = Utils.EmptyBytes;
return ;
}
public void GetMesh(ODEPhysRepData repData)
{
PhysicsActor actor = repData.actor;
PrimitiveBaseShape pbs = repData.pbs;
repData.mesh = null;
repData.hasOBB = false;
if (!needsMeshing(pbs))
{
repData.meshState = MeshState.noNeed;
return;
}
if (repData.meshState == MeshState.MeshFailed)
return;
if (pbs.SculptEntry)
{
if (repData.meshState == MeshState.AssetFailed)
{
if (pbs.SculptTexture == repData.assetID)
return;
}
}
repData.meshState = MeshState.noNeed;
IMesh mesh = null;
Vector3 size = repData.size;
byte shapetype = repData.shapetype;
bool convex;
int clod = (int)LevelOfDetail.High;
if (shapetype == 0)
convex = false;
else
{
convex = true;
if (pbs.SculptType != (byte)SculptType.Mesh)
clod = (int)LevelOfDetail.Low;
}
mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true);
if (mesh == null)
{
if (pbs.SculptEntry)
{
if (pbs.SculptTexture == UUID.Zero)
return;
repData.assetID = pbs.SculptTexture;
if (pbs.SculptData == null || pbs.SculptData.Length == 0)
{
repData.meshState = MeshState.needAsset;
return;
}
}
}
repData.mesh = mesh;
repData.pbs.SculptData = Utils.EmptyBytes;
if (mesh == null)
{
if (pbs.SculptEntry)
repData.meshState = MeshState.AssetFailed;
else
repData.meshState = MeshState.MeshFailed;
return;
}
repData.meshState = MeshState.AssetOK;
return;
}
private void CalculateBasicPrimVolume(ODEPhysRepData repData)
{
PrimitiveBaseShape _pbs = repData.pbs;
Vector3 _size = repData.size;
float volume = _size.X * _size.Y * _size.Z; // default
float tmp;
float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
float hollowVolume = hollowAmount * hollowAmount;
switch (_pbs.ProfileShape)
{
case ProfileShape.Square:
// default box
if (_pbs.PathCurve == (byte)Extrusion.Straight)
{
if (hollowAmount > 0.0)
{
switch (_pbs.HollowShape)
{
case HollowShape.Square:
case HollowShape.Same:
break;
case HollowShape.Circle:
hollowVolume *= 0.78539816339f;
break;
case HollowShape.Triangle:
hollowVolume *= (0.5f * .5f);
break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
{
//a tube
volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
tmp = 1.0f - 2.0e-2f * (float)(200 - _pbs.PathScaleY);
volume -= volume * tmp * tmp;
if (hollowAmount > 0.0)
{
hollowVolume *= hollowAmount;
switch (_pbs.HollowShape)
{
case HollowShape.Square:
case HollowShape.Same:
break;
case HollowShape.Circle:
hollowVolume *= 0.78539816339f;
break;
case HollowShape.Triangle:
hollowVolume *= 0.5f * 0.5f;
break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
break;
case ProfileShape.Circle:
if (_pbs.PathCurve == (byte)Extrusion.Straight)
{
volume *= 0.78539816339f; // elipse base
if (hollowAmount > 0.0)
{
switch (_pbs.HollowShape)
{
case HollowShape.Same:
case HollowShape.Circle:
break;
case HollowShape.Square:
hollowVolume *= 0.5f * 2.5984480504799f;
break;
case HollowShape.Triangle:
hollowVolume *= .5f * 1.27323954473516f;
break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
{
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
volume *= (1.0f - tmp * tmp);
if (hollowAmount > 0.0)
{
// calculate the hollow volume by it's shape compared to the prim shape
hollowVolume *= hollowAmount;
switch (_pbs.HollowShape)
{
case HollowShape.Same:
case HollowShape.Circle:
break;
case HollowShape.Square:
hollowVolume *= 0.5f * 2.5984480504799f;
break;
case HollowShape.Triangle:
hollowVolume *= .5f * 1.27323954473516f;
break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
break;
case ProfileShape.HalfCircle:
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
{
volume *= 0.5236f;
if (hollowAmount > 0.0)
{
hollowVolume *= hollowAmount;
switch (_pbs.HollowShape)
{
case HollowShape.Circle:
case HollowShape.Triangle: // diference in sl is minor and odd
case HollowShape.Same:
break;
case HollowShape.Square:
hollowVolume *= 0.909f;
break;
// case HollowShape.Triangle:
// hollowVolume *= .827f;
// break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
break;
case ProfileShape.EquilateralTriangle:
if (_pbs.PathCurve == (byte)Extrusion.Straight)
{
volume *= 0.32475953f;
if (hollowAmount > 0.0)
{
// calculate the hollow volume by it's shape compared to the prim shape
switch (_pbs.HollowShape)
{
case HollowShape.Same:
case HollowShape.Triangle:
hollowVolume *= .25f;
break;
case HollowShape.Square:
hollowVolume *= 0.499849f * 3.07920140172638f;
break;
case HollowShape.Circle:
// Hollow shape is a perfect cyllinder in respect to the cube's scale
// Cyllinder hollow volume calculation
hollowVolume *= 0.1963495f * 3.07920140172638f;
break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
{
volume *= 0.32475953f;
volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
volume *= (1.0f - tmp * tmp);
if (hollowAmount > 0.0)
{
hollowVolume *= hollowAmount;
switch (_pbs.HollowShape)
{
case HollowShape.Same:
case HollowShape.Triangle:
hollowVolume *= .25f;
break;
case HollowShape.Square:
hollowVolume *= 0.499849f * 3.07920140172638f;
break;
case HollowShape.Circle:
hollowVolume *= 0.1963495f * 3.07920140172638f;
break;
default:
hollowVolume = 0;
break;
}
volume *= (1.0f - hollowVolume);
}
}
break;
default:
break;
}
float taperX1;
float taperY1;
float taperX;
float taperY;
float pathBegin;
float pathEnd;
float profileBegin;
float profileEnd;
if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
{
taperX1 = _pbs.PathScaleX * 0.01f;
if (taperX1 > 1.0f)
taperX1 = 2.0f - taperX1;
taperX = 1.0f - taperX1;
taperY1 = _pbs.PathScaleY * 0.01f;
if (taperY1 > 1.0f)
taperY1 = 2.0f - taperY1;
taperY = 1.0f - taperY1;
}
else
{
taperX = _pbs.PathTaperX * 0.01f;
if (taperX < 0.0f)
taperX = -taperX;
taperX1 = 1.0f - taperX;
taperY = _pbs.PathTaperY * 0.01f;
if (taperY < 0.0f)
taperY = -taperY;
taperY1 = 1.0f - taperY;
}
volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
volume *= (pathEnd - pathBegin);
// this is crude aproximation
profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
volume *= (profileEnd - profileBegin);
repData.volume = volume;
}
private void CalcVolumeData(ODEPhysRepData repData)
{
if (repData.hasOBB)
{
Vector3 OBB = repData.OBB;
}
else
{
Vector3 OBB = repData.size;
OBB.X *= 0.5f;
OBB.Y *= 0.5f;
OBB.Z *= 0.5f;
repData.OBB = OBB;
repData.OBBOffset = Vector3.Zero;
}
CalculateBasicPrimVolume(repData);
}
}
public class ODEAssetRequest
{
ODEMeshWorker m_worker;
private ILog m_log;
ODEPhysRepData repData;
public ODEAssetRequest(ODEMeshWorker pWorker, RequestAssetDelegate provider,
ODEPhysRepData pRepData, ILog plog)
{
m_worker = pWorker;
m_log = plog;
repData = pRepData;
repData.meshState = MeshState.AssetFailed;
if (provider == null)
return;
if (repData.assetID == null)
return;
UUID assetID = (UUID) repData.assetID;
if (assetID == UUID.Zero)
return;
repData.meshState = MeshState.loadingAsset;
provider(assetID, ODEassetReceived);
}
void ODEassetReceived(AssetBase asset)
{
repData.meshState = MeshState.AssetFailed;
if (asset != null)
{
if (asset.Data != null && asset.Data.Length > 0)
{
repData.meshState = MeshState.noNeed;
if (!repData.pbs.SculptEntry)
return;
if (repData.pbs.SculptTexture != repData.assetID)
return;
repData.pbs.SculptData = new byte[asset.Data.Length];
asset.Data.CopyTo(repData.pbs.SculptData,0);
repData.meshState = MeshState.AssetOK;
m_worker.AssetLoaded(repData);
}
else
m_log.WarnFormat("[PHYSICS]: asset provider returned invalid mesh data for prim {0} asset UUID {1}.",
repData.actor.Name, asset.ID.ToString());
}
else
m_log.WarnFormat("[PHYSICS]: asset provider returned null asset fo mesh of prim {0}.",
repData.actor.Name);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -129,7 +129,7 @@ namespace OpenSim.Region.Physics.OdePlugin
req.length = length; req.length = length;
req.Normal = direction; req.Normal = direction;
req.Origin = position; req.Origin = position;
req.filter = RayFilterFlags.AllPrims; req.filter = RayFilterFlags.AllPrims | RayFilterFlags.land;
m_PendingRequests.Enqueue(req); m_PendingRequests.Enqueue(req);
} }
@ -288,7 +288,10 @@ namespace OpenSim.Region.Physics.OdePlugin
catflags |= CollisionCategories.Water; catflags |= CollisionCategories.Water;
if (catflags != 0) if (catflags != 0)
{
d.GeomSetCollideBits(ray, (uint)catflags);
doSpaceRay(req); doSpaceRay(req);
}
} }
else else
{ {
@ -314,7 +317,8 @@ namespace OpenSim.Region.Physics.OdePlugin
/// ///
private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton; private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton;
private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; // private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton;
private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton;
private void doSpaceRay(ODERayRequest req) private void doSpaceRay(ODERayRequest req)
{ {
@ -323,6 +327,16 @@ namespace OpenSim.Region.Physics.OdePlugin
d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback); d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount)) if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback); d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
{
// current ode land to ray collisions is very bad
// so for now limit its range badly
if (req.length > 30.0f)
d.GeomRaySetLength(ray, 30.0f);
d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
}
if (req.callbackMethod is RaycastCallback) if (req.callbackMethod is RaycastCallback)
{ {

View File

@ -60,6 +60,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public int lastframe; public int lastframe;
} }
// colision flags of things others can colide with // colision flags of things others can colide with
// rays, sensors, probes removed since can't be colided with // rays, sensors, probes removed since can't be colided with
// The top space where things are placed provided further selection // The top space where things are placed provided further selection
@ -109,7 +110,7 @@ namespace OpenSim.Region.Physics.OdePlugin
light = 7 // compatibility with old viewers light = 7 // compatibility with old viewers
} }
public enum changes : int public enum changes : int
{ {
Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?) Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?)
@ -147,6 +148,8 @@ namespace OpenSim.Region.Physics.OdePlugin
Size, Size,
Shape, Shape,
PhysRepData,
AddPhysRep,
CollidesWater, CollidesWater,
VolumeDtc, VolumeDtc,
@ -230,11 +233,6 @@ namespace OpenSim.Region.Physics.OdePlugin
private float minimumGroundFlightOffset = 3f; private float minimumGroundFlightOffset = 3f;
public float maximumMassObject = 10000.01f; public float maximumMassObject = 10000.01f;
public bool meshSculptedPrim = true;
public bool forceSimplePrimMeshing = false;
public float meshSculptLOD = 32;
public float MeshSculptphysicalLOD = 32;
public float geomDefaultDensity = 10.000006836f; public float geomDefaultDensity = 10.000006836f;
@ -302,6 +300,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public IntPtr TopSpace; // the global space public IntPtr TopSpace; // the global space
public IntPtr ActiveSpace; // space for active prims public IntPtr ActiveSpace; // space for active prims
public IntPtr StaticSpace; // space for the static things around public IntPtr StaticSpace; // space for the static things around
public IntPtr GroundSpace; // space for ground
// some speedup variables // some speedup variables
private int spaceGridMaxX; private int spaceGridMaxX;
@ -313,7 +312,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private IntPtr[] staticPrimspaceOffRegion; private IntPtr[] staticPrimspaceOffRegion;
public Object OdeLock; public Object OdeLock;
private static Object SimulationLock; public static Object SimulationLock;
public IMesher mesher; public IMesher mesher;
@ -328,7 +327,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private PhysicsScene m_parentScene = null; private PhysicsScene m_parentScene = null;
private ODERayCastRequestManager m_rayCastManager; private ODERayCastRequestManager m_rayCastManager;
public ODEMeshWorker m_meshWorker;
/* maybe needed if ode uses tls /* maybe needed if ode uses tls
private void checkThread() private void checkThread()
@ -361,6 +360,8 @@ namespace OpenSim.Region.Physics.OdePlugin
nearCallback = near; nearCallback = near;
m_rayCastManager = new ODERayCastRequestManager(this); m_rayCastManager = new ODERayCastRequestManager(this);
lock (OdeLock) lock (OdeLock)
{ {
// Create the world and the first space // Create the world and the first space
@ -372,6 +373,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// now the major subspaces // now the major subspaces
ActiveSpace = d.HashSpaceCreate(TopSpace); ActiveSpace = d.HashSpaceCreate(TopSpace);
StaticSpace = d.HashSpaceCreate(TopSpace); StaticSpace = d.HashSpaceCreate(TopSpace);
GroundSpace = d.HashSpaceCreate(TopSpace);
} }
catch catch
{ {
@ -381,10 +383,12 @@ namespace OpenSim.Region.Physics.OdePlugin
d.HashSpaceSetLevels(TopSpace, -2, 8); d.HashSpaceSetLevels(TopSpace, -2, 8);
d.HashSpaceSetLevels(ActiveSpace, -2, 8); d.HashSpaceSetLevels(ActiveSpace, -2, 8);
d.HashSpaceSetLevels(StaticSpace, -2, 8); d.HashSpaceSetLevels(StaticSpace, -2, 8);
d.HashSpaceSetLevels(GroundSpace, 0, 8);
// demote to second level // demote to second level
d.SpaceSetSublevel(ActiveSpace, 1); d.SpaceSetSublevel(ActiveSpace, 1);
d.SpaceSetSublevel(StaticSpace, 1); d.SpaceSetSublevel(StaticSpace, 1);
d.SpaceSetSublevel(GroundSpace, 1);
d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space | d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space |
CollisionCategories.Geom | CollisionCategories.Geom |
@ -402,6 +406,9 @@ namespace OpenSim.Region.Physics.OdePlugin
)); ));
d.GeomSetCollideBits(StaticSpace, 0); d.GeomSetCollideBits(StaticSpace, 0);
d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundSpace, 0);
contactgroup = d.JointGroupCreate(0); contactgroup = d.JointGroupCreate(0);
//contactgroup //contactgroup
@ -440,9 +447,11 @@ namespace OpenSim.Region.Physics.OdePlugin
int contactsPerCollision = 80; int contactsPerCollision = 80;
IConfig physicsconfig = null;
if (m_config != null) if (m_config != null)
{ {
IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; physicsconfig = m_config.Configs["ODEPhysicsSettings"];
if (physicsconfig != null) if (physicsconfig != null)
{ {
gravityx = physicsconfig.GetFloat("world_gravityx", gravityx); gravityx = physicsconfig.GetFloat("world_gravityx", gravityx);
@ -469,27 +478,7 @@ namespace OpenSim.Region.Physics.OdePlugin
geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity); geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity);
bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable); bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable);
/*
bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", bodyPIDD);
bodyPIDG = physicsconfig.GetFloat("body_pid_gain", bodyPIDG);
*/
forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", meshSculptedPrim);
meshSculptLOD = physicsconfig.GetFloat("mesh_lod", meshSculptLOD);
MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", MeshSculptphysicalLOD);
/*
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", avPIDD);
avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", avPIDP);
}
else
{
avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", avPIDD);
avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", avPIDP);
}
*/
physics_logging = physicsconfig.GetBoolean("physics_logging", false); physics_logging = physicsconfig.GetBoolean("physics_logging", false);
physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
@ -499,6 +488,8 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
} }
m_meshWorker = new ODEMeshWorker(this, m_log, meshmerizer, physicsconfig);
HalfOdeStep = ODE_STEPSIZE * 0.5f; HalfOdeStep = ODE_STEPSIZE * 0.5f;
odetimestepMS = (int)(1000.0f * ODE_STEPSIZE +0.5f); odetimestepMS = (int)(1000.0f * ODE_STEPSIZE +0.5f);
@ -727,6 +718,32 @@ namespace OpenSim.Region.Physics.OdePlugin
if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
return; return;
/*
// debug
PhysicsActor dp2;
if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
{
d.AABB aabb;
d.GeomGetAABB(g2, out aabb);
float x = aabb.MaxX - aabb.MinX;
float y = aabb.MaxY - aabb.MinY;
float z = aabb.MaxZ - aabb.MinZ;
if (x > 60.0f || y > 60.0f || z > 60.0f)
{
if (!actor_name_map.TryGetValue(g2, out dp2))
m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
else
m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})",
dp2.Name, dp2.Size, x, y, z,
dp2.Position.ToString(),
dp2.Orientation.ToString(),
dp2.Orientation.Length());
return;
}
}
//
*/
if(d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc || if(d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc ||
d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc) d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc)
@ -1225,6 +1242,7 @@ namespace OpenSim.Region.Physics.OdePlugin
chr.CollidingObj = false; chr.CollidingObj = false;
// do colisions with static space // do colisions with static space
d.SpaceCollide2(StaticSpace, chr.Shell, IntPtr.Zero, nearCallback); d.SpaceCollide2(StaticSpace, chr.Shell, IntPtr.Zero, nearCallback);
// no coll with gnd
} }
} }
catch (AccessViolationException) catch (AccessViolationException)
@ -1253,7 +1271,10 @@ namespace OpenSim.Region.Physics.OdePlugin
if (!prm.m_outbounds) if (!prm.m_outbounds)
{ {
if (d.BodyIsEnabled(prm.Body)) if (d.BodyIsEnabled(prm.Body))
{
d.SpaceCollide2(StaticSpace, prm.collide_geom, IntPtr.Zero, nearCallback); d.SpaceCollide2(StaticSpace, prm.collide_geom, IntPtr.Zero, nearCallback);
d.SpaceCollide2(GroundSpace, prm.collide_geom, IntPtr.Zero, nearCallback);
}
} }
} }
} }
@ -1295,6 +1316,15 @@ namespace OpenSim.Region.Physics.OdePlugin
_collisionEventPrimRemove.Add(obj); _collisionEventPrimRemove.Add(obj);
} }
public override float TimeDilation
{
get { return m_timeDilation; }
}
public override bool SupportsNINJAJoints
{
get { return false; }
}
#region Add/Remove Entities #region Add/Remove Entities
@ -1350,59 +1380,6 @@ namespace OpenSim.Region.Physics.OdePlugin
((OdeCharacter) actor).Destroy(); ((OdeCharacter) actor).Destroy();
} }
private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
PrimitiveBaseShape pbs, bool isphysical, uint localID)
{
Vector3 pos = position;
Vector3 siz = size;
Quaternion rot = rotation;
OdePrim newPrim;
lock (OdeLock)
{
newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical,false,0,localID);
lock (_prims)
_prims.Add(newPrim);
}
return newPrim;
}
private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, uint localID)
{
Vector3 pos = position;
Vector3 siz = size;
Quaternion rot = rotation;
OdePrim newPrim;
lock (OdeLock)
{
newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical, isPhantom, 0, localID);
lock (_prims)
_prims.Add(newPrim);
}
return newPrim;
}
private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID)
{
Vector3 pos = position;
Vector3 siz = size;
Quaternion rot = rotation;
OdePrim newPrim;
lock (OdeLock)
{
newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical, isPhantom, shapeType, localID);
lock (_prims)
_prims.Add(newPrim);
}
return newPrim;
}
public void addActivePrim(OdePrim activatePrim) public void addActivePrim(OdePrim activatePrim)
{ {
@ -1423,44 +1400,39 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
} }
private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID)
{
OdePrim newPrim;
lock (OdeLock)
{
newPrim = new OdePrim(name, this, position, size, rotation, pbs, isphysical, isPhantom, shapeType, localID);
lock (_prims)
_prims.Add(newPrim);
}
return newPrim;
}
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid) Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid)
{ {
return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, localid); return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, 0 , localid);
} }
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical, uint localid) Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
{ {
#if SPAM return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid);
m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
#endif
return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
} }
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid) Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid)
{ {
#if SPAM
m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
#endif
return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid); return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid);
} }
public override float TimeDilation
{
get { return m_timeDilation; }
}
public override bool SupportsNINJAJoints
{
get { return false; }
}
public void remActivePrim(OdePrim deactivatePrim) public void remActivePrim(OdePrim deactivatePrim)
{ {
lock (_activeprims) lock (_activeprims)
@ -1513,6 +1485,28 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
} }
public bool havePrim(OdePrim prm)
{
lock (_prims)
return _prims.Contains(prm);
}
public bool haveActor(PhysicsActor actor)
{
if (actor is OdePrim)
{
lock (_prims)
return _prims.Contains((OdePrim)actor);
}
else if (actor is OdeCharacter)
{
lock (_characters)
return _characters.Contains((OdeCharacter)actor);
}
return false;
}
#endregion #endregion
#region Space Separation Calculation #region Space Separation Calculation
@ -1615,135 +1609,6 @@ namespace OpenSim.Region.Physics.OdePlugin
#endregion #endregion
/// <summary>
/// Routine to figure out if we need to mesh this prim with our mesher
/// </summary>
/// <param name="pbs"></param>
/// <returns></returns>
public bool needsMeshing(PrimitiveBaseShape pbs)
{
// check sculpts or meshs
if (pbs.SculptEntry)
{
if (meshSculptedPrim)
return true;
if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs
return true;
return false;
}
if (forceSimplePrimMeshing)
return true;
// if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
|| (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
{
if (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)
{
#if SPAM
m_log.Warn("NonMesh");
#endif
return false;
}
}
// following code doesn't give meshs to boxes and spheres ever
// and it's odd.. so for now just return true if asked to force meshs
// hopefully mesher will fail if doesn't suport so things still get basic boxes
int iPropertiesNotSupportedDefault = 0;
if (pbs.ProfileHollow != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
iPropertiesNotSupportedDefault++;
if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
iPropertiesNotSupportedDefault++;
if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
iPropertiesNotSupportedDefault++;
// test for torus
if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
{
if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
{
if (pbs.PathCurve == (byte)Extrusion.Straight)
{
iPropertiesNotSupportedDefault++;
}
// ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
else if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
{
if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
{
if (pbs.PathCurve == (byte)Extrusion.Straight)
{
iPropertiesNotSupportedDefault++;
}
else if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
if (iPropertiesNotSupportedDefault == 0)
{
#if SPAM
m_log.Warn("NonMesh");
#endif
return false;
}
#if SPAM
m_log.Debug("Mesh");
#endif
return true;
}
/// <summary> /// <summary>
/// Called to queue a change to a actor /// Called to queue a change to a actor
@ -1766,8 +1631,52 @@ namespace OpenSim.Region.Physics.OdePlugin
/// </summary> /// </summary>
/// <param name="prim"></param> /// <param name="prim"></param>
public override void AddPhysicsActorTaint(PhysicsActor prim) public override void AddPhysicsActorTaint(PhysicsActor prim)
{
}
// does all pending changes generated during region load process
public override void PrepareSimulation()
{
lock (OdeLock)
{ {
if (world == IntPtr.Zero)
{
ChangesQueue.Clear();
return;
}
ODEchangeitem item;
int donechanges = 0;
if (ChangesQueue.Count > 0)
{
m_log.InfoFormat("[ODE] start processing pending actor operations");
int tstart = Util.EnvironmentTickCount();
while (ChangesQueue.Dequeue(out item))
{
if (item.actor != null)
{
try
{
if (item.actor is OdeCharacter)
((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
RemovePrimThreadLocked((OdePrim)item.actor);
}
catch
{
m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}",
item.actor.Name, item.what.ToString());
}
}
donechanges++;
}
int time = Util.EnvironmentTickCountSubtract(tstart);
m_log.InfoFormat("[ODE] finished {0} operations in {1}ms", donechanges, time);
}
} }
}
/// <summary> /// <summary>
/// This is our main simulate loop /// This is our main simulate loop
@ -1813,21 +1722,17 @@ namespace OpenSim.Region.Physics.OdePlugin
lock(OdeLock) lock(OdeLock)
{ {
if (world == IntPtr.Zero) if (world == IntPtr.Zero)
return 0;
// adjust number of iterations per step
// try
// {
d.WorldSetQuickStepNumIterations(world, curphysiteractions);
/* }
catch (StackOverflowException)
{ {
m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim."); ChangesQueue.Clear();
// ode.drelease(world); return 0;
base.TriggerPhysicsBasedRestart();
} }
*/
ODEchangeitem item;
d.WorldSetQuickStepNumIterations(world, curphysiteractions);
while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever
{ {
try try
@ -1835,14 +1740,12 @@ namespace OpenSim.Region.Physics.OdePlugin
// clear pointer/counter to contacts to pass into joints // clear pointer/counter to contacts to pass into joints
m_global_contactcount = 0; m_global_contactcount = 0;
ODEchangeitem item; if (ChangesQueue.Count > 0)
if(ChangesQueue.Count >0)
{ {
int ttmpstart = Util.EnvironmentTickCount(); int ttmpstart = Util.EnvironmentTickCount();
int ttmp; int ttmp;
while(ChangesQueue.Dequeue(out item)) while (ChangesQueue.Dequeue(out item))
{ {
if (item.actor != null) if (item.actor != null)
{ {
@ -1851,12 +1754,13 @@ namespace OpenSim.Region.Physics.OdePlugin
if (item.actor is OdeCharacter) if (item.actor is OdeCharacter)
((OdeCharacter)item.actor).DoAChange(item.what, item.arg); ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
RemovePrimThreadLocked((OdePrim)item.actor); RemovePrimThreadLocked((OdePrim)item.actor);
} }
catch catch
{ {
m_log.Warn("[PHYSICS]: doChange failed for a actor"); m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}",
}; item.actor.Name, item.what.ToString());
}
} }
ttmp = Util.EnvironmentTickCountSubtract(ttmpstart); ttmp = Util.EnvironmentTickCountSubtract(ttmpstart);
if (ttmp > 20) if (ttmp > 20)
@ -1994,10 +1898,47 @@ namespace OpenSim.Region.Physics.OdePlugin
mesher.ExpireReleaseMeshs(); mesher.ExpireReleaseMeshs();
m_lastMeshExpire = now; m_lastMeshExpire = now;
} }
// information block running in debug only
/* /*
int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
int ngroundgeoms = d.SpaceGetNumGeoms(GroundSpace);
int nactivegeoms = 0;
int nactivespaces = 0;
int nstaticgeoms = 0;
int nstaticspaces = 0;
IntPtr sp;
for (int i = 0; i < ntopactivegeoms; i++)
{
sp = d.SpaceGetGeom(ActiveSpace, i);
if (d.GeomIsSpace(sp))
{
nactivespaces++;
nactivegeoms += d.SpaceGetNumGeoms(sp);
}
else
nactivegeoms++;
}
for (int i = 0; i < ntopstaticgeoms; i++)
{
sp = d.SpaceGetGeom(StaticSpace, i);
if (d.GeomIsSpace(sp))
{
nstaticspaces++;
nstaticgeoms += d.SpaceGetNumGeoms(sp);
}
else
nstaticgeoms++;
}
int ntopgeoms = d.SpaceGetNumGeoms(TopSpace); int ntopgeoms = d.SpaceGetNumGeoms(TopSpace);
int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray
int nbodies = d.NTotalBodies; int nbodies = d.NTotalBodies;
int ngeoms = d.NTotalGeoms; int ngeoms = d.NTotalGeoms;
*/ */
@ -2294,7 +2235,9 @@ namespace OpenSim.Region.Physics.OdePlugin
offset, thickness, wrap); offset, thickness, wrap);
d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
GroundGeom = d.CreateHeightfield(StaticSpace, HeightmapData, 1);
GroundGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1);
if (GroundGeom != IntPtr.Zero) if (GroundGeom != IntPtr.Zero)
{ {
d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land)); d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
@ -2415,12 +2358,13 @@ namespace OpenSim.Region.Physics.OdePlugin
thickness, wrap); thickness, wrap);
// d.GeomUbitTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); // d.GeomUbitTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
GroundGeom = d.CreateUbitTerrain(StaticSpace, HeightmapData, 1); GroundGeom = d.CreateUbitTerrain(GroundSpace, HeightmapData, 1);
if (GroundGeom != IntPtr.Zero) if (GroundGeom != IntPtr.Zero)
{ {
d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land)); d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundGeom, 0); d.GeomSetCollideBits(GroundGeom, 0);
PhysicsActor pa = new NullPhysicsActor(); PhysicsActor pa = new NullPhysicsActor();
pa.Name = "Terrain"; pa.Name = "Terrain";
pa.PhysicsActorType = (int)ActorTypes.Ground; pa.PhysicsActorType = (int)ActorTypes.Ground;
@ -2599,6 +2543,9 @@ namespace OpenSim.Region.Physics.OdePlugin
*/ */
public override void Dispose() public override void Dispose()
{ {
if (m_meshWorker != null)
m_meshWorker.Stop();
lock (OdeLock) lock (OdeLock)
{ {
m_rayCastManager.Dispose(); m_rayCastManager.Dispose();
@ -2633,6 +2580,7 @@ namespace OpenSim.Region.Physics.OdePlugin
d.GeomDestroy(GroundGeom); d.GeomDestroy(GroundGeom);
} }
RegionTerrain.Clear(); RegionTerrain.Clear();
if (TerrainHeightFieldHeightsHandlers.Count > 0) if (TerrainHeightFieldHeightsHandlers.Count > 0)