diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index a03d62697a..b85d93d53a 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -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) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index f509d94c03..f6146a9171 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -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); +// } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs index bac71b0175..fcac182f45 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs @@ -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(); diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 233e559c13..edf2befc0d 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -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; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 985f0a0ba9..782a1af138 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -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(); } /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 2d90a22367..248679bdef 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -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 /// ID of asset received /// Register /// +/* 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); } - +*/ /// /// Do a physics property update for a NINJA joint. /// @@ -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. /// /// The mesh itself. +/* public void SculptTextureCallback(AssetBase texture) { if (m_shape.SculptEntry) @@ -3155,7 +3163,7 @@ namespace OpenSim.Region.Framework.Scenes } } } - +*/ /// /// Send a full update to the client for the given part /// @@ -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 /// /// When the physics engine has finished with it, the sculpt data is discarded to save memory. /// +/* 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 } } } - +*/ /// /// Update the texture entry for this part. /// @@ -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--; diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs index 5b743e8a02..8de70efaca 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs @@ -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 { diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index a8c99f7e67..ecc2918862 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs @@ -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(); } } diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index a2c72c30fb..14f65b8e14 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -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; + } + } + /// /// Velocity of this actor. /// diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 5274f3b471..ce269fabc1 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -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() { } + /// /// Perform a simulation of the current physics scene over the given timestep. /// diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs index f555cb9253..16846e612f 100644 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs @@ -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() { } } } diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs index c715642bac..6970553818 100644 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ b/OpenSim/Region/Physics/Meshing/Mesh.cs @@ -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 diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 3c4f737f9e..f629c4d60b 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -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() { } } } diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index eb02536907..7a0857faaf 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -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"); /// 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; } /// @@ -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); + } + } } } \ No newline at end of file diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs index 7e3ec63d23..8d7d3b3ae9 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs @@ -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(); diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index cbe21e20f9..d53bd90b61 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -4320,4 +4320,4 @@ namespace OpenSim.Region.Physics.OdePlugin m_stats[ODEPrimUpdateFrameMsStatName] = 0; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs index 98c0f0b458..1e9b8bc895 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs @@ -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 m_vertices; + public List 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 m_vertices; - private List 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 { @@ -73,43 +98,119 @@ namespace OpenSim.Region.Physics.Meshing { vertexcomp vcomp = new vertexcomp(); - m_vertices = new Dictionary(vcomp); - m_triangles = new List(); - m_centroid = Vector3.Zero; - m_centroidDiv = 0; + m_bdata = new MeshBuildingData(); + m_bdata.m_vertices = new Dictionary(vcomp); + m_bdata.m_triangles = new List(); + 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 getVertexList() { List result = new List(); - 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 kvp in m_vertices) + float[] result = new float[m_bdata.m_vertices.Count * 3]; + foreach (KeyValuePair 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 /// 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 /// 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; } } } diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs index 4c40175b76..29fdda4af6 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs @@ -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 m_uniqueMeshes = new Dictionary(); -// private Dictionary m_uniqueReleasedMeshes = new Dictionary(); private Dictionary m_uniqueMeshes = new Dictionary(); private Dictionary m_uniqueReleasedMeshes = new Dictionary(); @@ -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); - } } /// @@ -212,7 +214,7 @@ namespace OpenSim.Region.Physics.Meshing /// Size of entire object /// /// - private void AddSubMesh(OSDMap subMeshData, Vector3 size, List coords, List faces) + private void AddSubMesh(OSDMap subMeshData, List coords, List 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 /// /// /// - 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 /// Faces are added to this list by the method. /// true if coords and faces were successfully generated, false if not private bool GenerateCoordsAndFacesFromPrimMeshData( - string primName, PrimitiveBaseShape primShape, Vector3 size, out List coords, out List faces, bool convex) + string primName, PrimitiveBaseShape primShape, out List coords, out List 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 /// Faces are added to this list by the method. /// true if coords and faces were successfully generated, false if not private bool GenerateCoordsAndFacesFromPrimSculptData( - string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List coords, out List faces) + string primName, PrimitiveBaseShape primShape, float lod, out List coords, out List faces) { coords = new List(); faces = new List(); 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 /// Faces are added to this list by the method. /// true if coords and faces were successfully generated, false if not private bool GenerateCoordsAndFacesFromPrimShapeData( - string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List coords, out List faces) + string primName, PrimitiveBaseShape primShape, float lod, out List coords, out List faces) { PrimMesh primMesh; coords = new List(); @@ -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,35 +1118,78 @@ 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; - - lock(m_uniqueMeshes) - m_uniqueMeshes.Add(key, mesh); } + if (UnitMesh == null && primShape.SculptEntry && doMeshFileCache) + UnitMesh = GetFromFileCache(unitKey); + + if (UnitMesh == null) + { + UnitMesh = CreateMeshFromPrimMesher(primName, primShape, lod, convex); + + if (UnitMesh == null) + return null; + + UnitMesh.DumpRaw(baseDir, unitKey.ToString(), "Z"); + + if (forOde) + { + // force pinned mem allocation + UnitMesh.PrepForOde(); + } + else + UnitMesh.TrimExcess(); + + UnitMesh.Key = unitKey; + UnitMesh.RefCount = 1; + + if (doMeshFileCache && primShape.SculptEntry) + StoreToFileCache(unitKey, UnitMesh); + + lock (m_uniqueReleasedMeshes) + { + try + { + m_uniqueReleasedMeshes.Add(unitKey, UnitMesh); + } + catch { } + } + } + + mesh = UnitMesh.Scale(size); + mesh.Key = key; + mesh.RefCount = 1; + lock (m_uniqueMeshes) + { + try + { + m_uniqueMeshes.Add(key, mesh); + } + catch { } + } + return mesh; } @@ -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 { } + } + } } } diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs index c363310b16..f5bf05d1a0 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs @@ -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; diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs new file mode 100644 index 0000000000..73dd2fd49b --- /dev/null +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs @@ -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 createqueue = new OpenSim.Framework.BlockingQueue(); + 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); + } + + + /// + /// Routine to figure out if we need to mesh this prim with our mesher + /// + /// + /// + 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); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs index f2f4725900..ce67cc469e 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs @@ -79,7 +79,7 @@ namespace OpenSim.Region.Physics.OdePlugin private bool m_lastdoneSelected; internal bool m_outbounds; - private Quaternion m_lastorientation = new Quaternion(); + private Quaternion m_lastorientation; private Quaternion _orientation; private Vector3 _position; @@ -91,33 +91,30 @@ namespace OpenSim.Region.Physics.OdePlugin private Vector3 _size; private Vector3 _acceleration; private Vector3 m_angularlock = Vector3.One; - private IntPtr Amotor = IntPtr.Zero; + private IntPtr Amotor; private Vector3 m_force; private Vector3 m_forceacc; private Vector3 m_angularForceacc; - private float m_invTimeStep = 50.0f; - private float m_timeStep = .02f; + private float m_invTimeStep; + private float m_timeStep; private Vector3 m_PIDTarget; private float m_PIDTau; private bool m_usePID; - // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau), - // and are for non-VEHICLES only. - private float m_PIDHoverHeight; private float m_PIDHoverTau; private bool m_useHoverPID; - private PIDHoverType m_PIDHoverType = PIDHoverType.Ground; + private PIDHoverType m_PIDHoverType; private float m_targetHoverHeight; private float m_groundHeight; private float m_waterHeight; private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. - private int body_autodisable_frames = 5; - public int bodydisablecontrol = 0; + private int body_autodisable_frames; + public int bodydisablecontrol; // Default we're a Geometry @@ -147,12 +144,16 @@ namespace OpenSim.Region.Physics.OdePlugin private IMesh m_mesh; private object m_meshlock = new object(); private PrimitiveBaseShape _pbs; + + private UUID? m_assetID; + private MeshState m_meshState; + public OdeScene _parent_scene; /// /// The physics space which contains prim geometry /// - public IntPtr m_targetSpace = IntPtr.Zero; + public IntPtr m_targetSpace; public IntPtr prim_geom; public IntPtr _triMeshData; @@ -166,27 +167,32 @@ namespace OpenSim.Region.Physics.OdePlugin public IntPtr collide_geom; // for objects: geom if single prim space it linkset - private float m_density = 10.000006836f; // Aluminum g/cm3; + private float m_density; private byte m_shapetype; public bool _zeroFlag; private bool m_lastUpdateSent; - public IntPtr Body = IntPtr.Zero; + public IntPtr Body; private Vector3 _target_velocity; - public Vector3 primOOBsize; // prim real dimensions from mesh - public Vector3 primOOBoffset; // its centroid out of mesh or rest aabb + public Vector3 m_OBBOffset; + public Vector3 m_OBB; public float primOOBradiusSQ; + + private bool m_hasOBB = true; + + private float m_physCost; + private float m_streamCost; + public d.Mass primdMass; // prim inertia information on it's own referencial float primMass; // prim own mass float primVolume; // prim own volume; float _mass; // object mass acording to case - private bool hasOOBoffsetFromMesh = false; // if true we did compute it form mesh centroid, else from aabb - public int givefakepos = 0; + public int givefakepos; private Vector3 fakepos; - public int givefakeori = 0; + public int givefakeori; private Quaternion fakeori; private int m_eventsubscription; @@ -271,7 +277,23 @@ namespace OpenSim.Region.Physics.OdePlugin cdata.mu *= veh.FrictionFactor; // cdata.mu *= 0; } - } + } + + public override float PhysicsCost + { + get + { + return m_physCost; + } + } + + public override float StreamCost + { + get + { + return m_streamCost; + } + } public override int PhysicsActorType { @@ -394,7 +416,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (value.IsFinite()) { - AddChange(changes.Size, value); + _parent_scene.m_meshWorker.ChangeActorPhysRep(this, _pbs, value, m_shapetype); } else { @@ -464,7 +486,7 @@ namespace OpenSim.Region.Physics.OdePlugin q.Z = dq.Z; q.W = dq.W; - Vector3 Ptot = primOOBoffset * q; + Vector3 Ptot = m_OBBOffset * q; dtmp = d.GeomGetPosition(prim_geom); Ptot.X += dtmp.X; Ptot.Y += dtmp.Y; @@ -504,7 +526,7 @@ namespace OpenSim.Region.Physics.OdePlugin { get { - return primOOBsize; + return m_OBB; } } @@ -512,7 +534,7 @@ namespace OpenSim.Region.Physics.OdePlugin { get { - return primOOBoffset; + return m_OBBOffset; } } @@ -528,7 +550,8 @@ namespace OpenSim.Region.Physics.OdePlugin { set { - AddChange(changes.Shape, value); +// AddChange(changes.Shape, value); + _parent_scene.m_meshWorker.ChangeActorPhysRep(this, value, _size, m_shapetype); } } @@ -541,11 +564,10 @@ namespace OpenSim.Region.Physics.OdePlugin set { m_shapetype = value; - AddChange(changes.Shape, null); + _parent_scene.m_meshWorker.ChangeActorPhysRep(this, _pbs, _size, value); } } - public override Vector3 Velocity { get @@ -619,6 +641,9 @@ namespace OpenSim.Region.Physics.OdePlugin { fakeori = value; givefakeori++; + + value.Normalize(); + AddChange(changes.Orientation, value); } else @@ -1012,7 +1037,6 @@ namespace OpenSim.Region.Physics.OdePlugin m_invTimeStep = 1f / m_timeStep; m_density = parent_scene.geomDefaultDensity; - // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; body_autodisable_frames = parent_scene.bodyFramesAutoDisable; prim_geom = IntPtr.Zero; @@ -1064,7 +1088,6 @@ namespace OpenSim.Region.Physics.OdePlugin m_colliderfilter = 0; m_NoColide = false; - hasOOBoffsetFromMesh = false; _triMeshData = IntPtr.Zero; m_shapetype = _shapeType; @@ -1079,27 +1102,14 @@ namespace OpenSim.Region.Physics.OdePlugin mu = parent_scene.m_materialContactsData[(int)Material.Wood].mu; bounce = parent_scene.m_materialContactsData[(int)Material.Wood].bounce; - CalcPrimBodyData(); - - m_mesh = null; - if (_parent_scene.needsMeshing(pbs) && (pbs.SculptData.Length > 0)) - { - bool convex; - int clod = (int)LevelOfDetail.High; - if (m_shapetype == 0) - convex = false; - else - { - convex = true; - if (_pbs.SculptType != (byte)SculptType.Mesh) - clod = (int)LevelOfDetail.Low; - } - m_mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, clod, true, convex); - } - m_building = true; // control must set this to false when done - AddChange(changes.Add, null); + // get basic mass parameters + ODEPhysRepData repData = _parent_scene.m_meshWorker.NewActorPhysRep(this, _pbs, _size, m_shapetype); + + primVolume = repData.volume; + + UpdatePrimBodyData(); } private void resetCollisionAccounting() @@ -1323,105 +1333,6 @@ namespace OpenSim.Region.Physics.OdePlugin } } - private bool setMesh(OdeScene parent_scene) - { - IntPtr vertices, indices; - int vertexCount, indexCount; - int vertexStride, triStride; - - if (Body != IntPtr.Zero) - { - if (childPrim) - { - if (_parent != null) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildDelink(this, false); - } - } - else - { - DestroyBody(); - } - } - - IMesh mesh = null; - - lock (m_meshlock) - { - if (m_mesh == null) - { - bool convex; - int clod = (int)LevelOfDetail.High; - - if (m_shapetype == 0) - convex = false; - else - { - convex = true; - if (_pbs.SculptType != (byte)SculptType.Mesh) - clod = (int)LevelOfDetail.Low; - } - - mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, clod, true, convex); - } - else - { - mesh = m_mesh; - } - - if (mesh == null) - { - m_log.WarnFormat("[PHYSICS]: CreateMesh Failed on prim {0} at <{1},{2},{3}>.", Name, _position.X, _position.Y, _position.Z); - return false; - } - - - mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap - mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage - - if (vertexCount == 0 || indexCount == 0) - { - m_log.WarnFormat("[PHYSICS]: Got invalid mesh on prim {0} at <{1},{2},{3}>. mesh UUID {4}", - Name, _position.X, _position.Y, _position.Z, _pbs.SculptTexture.ToString()); - mesh.releaseSourceMeshData(); - return false; - } - - primOOBoffset = mesh.GetCentroid(); - hasOOBoffsetFromMesh = true; - - mesh.releaseSourceMeshData(); - m_mesh = mesh; - } - - IntPtr geo = IntPtr.Zero; - - try - { - _triMeshData = d.GeomTriMeshDataCreate(); - - d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); - d.GeomTriMeshDataPreprocess(_triMeshData); - - _parent_scene.waitForSpaceUnlock(m_targetSpace); - geo = d.CreateTriMesh(m_targetSpace, _triMeshData, null, null, null); - } - - catch (Exception e) - { - m_log.ErrorFormat("[PHYSICS]: SetGeom Mesh failed for {0} exception: {1}", Name, e); - if (_triMeshData != IntPtr.Zero) - { - d.GeomTriMeshDataDestroy(_triMeshData); - _triMeshData = IntPtr.Zero; - } - return false; - } - - SetGeom(geo); - return true; - } private void SetGeom(IntPtr geom) { @@ -1449,49 +1360,139 @@ namespace OpenSim.Region.Physics.OdePlugin d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); } - CalcPrimBodyData(); - + UpdatePrimBodyData(); _parent_scene.actor_name_map[prim_geom] = this; +/* +// debug + d.AABB aabb; + d.GeomGetAABB(prim_geom, 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) + m_log.WarnFormat("[PHYSICS]: large prim geo {0},size {1}, AABBsize <{2},{3},{4}, mesh {5} at {6}", + Name, _size.ToString(), x, y, z, _pbs.SculptEntry ? _pbs.SculptTexture.ToString() : "primMesh", _position.ToString()); + else if (x < 0.001f || y < 0.001f || z < 0.001f) + m_log.WarnFormat("[PHYSICS]: small prim geo {0},size {1}, AABBsize <{2},{3},{4}, mesh {5} at {6}", + Name, _size.ToString(), x, y, z, _pbs.SculptEntry ? _pbs.SculptTexture.ToString() : "primMesh", _position.ToString()); + +// +*/ + } else m_log.Warn("Setting bad Geom"); } - - /// - /// Create a geometry for the given mesh in the given target space. - /// - /// - /// If null, then a mesh is used that is based on the profile shape data. - private void CreateGeom() + private bool GetMeshGeom() { - if (_triMeshData != IntPtr.Zero) + IntPtr vertices, indices; + int vertexCount, indexCount; + int vertexStride, triStride; + + IMesh mesh = m_mesh; + + if (mesh == null) + return false; + + mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); + mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); + + if (vertexCount == 0 || indexCount == 0) { - d.GeomTriMeshDataDestroy(_triMeshData); - _triMeshData = IntPtr.Zero; + m_log.WarnFormat("[PHYSICS]: Invalid mesh data on OdePrim {0}, mesh {1}", + Name, _pbs.SculptEntry ? _pbs.SculptTexture.ToString() : "primMesh"); + + m_hasOBB = false; + m_OBBOffset = Vector3.Zero; + m_OBB = _size * 0.5f; + + m_physCost = 0.1f; + m_streamCost = 1.0f; + + _parent_scene.mesher.ReleaseMesh(mesh); + m_meshState = MeshState.MeshFailed; + m_mesh = null; + return false; } - bool haveMesh = false; - hasOOBoffsetFromMesh = false; + IntPtr geo = IntPtr.Zero; + + try + { + _triMeshData = d.GeomTriMeshDataCreate(); + + d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); + d.GeomTriMeshDataPreprocess(_triMeshData); + + geo = d.CreateTriMesh(m_targetSpace, _triMeshData, null, null, null); + } + + catch (Exception e) + { + m_log.ErrorFormat("[PHYSICS]: SetGeom Mesh failed for {0} exception: {1}", Name, e); + if (_triMeshData != IntPtr.Zero) + { + try + { + d.GeomTriMeshDataDestroy(_triMeshData); + } + catch + { + } + } + _triMeshData = IntPtr.Zero; + + m_hasOBB = false; + m_OBBOffset = Vector3.Zero; + m_OBB = _size * 0.5f; + m_physCost = 0.1f; + m_streamCost = 1.0f; + + _parent_scene.mesher.ReleaseMesh(mesh); + m_meshState = MeshState.MeshFailed; + m_mesh = null; + return false; + } + + m_physCost = 0.0013f * (float)indexCount; + // todo + m_streamCost = 1.0f; + + SetGeom(geo); + + return true; + } + + private void CreateGeom() + { + bool hasMesh = false; + m_NoColide = false; - if (_parent_scene.needsMeshing(_pbs)) + if ((m_meshState & MeshState.MeshNoColide) != 0) + m_NoColide = true; + + else if(m_mesh != null) { - haveMesh = setMesh(_parent_scene); // this will give a mesh to non trivial known prims - if (!haveMesh) + if (GetMeshGeom()) + hasMesh = true; + else m_NoColide = true; } - if (!haveMesh) + + if (!hasMesh) { + IntPtr geo = IntPtr.Zero; + if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1 && _size.X == _size.Y && _size.Y == _size.Z) { // it's a sphere - _parent_scene.waitForSpaceUnlock(m_targetSpace); try { - SetGeom(d.CreateSphere(m_targetSpace, _size.X * 0.5f)); + geo = d.CreateSphere(m_targetSpace, _size.X * 0.5f); } catch (Exception e) { @@ -1501,11 +1502,9 @@ namespace OpenSim.Region.Physics.OdePlugin } else {// do it as a box - _parent_scene.waitForSpaceUnlock(m_targetSpace); try { - //Console.WriteLine(" CreateGeom 4"); - SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + geo = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z); } catch (Exception e) { @@ -1513,19 +1512,18 @@ namespace OpenSim.Region.Physics.OdePlugin return; } } + m_physCost = 0.1f; + m_streamCost = 1.0f; + SetGeom(geo); } } - /// - /// Set a new geometry for this prim. - /// - /// private void RemoveGeom() { if (prim_geom != IntPtr.Zero) { -// _parent_scene.geom_name_map.Remove(prim_geom); _parent_scene.actor_name_map.Remove(prim_geom); + try { d.GeomDestroy(prim_geom); @@ -1534,11 +1532,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.GeomTriMeshDataDestroy(_triMeshData); _triMeshData = IntPtr.Zero; } - } - - - // catch (System.AccessViolationException) catch (Exception e) { m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction failed for {0} exception {1}", Name, e); @@ -1546,29 +1540,26 @@ namespace OpenSim.Region.Physics.OdePlugin prim_geom = IntPtr.Zero; collide_geom = IntPtr.Zero; + m_targetSpace = IntPtr.Zero; } else { m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction BAD {0}", Name); } - if (m_mesh != null) + lock (m_meshlock) { - _parent_scene.mesher.ReleaseMesh(m_mesh); - m_mesh = null; + if (m_mesh != null) + { + _parent_scene.mesher.ReleaseMesh(m_mesh); + m_mesh = null; + } } Body = IntPtr.Zero; - hasOOBoffsetFromMesh = false; + m_hasOBB = false; } -/* - private void ChildSetGeom(OdePrim odePrim) - { - // well.. - DestroyBody(); - MakeBody(); - } -*/ + //sets non physical prim m_targetSpace to right space in spaces grid for static prims // should only be called for non physical prims unless they are becoming non physical private void SetInStaticSpace(OdePrim prim) @@ -1631,9 +1622,6 @@ namespace OpenSim.Region.Physics.OdePlugin if (Body != IntPtr.Zero) { -// d.BodyDestroy(Body); -// Body = IntPtr.Zero; - // do a more complet destruction DestroyBody(); m_log.Warn("[PHYSICS]: MakeBody called having a body"); } @@ -2143,339 +2131,9 @@ namespace OpenSim.Region.Physics.OdePlugin #region Mass Calculation - private float CalculatePrimVolume() + private void UpdatePrimBodyData() { - 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); - - return volume; - } - - - private void CalcPrimBodyData() - { - float volume; - - if (prim_geom == IntPtr.Zero) - { - // Ubit let's have a initial basic OOB - primOOBsize.X = _size.X; - primOOBsize.Y = _size.Y; - primOOBsize.Z = _size.Z; - primOOBoffset = Vector3.Zero; - } - else - { - d.AABB AABB; - d.GeomGetAABB(prim_geom, out AABB); // get the AABB from engine geom - - primOOBsize.X = (AABB.MaxX - AABB.MinX); - primOOBsize.Y = (AABB.MaxY - AABB.MinY); - primOOBsize.Z = (AABB.MaxZ - AABB.MinZ); - if (!hasOOBoffsetFromMesh) - { - primOOBoffset.X = (AABB.MaxX + AABB.MinX) * 0.5f; - primOOBoffset.Y = (AABB.MaxY + AABB.MinY) * 0.5f; - primOOBoffset.Z = (AABB.MaxZ + AABB.MinZ) * 0.5f; - } - } - - // also its own inertia and mass - // keep using basic shape mass for now - volume = CalculatePrimVolume(); - - primVolume = volume; - primMass = m_density * volume; + primMass = m_density * primVolume; if (primMass <= 0) primMass = 0.0001f;//ckrinke: Mass must be greater then zero. @@ -2484,18 +2142,32 @@ namespace OpenSim.Region.Physics.OdePlugin _mass = primMass; // just in case - d.MassSetBoxTotal(out primdMass, primMass, primOOBsize.X, primOOBsize.Y, primOOBsize.Z); + d.MassSetBoxTotal(out primdMass, primMass, m_OBB.X, m_OBB.Y, m_OBB.Z); d.MassTranslate(ref primdMass, - primOOBoffset.X, - primOOBoffset.Y, - primOOBoffset.Z); + m_OBBOffset.X, + m_OBBOffset.Y, + m_OBBOffset.Z); - primOOBsize *= 0.5f; // let obb size be a corner coords - primOOBradiusSQ = primOOBsize.LengthSquared(); + primOOBradiusSQ = m_OBB.LengthSquared(); + + if (_triMeshData != IntPtr.Zero) + { + float pc = m_physCost; + float psf = primOOBradiusSQ; + psf *= 1.33f * .2f; + pc *= psf; + if (pc < 0.1f) + pc = 0.1f; + + m_physCost = pc; + } + else + m_physCost = 0.1f; + + m_streamCost = 1.0f; } - #endregion @@ -2575,6 +2247,14 @@ namespace OpenSim.Region.Physics.OdePlugin _orientation.Y = qtmp.Y; _orientation.Z = qtmp.Z; _orientation.W = qtmp.W; +/* +// Debug + float qlen = _orientation.Length(); + if (qlen > 1.01f || qlen < 0.99) + m_log.WarnFormat("[PHYSICS]: Got nonnorm quaternion from geom in Object {0} norm {1}", Name, qlen); +// +*/ + _orientation.Normalize(); d.Vector3 lpos = d.GeomGetPosition(prim_geom); _position.X = lpos.X; @@ -2684,27 +2364,6 @@ namespace OpenSim.Region.Physics.OdePlugin private void changeadd() { - CreateGeom(); - - if (prim_geom != IntPtr.Zero) - { - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - d.GeomSetQuaternion(prim_geom, ref myrot); - - if (!m_isphysical) - { - SetInStaticSpace(this); - UpdateCollisionCatFlags(); - ApplyCollisionCatFlags(); - } - else - MakeBody(); - } } private void changeAngularLock(Vector3 newLock) @@ -2774,6 +2433,9 @@ namespace OpenSim.Region.Physics.OdePlugin _target_velocity = Vector3.Zero; if (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) m_vehicle.Stop(); + + _zeroFlag = false; + base.RequestPhysicsterseUpdate(); } if (Body != IntPtr.Zero) @@ -3148,7 +2810,63 @@ namespace OpenSim.Region.Physics.OdePlugin resetCollisionAccounting(); } - private void changeprimsizeshape() + private void changeSize(Vector3 newSize) + { + } + + private void changeShape(PrimitiveBaseShape newShape) + { + } + + private void changeAddPhysRep(ODEPhysRepData repData) + { + _size = repData.size; //?? + _pbs = repData.pbs; + m_shapetype = repData.shapetype; + + m_mesh = repData.mesh; + + m_assetID = repData.assetID; + m_meshState = repData.meshState; + + m_hasOBB = repData.hasOBB; + m_OBBOffset = repData.OBBOffset; + m_OBB = repData.OBB; + + primVolume = repData.volume; + + CreateGeom(); + + if (prim_geom != IntPtr.Zero) + { + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + d.GeomSetQuaternion(prim_geom, ref myrot); + } + + if (!m_isphysical) + { + SetInStaticSpace(this); + UpdateCollisionCatFlags(); + ApplyCollisionCatFlags(); + } + else + MakeBody(); + + if ((m_meshState & MeshState.NeedMask) != 0) + { + repData.size = _size; + repData.pbs = _pbs; + repData.shapetype = m_shapetype; + _parent_scene.m_meshWorker.RequestMesh(repData); + } + } + + private void changePhysRepData(ODEPhysRepData repData) { CheckDelaySelect(); @@ -3170,16 +2888,22 @@ namespace OpenSim.Region.Physics.OdePlugin RemoveGeom(); - // we don't need to do space calculation because the client sends a position update also. - if (_size.X <= 0) - _size.X = 0.01f; - if (_size.Y <= 0) - _size.Y = 0.01f; - if (_size.Z <= 0) - _size.Z = 0.01f; - // Construction of new prim + _size = repData.size; + _pbs = repData.pbs; + m_shapetype = repData.shapetype; - CreateGeom(); + m_mesh = repData.mesh; + + m_assetID = repData.assetID; + m_meshState = repData.meshState; + + m_hasOBB = repData.hasOBB; + m_OBBOffset = repData.OBBOffset; + m_OBB = repData.OBB; + + primVolume = repData.volume; + + CreateGeom(); if (prim_geom != IntPtr.Zero) { @@ -3202,29 +2926,24 @@ namespace OpenSim.Region.Physics.OdePlugin } } else - MakeBody(); + MakeBody(); } - else { + SetInStaticSpace(this); UpdateCollisionCatFlags(); ApplyCollisionCatFlags(); } resetCollisionAccounting(); - } - private void changeSize(Vector3 newSize) - { - _size = newSize; - changeprimsizeshape(); - } - - private void changeShape(PrimitiveBaseShape newShape) - { - if(newShape != null) - _pbs = newShape; - changeprimsizeshape(); + if ((m_meshState & MeshState.NeedMask) != 0) + { + repData.size = _size; + repData.pbs = _pbs; + repData.shapetype = m_shapetype; + _parent_scene.m_meshWorker.RequestMesh(repData); + } } private void changeFloatOnWater(bool newval) @@ -3891,7 +3610,7 @@ namespace OpenSim.Region.Physics.OdePlugin public bool DoAChange(changes what, object arg) { - if (prim_geom == IntPtr.Zero && what != changes.Add && what != changes.Remove) + if (prim_geom == IntPtr.Zero && what != changes.Add && what != changes.AddPhysRep && what != changes.Remove) { return false; } @@ -3902,6 +3621,11 @@ namespace OpenSim.Region.Physics.OdePlugin case changes.Add: changeadd(); break; + + case changes.AddPhysRep: + changeAddPhysRep((ODEPhysRepData)arg); + break; + case changes.Remove: //If its being removed, we don't want to rebuild the physical rep at all, so ignore this stuff... //When we return true, it destroys all of the prims in the linkset anyway @@ -3984,6 +3708,10 @@ namespace OpenSim.Region.Physics.OdePlugin changeShape((PrimitiveBaseShape)arg); break; + case changes.PhysRepData: + changePhysRepData((ODEPhysRepData) arg); + break; + case changes.CollidesWater: changeFloatOnWater((bool)arg); break; @@ -4072,6 +3800,8 @@ namespace OpenSim.Region.Physics.OdePlugin donullchange(); break; + + default: donullchange(); break; diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs index 21fe9c08f7..799a324f4b 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs @@ -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) { diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index f126644d8b..b98f177e86 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -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 @@ -109,7 +110,7 @@ namespace OpenSim.Region.Physics.OdePlugin light = 7 // compatibility with old viewers } - + public enum changes : int { Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?) @@ -147,6 +148,8 @@ namespace OpenSim.Region.Physics.OdePlugin Size, 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 - /// - /// Routine to figure out if we need to mesh this prim with our mesher - /// - /// - /// - 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; - } /// /// Called to queue a change to a actor @@ -1766,8 +1631,52 @@ namespace OpenSim.Region.Physics.OdePlugin /// /// 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); + } } + } /// /// 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)