Merge branch 'avination' into careminster

Conflicts:
	OpenSim/Framework/WebUtil.cs
	OpenSim/Region/Physics/OdePlugin/OdeScene.cs
avinationmerge
Melanie 2012-10-18 20:56:34 +01:00
commit 72c925a6c9
23 changed files with 2359 additions and 1226 deletions

View File

@ -733,7 +733,8 @@ namespace OpenSim.Framework
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount();
int tickdata = 0;
// int tickdata = 0;
int tickdiff = 0;
Type type = typeof(TRequest);
@ -776,8 +777,8 @@ namespace OpenSim.Framework
requestStream.Close();
// capture how much time was spent writing
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
// useless in this async
// tickdata = Util.EnvironmentTickCountSubtract(tickstart);
request.BeginGetResponse(delegate(IAsyncResult ar)
{
response = request.EndGetResponse(ar);
@ -794,7 +795,8 @@ namespace OpenSim.Framework
finally
{
// Let's not close this
//buffer.Close();
// yes do close it
buffer.Close();
respStream.Close();
response.Close();
}
@ -862,7 +864,6 @@ namespace OpenSim.Framework
}
// m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
try
{
action(deserial);
@ -877,9 +878,10 @@ namespace OpenSim.Framework
}, null);
}
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime)
{
/*
string originalRequest = null;
if (buffer != null)
@ -898,12 +900,19 @@ namespace OpenSim.Framework
tickdiff,
tickdata,
originalRequest);
*/
m_log.InfoFormat(
"[ASYNC REQUEST]: Slow WebRequest SETUP <{0}> {1} {2} took {3}ms",
reqnum,
verb,
requestUrl,
tickdiff);
}
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
"[WEB UTIL]: HTTP OUT {0} took {1}ms",
reqnum, tickdiff);
}
}
}
@ -938,6 +947,8 @@ namespace OpenSim.Framework
request.Method = verb;
string respstring = String.Empty;
int tickset = Util.EnvironmentTickCountSubtract(tickstart);
using (MemoryStream buffer = new MemoryStream())
{
if ((verb == "POST") || (verb == "PUT"))
@ -1019,6 +1030,7 @@ namespace OpenSim.Framework
verb,
requestUrl,
tickdiff,
tickset,
tickdata,
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
else if (WebUtil.DebugLevel >= 4)

View File

@ -1117,17 +1117,17 @@ namespace OpenSim.Region.ClientStack.Linden
else
{
AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
if (client != null)
{
// let users see anything.. i don't so far
string str;
if (cost > 0)
// dont remember where is money unit name to put here
str = "Upload complete. charged " + cost.ToString() + "$";
else
str = "Upload complete";
client.SendAgentAlertMessage(str, true);
}
// if (client != null)
// {
// // let users see anything.. i don't so far
// string str;
// if (cost > 0)
// // dont remember where is money unit name to put here
// str = "Upload complete. charged " + cost.ToString() + "$";
// else
// str = "Upload complete";
// client.SendAgentAlertMessage(str, true);
// }
}
}

View File

@ -104,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
public void RegisterCaps(UUID agentID, Caps caps)
{
if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID))
if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
return;
UUID capID = UUID.Random();

View File

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

View File

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

View File

