diff options
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Mesh.cs | 87 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 69 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 17 |
3 files changed, 95 insertions, 78 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs index ceafaad..7567556 100644 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ b/OpenSim/Region/Physics/Meshing/Mesh.cs | |||
@@ -40,7 +40,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
40 | private List<Triangle> triangles; | 40 | private List<Triangle> triangles; |
41 | GCHandle pinnedVirtexes; | 41 | GCHandle pinnedVirtexes; |
42 | GCHandle pinnedIndex; | 42 | GCHandle pinnedIndex; |
43 | public PrimMesh primMesh = null; | ||
44 | public float[] normals; | 43 | public float[] normals; |
45 | 44 | ||
46 | public Mesh() | 45 | public Mesh() |
@@ -63,6 +62,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
63 | 62 | ||
64 | public void Add(Triangle triangle) | 63 | public void Add(Triangle triangle) |
65 | { | 64 | { |
65 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | ||
66 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | ||
66 | // If a vertex of the triangle is not yet in the vertices list, | 67 | // If a vertex of the triangle is not yet in the vertices list, |
67 | // add it and set its index to the current index count | 68 | // add it and set its index to the current index count |
68 | if (!vertices.ContainsKey(triangle.v1)) | 69 | if (!vertices.ContainsKey(triangle.v1)) |
@@ -148,40 +149,22 @@ namespace OpenSim.Region.Physics.Meshing | |||
148 | 149 | ||
149 | public float[] getVertexListAsFloatLocked() | 150 | public float[] getVertexListAsFloatLocked() |
150 | { | 151 | { |
152 | if( pinnedVirtexes.IsAllocated ) | ||
153 | return (float[])(pinnedVirtexes.Target); | ||
151 | float[] result; | 154 | float[] result; |
152 | 155 | ||
153 | if (primMesh == null) | 156 | //m_log.WarnFormat("vertices.Count = {0}", vertices.Count); |
157 | result = new float[vertices.Count * 3]; | ||
158 | foreach (KeyValuePair<Vertex, int> kvp in vertices) | ||
154 | { | 159 | { |
155 | //m_log.WarnFormat("vertices.Count = {0}", vertices.Count); | 160 | Vertex v = kvp.Key; |
156 | result = new float[vertices.Count * 3]; | 161 | int i = kvp.Value; |
157 | foreach (KeyValuePair<Vertex, int> kvp in vertices) | 162 | //m_log.WarnFormat("kvp.Value = {0}", i); |
158 | { | 163 | result[3 * i + 0] = v.X; |
159 | Vertex v = kvp.Key; | 164 | result[3 * i + 1] = v.Y; |
160 | int i = kvp.Value; | 165 | result[3 * i + 2] = v.Z; |
161 | //m_log.WarnFormat("kvp.Value = {0}", i); | ||
162 | result[3 * i + 0] = v.X; | ||
163 | result[3 * i + 1] = v.Y; | ||
164 | result[3 * i + 2] = v.Z; | ||
165 | } | ||
166 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | int count = primMesh.coords.Count; | ||
171 | result = new float[count * 3]; | ||
172 | for (int i = 0; i < count; i++) | ||
173 | { | ||
174 | Coord c = primMesh.coords[i]; | ||
175 | { | ||
176 | int resultIndex = 3 * i; | ||
177 | result[resultIndex] = c.X; | ||
178 | result[resultIndex + 1] = c.Y; | ||
179 | result[resultIndex + 2] = c.Z; | ||
180 | } | ||
181 | |||
182 | } | ||
183 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
184 | } | 166 | } |
167 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
185 | return result; | 168 | return result; |
186 | } | 169 | } |
187 | 170 | ||
@@ -189,33 +172,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
189 | { | 172 | { |
190 | int[] result; | 173 | int[] result; |
191 | 174 | ||
192 | if (primMesh == null) | 175 | result = new int[triangles.Count * 3]; |
193 | { | 176 | for (int i = 0; i < triangles.Count; i++) |
194 | result = new int[triangles.Count * 3]; | ||
195 | for (int i = 0; i < triangles.Count; i++) | ||
196 | { | ||
197 | Triangle t = triangles[i]; | ||
198 | result[3 * i + 0] = vertices[t.v1]; | ||
199 | result[3 * i + 1] = vertices[t.v2]; | ||
200 | result[3 * i + 2] = vertices[t.v3]; | ||
201 | } | ||
202 | } | ||
203 | else | ||
204 | { | 177 | { |
205 | int numFaces = primMesh.faces.Count; | 178 | Triangle t = triangles[i]; |
206 | result = new int[numFaces * 3]; | 179 | result[3 * i + 0] = vertices[t.v1]; |
207 | for (int i = 0; i < numFaces; i++) | 180 | result[3 * i + 1] = vertices[t.v2]; |
208 | { | 181 | result[3 * i + 2] = vertices[t.v3]; |
209 | Face f = primMesh.faces[i]; | ||
210 | // Coord c1 = primMesh.coords[f.v1]; | ||
211 | // Coord c2 = primMesh.coords[f.v2]; | ||
212 | // Coord c3 = primMesh.coords[f.v3]; | ||
213 | |||
214 | int resultIndex = i * 3; | ||
215 | result[resultIndex] = f.v1; | ||
216 | result[resultIndex + 1] = f.v2; | ||
217 | result[resultIndex + 2] = f.v3; | ||
218 | } | ||
219 | } | 182 | } |
220 | return result; | 183 | return result; |
221 | } | 184 | } |
@@ -226,6 +189,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
226 | /// <returns></returns> | 189 | /// <returns></returns> |
227 | public int[] getIndexListAsIntLocked() | 190 | public int[] getIndexListAsIntLocked() |
228 | { | 191 | { |
192 | if (pinnedIndex.IsAllocated) | ||
193 | return (int[])(pinnedIndex.Target); | ||
194 | |||
229 | int[] result = getIndexListAsInt(); | 195 | int[] result = getIndexListAsInt(); |
230 | pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | 196 | pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); |
231 | 197 | ||
@@ -245,11 +211,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
245 | { | 211 | { |
246 | triangles = null; | 212 | triangles = null; |
247 | vertices = null; | 213 | vertices = null; |
248 | primMesh = null; | ||
249 | } | 214 | } |
250 | 215 | ||
251 | public void Append(IMesh newMesh) | 216 | public void Append(IMesh newMesh) |
252 | { | 217 | { |
218 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | ||
219 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | ||
220 | |||
253 | if (!(newMesh is Mesh)) | 221 | if (!(newMesh is Mesh)) |
254 | return; | 222 | return; |
255 | 223 | ||
@@ -260,6 +228,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
260 | // Do a linear transformation of mesh. | 228 | // Do a linear transformation of mesh. |
261 | public void TransformLinear(float[,] matrix, float[] offset) | 229 | public void TransformLinear(float[,] matrix, float[] offset) |
262 | { | 230 | { |
231 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | ||
232 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | ||
233 | |||
263 | foreach (Vertex v in vertices.Keys) | 234 | foreach (Vertex v in vertices.Keys) |
264 | { | 235 | { |
265 | if (v == null) | 236 | if (v == null) |
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 | |||
76 | 76 | ||
77 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh | 77 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh |
78 | 78 | ||
79 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | ||
79 | 80 | ||
80 | /// <summary> | 81 | /// <summary> |
81 | /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may | 82 | /// 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 | |||
170 | 171 | ||
171 | } | 172 | } |
172 | 173 | ||
173 | public Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) | 174 | private ulong GetMeshKey( PrimitiveBaseShape pbs, PhysicsVector size, float lod ) |
175 | { | ||
176 | ulong hash = 5381; | ||
177 | |||
178 | hash = djb2(hash, pbs.PathCurve); | ||
179 | hash = djb2(hash, (byte)((byte)pbs.HollowShape | (byte)pbs.ProfileShape)); | ||
180 | hash = djb2(hash, pbs.PathBegin); | ||
181 | hash = djb2(hash, pbs.PathEnd); | ||
182 | hash = djb2(hash, pbs.PathScaleX); | ||
183 | hash = djb2(hash, pbs.PathScaleY); | ||
184 | hash = djb2(hash, pbs.PathShearX); | ||
185 | hash = djb2(hash, pbs.PathShearY); | ||
186 | hash = djb2(hash, (byte)pbs.PathTwist); | ||
187 | hash = djb2(hash, (byte)pbs.PathTwistBegin); | ||
188 | hash = djb2(hash, (byte)pbs.PathRadiusOffset); | ||
189 | hash = djb2(hash, (byte)pbs.PathTaperX); | ||
190 | hash = djb2(hash, (byte)pbs.PathTaperY); | ||
191 | hash = djb2(hash, pbs.PathRevolutions); | ||
192 | hash = djb2(hash, (byte)pbs.PathSkew); | ||
193 | hash = djb2(hash, pbs.ProfileBegin); | ||
194 | hash = djb2(hash, pbs.ProfileEnd); | ||
195 | hash = djb2(hash, pbs.ProfileHollow); | ||
196 | |||
197 | // TODO: Separate scale out from the primitive shape data (after | ||
198 | // scaling is supported at the physics engine level) | ||
199 | byte[] scaleBytes = size.GetBytes(); | ||
200 | for (int i = 0; i < scaleBytes.Length; i++) | ||
201 | hash = djb2(hash, scaleBytes[i]); | ||
202 | |||
203 | // Include LOD in hash, accounting for endianness | ||
204 | byte[] lodBytes = new byte[4]; | ||
205 | Buffer.BlockCopy(BitConverter.GetBytes(lod), 0, lodBytes, 0, 4); | ||
206 | if (!BitConverter.IsLittleEndian) | ||
207 | { | ||
208 | Array.Reverse(lodBytes, 0, 4); | ||
209 | } | ||
210 | for (int i = 0; i < lodBytes.Length; i++) | ||
211 | hash = djb2(hash, lodBytes[i]); | ||
212 | |||
213 | return hash; | ||
214 | } | ||
215 | |||
216 | private ulong djb2(ulong hash, byte c) | ||
217 | { | ||
218 | return ((hash << 5) + hash) + (ulong)c; | ||
219 | } | ||
220 | |||
221 | private ulong djb2(ulong hash, ushort c) | ||
222 | { | ||
223 | hash = ((hash << 5) + hash) + (ulong)((byte)c); | ||
224 | return ((hash << 5) + hash) + (ulong)(c >> 8); | ||
225 | } | ||
226 | |||
227 | |||
228 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) | ||
174 | { | 229 | { |
175 | Mesh mesh = new Mesh(); | ||
176 | PrimMesh primMesh; | 230 | PrimMesh primMesh; |
177 | PrimMesher.SculptMesh sculptMesh; | 231 | PrimMesher.SculptMesh sculptMesh; |
178 | 232 | ||
@@ -385,8 +439,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
385 | 439 | ||
386 | coords = primMesh.coords; | 440 | coords = primMesh.coords; |
387 | faces = primMesh.faces; | 441 | faces = primMesh.faces; |
388 | |||
389 | |||
390 | } | 442 | } |
391 | 443 | ||
392 | 444 | ||
@@ -401,13 +453,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
401 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); | 453 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); |
402 | } | 454 | } |
403 | 455 | ||
456 | Mesh mesh = new Mesh(); | ||
404 | // Add the corresponding triangles to the mesh | 457 | // Add the corresponding triangles to the mesh |
405 | for (int i = 0; i < numFaces; i++) | 458 | for (int i = 0; i < numFaces; i++) |
406 | { | 459 | { |
407 | Face f = faces[i]; | 460 | Face f = faces[i]; |
408 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); | 461 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); |
409 | } | 462 | } |
410 | |||
411 | return mesh; | 463 | return mesh; |
412 | } | 464 | } |
413 | 465 | ||
@@ -418,7 +470,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
418 | 470 | ||
419 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod, bool isPhysical) | 471 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod, bool isPhysical) |
420 | { | 472 | { |
473 | // If this mesh has been created already, return it instead of creating another copy | ||
474 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | ||
475 | ulong key = GetMeshKey(primShape, size, lod); | ||
421 | Mesh mesh = null; | 476 | Mesh mesh = null; |
477 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
478 | return mesh; | ||
422 | 479 | ||
423 | if (size.X < 0.01f) size.X = 0.01f; | 480 | if (size.X < 0.01f) size.X = 0.01f; |
424 | if (size.Y < 0.01f) size.Y = 0.01f; | 481 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -441,7 +498,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
441 | // trim the vertex and triangle lists to free up memory | 498 | // trim the vertex and triangle lists to free up memory |
442 | mesh.TrimExcess(); | 499 | mesh.TrimExcess(); |
443 | } | 500 | } |
444 | 501 | m_uniqueMeshes.Add(key, mesh); | |
445 | return mesh; | 502 | return mesh; |
446 | } | 503 | } |
447 | } | 504 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 673ae39..032b5df 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -82,7 +82,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
82 | 82 | ||
83 | // private float m_tensor = 5f; | 83 | // private float m_tensor = 5f; |
84 | private int body_autodisable_frames = 20; | 84 | private int body_autodisable_frames = 20; |
85 | private IMesh primMesh = null; | ||
86 | 85 | ||
87 | 86 | ||
88 | private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom | 87 | private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom |
@@ -814,14 +813,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
814 | } | 813 | } |
815 | } | 814 | } |
816 | 815 | ||
817 | IMesh oldMesh = primMesh; | 816 | float[] vertexList = mesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory |
817 | int[] indexList = mesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage | ||
818 | 818 | ||
819 | primMesh = mesh; | 819 | mesh.releaseSourceMeshData(); // free up the original mesh data to save memory |
820 | |||
821 | float[] vertexList = primMesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory | ||
822 | int[] indexList = primMesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage | ||
823 | |||
824 | primMesh.releaseSourceMeshData(); // free up the original mesh data to save memory | ||
825 | 820 | ||
826 | int VertexCount = vertexList.GetLength(0)/3; | 821 | int VertexCount = vertexList.GetLength(0)/3; |
827 | int IndexCount = indexList.GetLength(0); | 822 | int IndexCount = indexList.GetLength(0); |
@@ -847,12 +842,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
847 | return; | 842 | return; |
848 | } | 843 | } |
849 | 844 | ||
850 | if (oldMesh != null) | ||
851 | { | ||
852 | oldMesh.releasePinned(); | ||
853 | oldMesh = null; | ||
854 | } | ||
855 | |||
856 | // if (IsPhysical && Body == (IntPtr) 0) | 845 | // if (IsPhysical && Body == (IntPtr) 0) |
857 | // { | 846 | // { |
858 | // Recreate the body | 847 | // Recreate the body |