From 1b2828f5d859d2941167b0457158142e683efe39 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 24 Sep 2009 10:00:31 -0700 Subject: Meshmerizer stores dictionary of unique Meshes keyed on construction parameters. CreateMesh() returns a Mesh from the dictionary or creates a new Mesh if it has not been created before. Meshes are never purged from the dictionary. The raw Mesh data is discarded once the memory is pinned for ODE use. All copies of the same prim/mesh use the same pinned memory. ONLY IMPLEMENTED AND TESTED WITH MESHMERIZER AND ODE Signed-off-by: dahlia --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 69 ++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region/Physics/Meshing/Meshmerizer.cs') diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index f469ad6..0873035 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -76,6 +76,7 @@ namespace OpenSim.Region.Physics.Meshing private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh + private Dictionary m_uniqueMeshes = new Dictionary(); /// /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may @@ -170,9 +171,62 @@ namespace OpenSim.Region.Physics.Meshing } - public Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) + private ulong GetMeshKey( PrimitiveBaseShape pbs, PhysicsVector size, float lod ) + { + ulong hash = 5381; + + hash = djb2(hash, pbs.PathCurve); + hash = djb2(hash, (byte)((byte)pbs.HollowShape | (byte)pbs.ProfileShape)); + hash = djb2(hash, pbs.PathBegin); + hash = djb2(hash, pbs.PathEnd); + hash = djb2(hash, pbs.PathScaleX); + hash = djb2(hash, pbs.PathScaleY); + hash = djb2(hash, pbs.PathShearX); + hash = djb2(hash, pbs.PathShearY); + hash = djb2(hash, (byte)pbs.PathTwist); + hash = djb2(hash, (byte)pbs.PathTwistBegin); + hash = djb2(hash, (byte)pbs.PathRadiusOffset); + hash = djb2(hash, (byte)pbs.PathTaperX); + hash = djb2(hash, (byte)pbs.PathTaperY); + hash = djb2(hash, pbs.PathRevolutions); + hash = djb2(hash, (byte)pbs.PathSkew); + hash = djb2(hash, pbs.ProfileBegin); + hash = djb2(hash, pbs.ProfileEnd); + hash = djb2(hash, pbs.ProfileHollow); + + // TODO: Separate scale out from the primitive shape data (after + // scaling is supported at the physics engine level) + byte[] scaleBytes = size.GetBytes(); + for (int i = 0; i < scaleBytes.Length; i++) + hash = djb2(hash, scaleBytes[i]); + + // Include LOD in hash, accounting for endianness + byte[] lodBytes = new byte[4]; + Buffer.BlockCopy(BitConverter.GetBytes(lod), 0, lodBytes, 0, 4); + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(lodBytes, 0, 4); + } + for (int i = 0; i < lodBytes.Length; i++) + hash = djb2(hash, lodBytes[i]); + + return hash; + } + + private ulong djb2(ulong hash, byte c) + { + return ((hash << 5) + hash) + (ulong)c; + } + + private ulong djb2(ulong hash, ushort c) + { + hash = ((hash << 5) + hash) + (ulong)((byte)c); + return ((hash << 5) + hash) + (ulong)(c >> 8); + } + + + private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) { - Mesh mesh = new Mesh(); PrimMesh primMesh; PrimMesher.SculptMesh sculptMesh; @@ -385,8 +439,6 @@ namespace OpenSim.Region.Physics.Meshing coords = primMesh.coords; faces = primMesh.faces; - - } @@ -401,13 +453,13 @@ namespace OpenSim.Region.Physics.Meshing vertices.Add(new Vertex(c.X, c.Y, c.Z)); } + Mesh mesh = new Mesh(); // Add the corresponding triangles to the mesh for (int i = 0; i < numFaces; i++) { Face f = faces[i]; mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); } - return mesh; } @@ -418,7 +470,12 @@ namespace OpenSim.Region.Physics.Meshing public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod, bool isPhysical) { + // If this mesh has been created already, return it instead of creating another copy + // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory + ulong key = GetMeshKey(primShape, size, lod); Mesh mesh = null; + if (m_uniqueMeshes.TryGetValue(key, out mesh)) + return mesh; if (size.X < 0.01f) size.X = 0.01f; if (size.Y < 0.01f) size.Y = 0.01f; @@ -441,7 +498,7 @@ namespace OpenSim.Region.Physics.Meshing // trim the vertex and triangle lists to free up memory mesh.TrimExcess(); } - + m_uniqueMeshes.Add(key, mesh); return mesh; } } -- cgit v1.1