@ -1095,9 +1095,9 @@ namespace OpenSim.Region.Framework.Scenes
{
actor.Size = m_shape.Scale;
if (Shape.SculptEntry)
CheckSculptAndLoad();
else
// if (Shape.SculptEntry)
// CheckSculptAndLoad();
// else
ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
}
}
@ -1583,7 +1583,9 @@ namespace OpenSim.Region.Framework.Scenes
float cost = 0.1f;
if (PhysActor != null)
// cost += PhysActor.Cost;
cost = PhysActor.PhysicsCost;
else
cost = 0.1f;
if ((Flags & PrimFlags.Physics) != 0)
cost *= (1.0f + 0.01333f * Scale.LengthSquared()); // 0.01333 == 0.04/3
@ -1596,9 +1598,12 @@ namespace OpenSim.Region.Framework.Scenes
{
get
{
return 0.1f;
float cost;
if (PhysActor != null)
cost = PhysActor.StreamCost;
else
cost = 1.0f;
return 1.0f;
}
}
@ -1654,8 +1659,8 @@ namespace OpenSim.Region.Framework.Scenes
else
{
PhysActor.PhysicsShapeType = m_physicsShapeType;
if (Shape.SculptEntry)
CheckSculptAndLoad();
// if (Shape.SculptEntry)
// CheckSculptAndLoad();
}
if (ParentGroup != null)
@ -2115,12 +2120,13 @@ namespace OpenSim.Region.Framework.Scenes
if (userExposed)
{
/*
if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero)
{
ParentGroup.Scene.AssetService.Get(
dupe.m_shape.SculptTexture.ToString(), dupe, dupe.AssetReceived);
}
*/
bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0);
dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
// dupe.UpdatePhysicsSubscribedEvents(); // not sure...
@ -2142,6 +2148,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="id">ID of asset received</param>
/// <param name="sender">Register</param>
/// <param name="asset"></param>
/*
protected void AssetReceived(string id, Object sender, AssetBase asset)
{
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",
// Name, UUID, id);
}
*/
/// <summary>
/// Do a physics property update for a NINJA joint.
/// </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
// mesh data.
if (Shape.SculptEntry)
CheckSculptAndLoad();
else
// if (Shape.SculptEntry)
// CheckSculptAndLoad();
// else
ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
}
}
@ -3128,6 +3135,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Set sculpt and mesh data, and tell the physics engine to process the change.
/// </summary>
/// <param name="texture">The mesh itself.</param>
/*
public void SculptTextureCallback(AssetBase texture)
{
if (m_shape.SculptEntry)
@ -3155,7 +3163,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
}
*/
/// <summary>
/// Send a full update to the client for the given part
/// </summary>
@ -4397,7 +4405,7 @@ namespace OpenSim.Region.Framework.Scenes
public void UpdateExtraParam(ushort type, bool inUse, byte[] data)
{
m_shape.ReadInUpdateExtraParam(type, inUse, data);
/*
if (type == 0x30)
{
if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero)
@ -4405,7 +4413,7 @@ namespace OpenSim.Region.Framework.Scenes
ParentGroup.Scene.AssetService.Get(m_shape.SculptTexture.ToString(), this, AssetReceived);
}
}
*/
if (ParentGroup != null)
{
ParentGroup.HasGroupChanged = true;
@ -4813,9 +4821,9 @@ namespace OpenSim.Region.Framework.Scenes
}
}
if (Shape.SculptEntry)
CheckSculptAndLoad();
else
// if (Shape.SculptEntry)
// CheckSculptAndLoad();
// else
ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
if (!building)
@ -4969,10 +4977,13 @@ namespace OpenSim.Region.Framework.Scenes
/// <remarks>
/// When the physics engine has finished with it, the sculpt data is discarded to save memory.
/// </remarks>
/*
public void CheckSculptAndLoad()
{
// m_log.DebugFormat("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
return;
if (ParentGroup.IsDeleted)
return;
@ -4994,7 +5005,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
}
*/
/// <summary>
/// Update the texture entry for this part.
/// </summary>
@ -5262,6 +5273,7 @@ namespace OpenSim.Region.Framework.Scenes
}
Quaternion rot = Quaternion.Slerp(RotationOffset,APIDTarget,1.0f/(float)m_APIDIterations);
rot.Normalize();
UpdateRotation(rot);
m_APIDIterations--;

View File

@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin
convex = false;
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
{
@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin
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
{

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, 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 ExpireReleaseMeshs();
void ExpireFileCache();
}
// Values for level of detail to be passed to the mesher.
@ -57,6 +59,7 @@ namespace OpenSim.Region.Physics.Manager
{
}
[Serializable()]
[StructLayout(LayoutKind.Explicit)]
public struct AMeshKey
{
@ -66,6 +69,13 @@ namespace OpenSim.Region.Physics.Manager
public ulong hashA;
[FieldOffset(8)]
public ulong hashB;
[FieldOffset(16)]
public ulong hashC;
public override string ToString()
{
return uuid.ToString() + "-" + hashC.ToString("x") ;
}
}
public interface IMesh
@ -81,5 +91,6 @@ namespace OpenSim.Region.Physics.Manager
void Append(IMesh newMesh);
void TransformLinear(float[,] matrix, float[] offset);
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>
/// Velocity of this actor.
/// </summary>

View File

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

View File

@ -67,7 +67,7 @@ namespace OpenSim.Region.Physics.Manager
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);
}
@ -79,7 +79,14 @@ namespace OpenSim.Region.Physics.Manager
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 ExpireReleaseMeshs() { }
public void ExpireFileCache() { }
}
}

View File

@ -148,6 +148,12 @@ namespace OpenSim.Region.Physics.Meshing
return Vector3.Zero;
}
// not functional
public Vector3 GetOBB()
{
return new Vector3(0.5f, 0.5f, 0.5f);
}
public void CalcNormals()
{
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)
{
// A vertex is 3 floats
vertexStride = 3 * sizeof(float);
// If there isn't an unmanaged array allocated yet, do it now

View File

@ -74,8 +74,6 @@ namespace OpenSim.Region.Physics.Meshing
#endif
private bool cacheSculptMaps = true;
private bool cacheSculptAlphaMaps = true;
private string decodedSculptMapPath = null;
private bool useMeshiesPhysicsMesh = false;
@ -89,16 +87,7 @@ namespace OpenSim.Region.Physics.Meshing
IConfig mesh_config = config.Configs["Mesh"];
decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
cacheSculptAlphaMaps = false;
}
else
cacheSculptAlphaMaps = cacheSculptMaps;
if(mesh_config != null)
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))
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
{
if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
return null;
}
// keep compatible
// Remove the reference to any JPEG2000 sculpt data so it can be GCed
primShape.SculptData = Utils.EmptyBytes;
int numCoords = coords.Count;
@ -335,7 +321,7 @@ namespace OpenSim.Region.Physics.Meshing
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;
}
@ -496,8 +482,7 @@ namespace OpenSim.Region.Physics.Meshing
//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)
if (cacheSculptMaps)
{
try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
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);
}
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);
}
@ -763,7 +748,13 @@ namespace OpenSim.Region.Physics.Meshing
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 ExpireReleaseMeshs() { }
public void ExpireFileCache() { }
}
}

View File

@ -100,6 +100,9 @@ namespace OpenSim.Region.Physics.OdePlugin
private Vector3 m_taintAngularLock = Vector3.One;
private IntPtr Amotor = IntPtr.Zero;
private object m_assetsLock = new object();
private bool m_assetFailed = false;
private Vector3 m_PIDTarget;
private float m_PIDTau;
private float PID_D = 35f;
@ -282,6 +285,7 @@ namespace OpenSim.Region.Physics.OdePlugin
}
m_taintadd = true;
m_assetFailed = false;
_parent_scene.AddPhysicsActorTaint(this);
}
@ -604,8 +608,8 @@ namespace OpenSim.Region.Physics.OdePlugin
break;
case HollowShape.Circle:
// Hollow shape is a perfect cylinder in respect to the cube's scale
// Cylinder hollow volume calculation
// Hollow shape is a perfect cyllinder in respect to the cube's scale
// Cyllinder hollow volume calculation
hollowVolume *= 0.1963495f * 3.07920140172638f;
break;
@ -1498,6 +1502,8 @@ Console.WriteLine("CreateGeom:");
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.
// m_log.Debug(m_localID);
if (mesh == null)
CheckMeshAsset();
}
#if SPAM
@ -1997,7 +2003,12 @@ Console.WriteLine(" JointCreateFixed");
// Don't need to re-enable body.. it's done in SetMesh
if (_parent_scene.needsMeshing(_pbs))
{
mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
if (mesh == null)
CheckMeshAsset();
}
}
CreateGeom(m_targetSpace, mesh);
@ -2057,6 +2068,8 @@ Console.WriteLine(" JointCreateFixed");
/// </summary>
private void changeshape()
{
m_taintshape = false;
// Cleanup of old prim geometry and Bodies
if (IsPhysical && Body != IntPtr.Zero)
{
@ -2084,6 +2097,7 @@ Console.WriteLine(" JointCreateFixed");
IMesh mesh = null;
if (_parent_scene.needsMeshing(_pbs))
{
// Don't need to re-enable body.. it's done in CreateMesh
@ -2094,6 +2108,8 @@ Console.WriteLine(" JointCreateFixed");
// createmesh returns null when it doesn't mesh.
mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
if (mesh == null)
CheckMeshAsset();
}
CreateGeom(m_targetSpace, mesh);
@ -2130,7 +2146,7 @@ Console.WriteLine(" JointCreateFixed");
}
resetCollisionAccounting();
m_taintshape = false;
// m_taintshape = false;
}
/// <summary>
@ -2396,6 +2412,7 @@ Console.WriteLine(" JointCreateFixed");
set
{
_pbs = value;
m_assetFailed = false;
m_taintshape = true;
}
}
@ -3234,5 +3251,37 @@ Console.WriteLine(" JointCreateFixed");
{
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();
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
}
catch
{
//Fail silently
}
if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
RayCast(reqs[i]); // if there isn't anyone to send results
}
m_PendingRequests.Clear();

View File

@ -32,24 +32,49 @@ using System.Runtime.InteropServices;
using OpenSim.Region.Physics.Manager;
using PrimMesher;
using OpenMetaverse;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
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
{
private Dictionary<Vertex, int> m_vertices;
private List<Triangle> m_triangles;
GCHandle m_pinnedVertexes;
GCHandle m_pinnedIndex;
float[] vertices;
int[] indexes;
Vector3 m_obb;
Vector3 m_obboffset;
[NonSerialized()]
MeshBuildingData m_bdata;
[NonSerialized()]
GCHandle vhandler;
[NonSerialized()]
GCHandle ihandler;
[NonSerialized()]
IntPtr m_verticesPtr = IntPtr.Zero;
int m_vertexCount = 0;
[NonSerialized()]
IntPtr m_indicesPtr = IntPtr.Zero;
[NonSerialized()]
int m_vertexCount = 0;
[NonSerialized()]
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>
{
@ -73,43 +98,119 @@ namespace OpenSim.Region.Physics.Meshing
{
vertexcomp vcomp = new vertexcomp();
m_vertices = new Dictionary<Vertex, int>(vcomp);
m_triangles = new List<Triangle>();
m_centroid = Vector3.Zero;
m_centroidDiv = 0;
m_bdata = new MeshBuildingData();
m_bdata.m_vertices = new Dictionary<Vertex, int>(vcomp);
m_bdata.m_triangles = new List<Triangle>();
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 void Scale(Vector3 scale)
public Mesh 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()
{
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_centroidDiv = m_centroidDiv;
result.m_obb = m_obb;
result.m_obboffset = m_obboffset;
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)
{
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");
// 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)
|| (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)
@ -118,113 +219,59 @@ namespace OpenSim.Region.Physics.Meshing
return;
}
if (m_vertices.Count == 0)
if (m_bdata.m_vertices.Count == 0)
{
m_centroidDiv = 0;
m_centroid = Vector3.Zero;
m_bdata.m_centroidDiv = 0;
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_centroid.X += triangle.v1.X;
m_centroid.Y += triangle.v1.Y;
m_centroid.Z += triangle.v1.Z;
m_centroidDiv++;
m_bdata.m_vertices[triangle.v1] = m_bdata.m_vertices.Count;
addVertexLStats(triangle.v1);
}
if (!m_vertices.ContainsKey(triangle.v2))
if (!m_bdata.m_vertices.ContainsKey(triangle.v2))
{
m_vertices[triangle.v2] = m_vertices.Count;
m_centroid.X += triangle.v2.X;
m_centroid.Y += triangle.v2.Y;
m_centroid.Z += triangle.v2.Z;
m_centroidDiv++;
m_bdata.m_vertices[triangle.v2] = m_bdata.m_vertices.Count;
addVertexLStats(triangle.v2);
}
if (!m_vertices.ContainsKey(triangle.v3))
if (!m_bdata.m_vertices.ContainsKey(triangle.v3))
{
m_vertices[triangle.v3] = m_vertices.Count;
m_centroid.X += triangle.v3.X;
m_centroid.Y += triangle.v3.Y;
m_centroid.Z += triangle.v3.Z;
m_centroidDiv++;
m_bdata.m_vertices[triangle.v3] = m_bdata.m_vertices.Count;
addVertexLStats(triangle.v3);
}
m_triangles.Add(triangle);
m_bdata.m_triangles.Add(triangle);
}
public Vector3 GetCentroid()
{
if (m_centroidDiv > 0)
return new Vector3(m_centroid.X / m_centroidDiv, m_centroid.Y / m_centroidDiv, m_centroid.Z / m_centroidDiv);
else
return Vector3.Zero;
return m_obboffset;
}
public void CalcNormals()
public Vector3 GetOBB()
{
int iTriangles = m_triangles.Count;
this.m_normals = new float[iTriangles * 3];
int i = 0;
foreach (Triangle t in m_triangles)
return m_obb;
float x, y, z;
if (m_bdata.m_centroidDiv > 0)
{
float ux, uy, uz;
float vx, vy, vz;
float wx, wy, wz;
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;
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 // ??
{
x = 0.5f;
y = 0.5f;
z = 0.5f;
}
return new Vector3(x, y, z);
}
public List<Vector3> getVertexList()
{
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));
}
@ -233,10 +280,10 @@ namespace OpenSim.Region.Physics.Meshing
private float[] getVertexListAsFloat()
{
if (m_vertices == null)
if (m_bdata.m_vertices == null)
throw new NotSupportedException();
float[] result = new float[m_vertices.Count * 3];
foreach (KeyValuePair<Vertex, int> kvp in m_vertices)
float[] result = new float[m_bdata.m_vertices.Count * 3];
foreach (KeyValuePair<Vertex, int> kvp in m_bdata.m_vertices)
{
Vertex v = kvp.Key;
int i = kvp.Value;
@ -249,48 +296,39 @@ namespace OpenSim.Region.Physics.Meshing
public float[] getVertexListAsFloatLocked()
{
if (m_pinnedVertexes.IsAllocated)
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;
return null;
}
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
vertexStride = 3 * sizeof(float);
// 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)
m_vertexCount = vertexList.Length / 3;
int byteCount = m_vertexCount * vertexStride;
m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount);
System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3);
m_vertexCount = vertices.Length / 3;
vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
m_verticesPtr = vhandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(vertices));
}
vertices = m_verticesPtr;
_vertices = m_verticesPtr;
vertexCount = m_vertexCount;
}
public int[] getIndexListAsInt()
{
if (m_triangles == null)
if (m_bdata.m_triangles == null)
throw new NotSupportedException();
int[] result = new int[m_triangles.Count * 3];
for (int i = 0; i < m_triangles.Count; i++)
int[] result = new int[m_bdata.m_triangles.Count * 3];
for (int i = 0; i < m_bdata.m_triangles.Count; i++)
{
Triangle t = m_triangles[i];
result[3 * i + 0] = m_vertices[t.v1];
result[3 * i + 1] = m_vertices[t.v2];
result[3 * i + 2] = m_vertices[t.v3];
Triangle t = m_bdata.m_triangles[i];
result[3 * i + 0] = m_bdata.m_vertices[t.v1];
result[3 * i + 1] = m_bdata.m_vertices[t.v2];
result[3 * i + 2] = m_bdata.m_vertices[t.v3];
}
return result;
}
@ -301,28 +339,19 @@ namespace OpenSim.Region.Physics.Meshing
/// <returns></returns>
public int[] getIndexListAsIntLocked()
{
if (m_pinnedIndex.IsAllocated)
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;
return null;
}
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 (m_indicesPtr == IntPtr.Zero)
if (m_indicesPtr == IntPtr.Zero && m_bdata != null)
{
int[] indexList = getIndexListAsInt();
m_indexCount = indexList.Length;
int byteCount = m_indexCount * sizeof(int);
m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount);
System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount);
indexes = getIndexListAsInt();
m_indexCount = indexes.Length;
ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
m_indicesPtr = ihandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(indexes));
}
// A triangle is 3 ints (indices)
triStride = 3 * sizeof(int);
@ -332,18 +361,16 @@ namespace OpenSim.Region.Physics.Meshing
public void releasePinned()
{
if (m_pinnedVertexes.IsAllocated)
m_pinnedVertexes.Free();
if (m_pinnedIndex.IsAllocated)
m_pinnedIndex.Free();
if (m_verticesPtr != IntPtr.Zero)
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr);
vhandler.Free();
vertices = null;
m_verticesPtr = IntPtr.Zero;
}
if (m_indicesPtr != IntPtr.Zero)
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr);
ihandler.Free();
indexes = null;
m_indicesPtr = IntPtr.Zero;
}
}
@ -353,29 +380,42 @@ namespace OpenSim.Region.Physics.Meshing
/// </summary>
public void releaseSourceMeshData()
{
m_triangles = null;
m_vertices = null;
if (m_bdata != 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)
{
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");
if (!(newMesh is Mesh))
return;
foreach (Triangle t in ((Mesh)newMesh).m_triangles)
foreach (Triangle t in ((Mesh)newMesh).m_bdata.m_triangles)
Add(t);
}
// Do a linear transformation of mesh.
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");
foreach (Vertex v in m_vertices.Keys)
foreach (Vertex v in m_bdata.m_vertices.Keys)
{
if (v == null)
continue;
@ -393,10 +433,12 @@ namespace OpenSim.Region.Physics.Meshing
{
if (path == null)
return;
if (m_bdata == null)
return;
String fileName = name + "_" + title + ".raw";
String completePath = System.IO.Path.Combine(path, fileName);
StreamWriter sw = new StreamWriter(completePath);
foreach (Triangle t in m_triangles)
foreach (Triangle t in m_bdata.m_triangles)
{
String s = t.ToStringRaw();
sw.WriteLine(s);
@ -406,7 +448,144 @@ namespace OpenSim.Region.Physics.Meshing
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 ComponentAce.Compression.Libs.zlib;
using OpenSim.Region.Physics.ConvexDecompositionDotNet;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
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
// raw files can be imported by blender so a visual inspection of the results can be done
#if SPAM
const string baseDir = "rawFiles";
#else
public object diskLock = new object();
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";
#endif
private bool cacheSculptMaps = true;
private bool cacheSculptAlphaMaps = true;
private string decodedSculptMapPath = null;
private bool useMeshiesPhysicsMesh = false;
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_uniqueReleasedMeshes = new Dictionary<AMeshKey, Mesh>();
@ -92,29 +94,29 @@ namespace OpenSim.Region.Physics.Meshing
IConfig start_config = config.Configs["Startup"];
IConfig mesh_config = config.Configs["Mesh"];
decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
cacheSculptAlphaMaps = false;
}
else
cacheSculptAlphaMaps = cacheSculptMaps;
float fcache = 48.0f;
// float fcache = 0.02f;
if(mesh_config != null)
{
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>
@ -212,7 +214,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="size">Size of entire object</param>
/// <param name="coords"></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));
@ -245,9 +247,9 @@ namespace OpenSim.Region.Physics.Meshing
ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
Coord c = new Coord(
Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));
coords.Add(c);
}
@ -271,7 +273,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <param name="size"></param>
/// <param name="lod"></param>
/// <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(
// "[MESH]: Creating physics proxy for {0}, shape {1}",
@ -287,18 +289,18 @@ namespace OpenSim.Region.Physics.Meshing
if (!useMeshiesPhysicsMesh)
return null;
if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces, convex))
if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, out coords, out faces, convex))
return null;
}
else
{
if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, lod, out coords, out faces))
return null;
}
}
else
{
if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, out coords, out faces))
return null;
}
@ -333,7 +335,7 @@ namespace OpenSim.Region.Physics.Meshing
/// <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>
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);
@ -345,7 +347,7 @@ namespace OpenSim.Region.Physics.Meshing
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;
}
@ -406,7 +408,7 @@ namespace OpenSim.Region.Physics.Meshing
OSD decodedMeshOsd = new OSD();
byte[] meshBytes = new byte[physSize];
System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
// byte[] decompressed = new byte[physSize * 5];
try
{
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
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;
foreach (OSD subMeshOsd in decodedMeshOsdArray)
{
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++] << 8;
f3 = new float3((t1 * range.X + min.X) * size.X,
(t2 * range.Y + min.Y) * size.Y,
(t3 * range.Z + min.Z) * size.Z);
f3 = new float3((t1 * range.X + min.X),
(t2 * range.Y + min.Y),
(t3 * range.Z + min.Z));
vs.Add(f3);
}
@ -621,9 +623,9 @@ namespace OpenSim.Region.Physics.Meshing
t3 = data[i++];
t3 += data[i++] << 8;
f3 = new float3((t1 * range.X + min.X) * size.X,
(t2 * range.Y + min.Y) * size.Y,
(t3 * range.Z + min.Z) * size.Z);
f3 = new float3((t1 * range.X + min.X),
(t2 * range.Y + min.Y),
(t3 * range.Z + min.Z));
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>
/// <returns>true if coords and faces were successfully generated, false if not</returns>
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>();
faces = new List<Face>();
PrimMesher.SculptMesh sculptMesh;
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)
return false;
@ -748,25 +728,15 @@ namespace OpenSim.Region.Physics.Meshing
OpenMetaverse.Imaging.ManagedImage unusedData;
OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
unusedData = null;
if (idata == null)
{
// In some cases it seems that the decode can return a null bitmap without throwing
// an exception
m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
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)
{
@ -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);
return false;
}
}
PrimMesher.SculptMesh.SculptType sculptType;
// remove mirror and invert bits
@ -814,9 +783,7 @@ namespace OpenSim.Region.Physics.Meshing
idata.Dispose();
sculptMesh.DumpRaw(baseDir, primName, "primMesh");
sculptMesh.Scale(size.X, size.Y, size.Z);
// sculptMesh.DumpRaw(baseDir, primName, "primMesh");
coords = sculptMesh.coords;
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>
/// <returns>true if coords and faces were successfully generated, false if not</returns>
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;
coords = new List<Coord>();
@ -969,9 +936,7 @@ namespace OpenSim.Region.Physics.Meshing
}
}
primMesh.DumpRaw(baseDir, primName, "primMesh");
primMesh.Scale(size.X, size.Y, size.Z);
// primMesh.DumpRaw(baseDir, primName, "primMesh");
coords = primMesh.coords;
faces = primMesh.faces;
@ -985,12 +950,14 @@ namespace OpenSim.Region.Physics.Meshing
Byte[] someBytes;
key.hashB = 5181;
key.hashC = 5181;
ulong hash = 5381;
if (primShape.SculptEntry)
{
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
{
@ -1002,6 +969,8 @@ namespace OpenSim.Region.Physics.Meshing
hash = mdjb2(hash, primShape.PathScaleX);
hash = mdjb2(hash, primShape.PathScaleY);
hash = mdjb2(hash, primShape.PathShearX);
key.hashA = hash;
hash = key.hashB;
hash = mdjb2(hash, primShape.PathShearY);
hash = mdjb2(hash, (byte)primShape.PathTwist);
hash = mdjb2(hash, (byte)primShape.PathTwistBegin);
@ -1013,26 +982,38 @@ namespace OpenSim.Region.Physics.Meshing
hash = mdjb2(hash, primShape.ProfileBegin);
hash = mdjb2(hash, primShape.ProfileEnd);
hash = mdjb2(hash, primShape.ProfileHollow);
key.hashA = hash;
hash = mdjb2(hash, primShape.PCode);
key.hashB = hash;
}
hash = key.hashB;
someBytes = size.GetBytes();
for (int i = 0; i < someBytes.Length; i++)
hash = mdjb2(hash, someBytes[i]);
hash = key.hashC;
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)
hash |= 0x4000000000000000;
hash |= 4;
if (primShape.SculptEntry)
hash |= 0x8000000000000000;
{
hash |= 1;
if (primShape.SculptType == (byte)SculptType.Mesh)
hash |= 2;
}
key.hashB = hash;
key.hashC = hash;
return key;
}
@ -1048,35 +1029,74 @@ namespace OpenSim.Region.Physics.Meshing
return ((hash << 5) + hash) + (ulong)(c >> 8);
}
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)
{
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
m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
#endif
Mesh mesh = null;
// ulong key = 0;
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;
// try to find a identical mesh on meshs in use
// key = primShape.GetMeshKey(size, lod, convex);
AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex);
lock (m_uniqueMeshes)
@ -1098,33 +1118,76 @@ namespace OpenSim.Region.Physics.Meshing
{
m_uniqueReleasedMeshes.Remove(key);
lock (m_uniqueMeshes)
m_uniqueMeshes.Add(key, mesh);
{
try
{
m_uniqueMeshes.Add(key, mesh);
}
catch { }
}
mesh.RefCount = 1;
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
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");
UnitMesh.RefCount = 1;
}
}
// trim the vertex and triangle lists to free up memory
mesh.TrimExcess();
mesh.Key = key;
mesh.RefCount = 1;
if (UnitMesh == null && primShape.SculptEntry && doMeshFileCache)
UnitMesh = GetFromFileCache(unitKey);
lock(m_uniqueMeshes)
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;
@ -1137,21 +1200,27 @@ namespace OpenSim.Region.Physics.Meshing
Mesh mesh = (Mesh)imesh;
int curRefCount = mesh.RefCount;
curRefCount--;
if (curRefCount > 0)
{
mesh.RefCount = curRefCount;
return;
}
lock (m_uniqueMeshes)
{
int curRefCount = mesh.RefCount;
curRefCount--;
if (curRefCount > 0)
{
mesh.RefCount = curRefCount;
return;
}
mesh.RefCount = 0;
m_uniqueMeshes.Remove(mesh.Key);
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)
{
m_uniqueReleasedMeshes.Remove(m.Key);
m.releaseSourceMeshData();
m.releaseBuildingMeshData();
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
m_density = 3.0f;
mu = parent_scene.AvatarFriction;
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.Normal = direction;
req.Origin = position;
req.filter = RayFilterFlags.AllPrims;
req.filter = RayFilterFlags.AllPrims | RayFilterFlags.land;
m_PendingRequests.Enqueue(req);
}
@ -288,7 +288,10 @@ namespace OpenSim.Region.Physics.OdePlugin
catflags |= CollisionCategories.Water;
if (catflags != 0)
{
d.GeomSetCollideBits(ray, (uint)catflags);
doSpaceRay(req);
}
}
else
{
@ -314,7 +317,8 @@ namespace OpenSim.Region.Physics.OdePlugin
///
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)
{
@ -323,6 +327,16 @@ namespace OpenSim.Region.Physics.OdePlugin
d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
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)
{

View File

@ -60,6 +60,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public int lastframe;
}
// colision flags of things others can colide with
// rays, sensors, probes removed since can't be colided with
// The top space where things are placed provided further selection
@ -147,6 +148,8 @@ namespace OpenSim.Region.Physics.OdePlugin
Size,
Shape,
PhysRepData,
AddPhysRep,
CollidesWater,
VolumeDtc,
@ -230,11 +233,6 @@ namespace OpenSim.Region.Physics.OdePlugin
private float minimumGroundFlightOffset = 3f;
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;
@ -302,6 +300,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public IntPtr TopSpace; // the global space
public IntPtr ActiveSpace; // space for active prims
public IntPtr StaticSpace; // space for the static things around
public IntPtr GroundSpace; // space for ground
// some speedup variables
private int spaceGridMaxX;
@ -313,7 +312,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private IntPtr[] staticPrimspaceOffRegion;
public Object OdeLock;
private static Object SimulationLock;
public static Object SimulationLock;
public IMesher mesher;
@ -328,7 +327,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private PhysicsScene m_parentScene = null;
private ODERayCastRequestManager m_rayCastManager;
public ODEMeshWorker m_meshWorker;
/* maybe needed if ode uses tls
private void checkThread()
@ -361,6 +360,8 @@ namespace OpenSim.Region.Physics.OdePlugin
nearCallback = near;
m_rayCastManager = new ODERayCastRequestManager(this);
lock (OdeLock)
{
// Create the world and the first space
@ -372,6 +373,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// now the major subspaces
ActiveSpace = d.HashSpaceCreate(TopSpace);
StaticSpace = d.HashSpaceCreate(TopSpace);
GroundSpace = d.HashSpaceCreate(TopSpace);
}
catch
{
@ -381,10 +383,12 @@ namespace OpenSim.Region.Physics.OdePlugin
d.HashSpaceSetLevels(TopSpace, -2, 8);
d.HashSpaceSetLevels(ActiveSpace, -2, 8);
d.HashSpaceSetLevels(StaticSpace, -2, 8);
d.HashSpaceSetLevels(GroundSpace, 0, 8);
// demote to second level
d.SpaceSetSublevel(ActiveSpace, 1);
d.SpaceSetSublevel(StaticSpace, 1);
d.SpaceSetSublevel(GroundSpace, 1);
d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space |
CollisionCategories.Geom |
@ -402,6 +406,9 @@ namespace OpenSim.Region.Physics.OdePlugin
));
d.GeomSetCollideBits(StaticSpace, 0);
d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundSpace, 0);
contactgroup = d.JointGroupCreate(0);
//contactgroup
@ -440,9 +447,11 @@ namespace OpenSim.Region.Physics.OdePlugin
int contactsPerCollision = 80;
IConfig physicsconfig = null;
if (m_config != null)
{
IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
physicsconfig = m_config.Configs["ODEPhysicsSettings"];
if (physicsconfig != null)
{
gravityx = physicsconfig.GetFloat("world_gravityx", gravityx);
@ -469,27 +478,7 @@ namespace OpenSim.Region.Physics.OdePlugin
geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity);
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_interval = physicsconfig.GetInt("physics_logging_interval", 0);
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;
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))
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 ||
d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc)
@ -1225,6 +1242,7 @@ namespace OpenSim.Region.Physics.OdePlugin
chr.CollidingObj = false;
// do colisions with static space
d.SpaceCollide2(StaticSpace, chr.Shell, IntPtr.Zero, nearCallback);
// no coll with gnd
}
}
catch (AccessViolationException)
@ -1253,7 +1271,10 @@ namespace OpenSim.Region.Physics.OdePlugin
if (!prm.m_outbounds)
{
if (d.BodyIsEnabled(prm.Body))
{
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);
}
public override float TimeDilation
{
get { return m_timeDilation; }
}
public override bool SupportsNINJAJoints
{
get { return false; }
}
#region Add/Remove Entities
@ -1350,59 +1380,6 @@ namespace OpenSim.Region.Physics.OdePlugin
((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)
{
@ -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,
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,
Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
{
#if SPAM
m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
#endif
return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid);
}
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
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);
}
public override float TimeDilation
{
get { return m_timeDilation; }
}
public override bool SupportsNINJAJoints
{
get { return false; }
}
public void remActivePrim(OdePrim deactivatePrim)
{
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
#region Space Separation Calculation
@ -1615,135 +1609,6 @@ namespace OpenSim.Region.Physics.OdePlugin
#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>
/// Called to queue a change to a actor
@ -1766,8 +1631,52 @@ namespace OpenSim.Region.Physics.OdePlugin
/// </summary>
/// <param name="prim"></param>
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>
/// This is our main simulate loop
@ -1813,21 +1722,17 @@ namespace OpenSim.Region.Physics.OdePlugin
lock(OdeLock)
{
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.");
// ode.drelease(world);
base.TriggerPhysicsBasedRestart();
ChangesQueue.Clear();
return 0;
}
*/
ODEchangeitem item;
d.WorldSetQuickStepNumIterations(world, curphysiteractions);
while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever
{
try
@ -1835,14 +1740,12 @@ namespace OpenSim.Region.Physics.OdePlugin
// clear pointer/counter to contacts to pass into joints
m_global_contactcount = 0;
ODEchangeitem item;
if(ChangesQueue.Count >0)
if (ChangesQueue.Count > 0)
{
int ttmpstart = Util.EnvironmentTickCount();
int ttmp;
while(ChangesQueue.Dequeue(out item))
while (ChangesQueue.Dequeue(out item))
{
if (item.actor != null)
{
@ -1851,12 +1754,13 @@ namespace OpenSim.Region.Physics.OdePlugin
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);
RemovePrimThreadLocked((OdePrim)item.actor);
}
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);
if (ttmp > 20)
@ -1994,10 +1898,47 @@ namespace OpenSim.Region.Physics.OdePlugin
mesher.ExpireReleaseMeshs();
m_lastMeshExpire = now;
}
// information block running in debug only
/*
int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
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 totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray
int nbodies = d.NTotalBodies;
int ngeoms = d.NTotalGeoms;
*/
@ -2294,7 +2235,9 @@ namespace OpenSim.Region.Physics.OdePlugin
offset, thickness, wrap);
d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
GroundGeom = d.CreateHeightfield(StaticSpace, HeightmapData, 1);
GroundGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1);
if (GroundGeom != IntPtr.Zero)
{
d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
@ -2415,12 +2358,13 @@ namespace OpenSim.Region.Physics.OdePlugin
thickness, wrap);
// d.GeomUbitTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
GroundGeom = d.CreateUbitTerrain(StaticSpace, HeightmapData, 1);
GroundGeom = d.CreateUbitTerrain(GroundSpace, HeightmapData, 1);
if (GroundGeom != IntPtr.Zero)
{
d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundGeom, 0);
PhysicsActor pa = new NullPhysicsActor();
pa.Name = "Terrain";
pa.PhysicsActorType = (int)ActorTypes.Ground;
@ -2599,6 +2543,9 @@ namespace OpenSim.Region.Physics.OdePlugin
*/
public override void Dispose()
{
if (m_meshWorker != null)
m_meshWorker.Stop();
lock (OdeLock)
{
m_rayCastManager.Dispose();
@ -2633,6 +2580,7 @@ namespace OpenSim.Region.Physics.OdePlugin
d.GeomDestroy(GroundGeom);
}
RegionTerrain.Clear();
if (TerrainHeightFieldHeightsHandlers.Count > 0)