diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/UbitMeshing/Mesh.cs | 517 | ||||
-rw-r--r-- | OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs | 501 |
2 files changed, 713 insertions, 305 deletions
diff --git a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs index 98c0f0b..1e9b8bc 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs | |||
@@ -32,24 +32,49 @@ using System.Runtime.InteropServices; | |||
32 | using OpenSim.Region.Physics.Manager; | 32 | using OpenSim.Region.Physics.Manager; |
33 | using PrimMesher; | 33 | using PrimMesher; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using System.Runtime.Serialization; | ||
36 | using System.Runtime.Serialization.Formatters.Binary; | ||
35 | 37 | ||
36 | namespace OpenSim.Region.Physics.Meshing | 38 | namespace OpenSim.Region.Physics.Meshing |
37 | { | 39 | { |
38 | public class Mesh : IMesh | 40 | public class MeshBuildingData |
39 | { | 41 | { |
42 | public Dictionary<Vertex, int> m_vertices; | ||
43 | public List<Triangle> m_triangles; | ||
44 | public float m_obbXmin; | ||
45 | public float m_obbXmax; | ||
46 | public float m_obbYmin; | ||
47 | public float m_obbYmax; | ||
48 | public float m_obbZmin; | ||
49 | public float m_obbZmax; | ||
50 | public Vector3 m_centroid; | ||
51 | public int m_centroidDiv; | ||
52 | } | ||
40 | 53 | ||
41 | private Dictionary<Vertex, int> m_vertices; | 54 | [Serializable()] |
42 | private List<Triangle> m_triangles; | 55 | public class Mesh : IMesh |
43 | GCHandle m_pinnedVertexes; | 56 | { |
44 | GCHandle m_pinnedIndex; | 57 | float[] vertices; |
58 | int[] indexes; | ||
59 | Vector3 m_obb; | ||
60 | Vector3 m_obboffset; | ||
61 | [NonSerialized()] | ||
62 | MeshBuildingData m_bdata; | ||
63 | [NonSerialized()] | ||
64 | GCHandle vhandler; | ||
65 | [NonSerialized()] | ||
66 | GCHandle ihandler; | ||
67 | [NonSerialized()] | ||
45 | IntPtr m_verticesPtr = IntPtr.Zero; | 68 | IntPtr m_verticesPtr = IntPtr.Zero; |
46 | int m_vertexCount = 0; | 69 | [NonSerialized()] |
47 | IntPtr m_indicesPtr = IntPtr.Zero; | 70 | IntPtr m_indicesPtr = IntPtr.Zero; |
71 | [NonSerialized()] | ||
72 | int m_vertexCount = 0; | ||
73 | [NonSerialized()] | ||
48 | int m_indexCount = 0; | 74 | int m_indexCount = 0; |
49 | public float[] m_normals; | ||
50 | Vector3 m_centroid; | ||
51 | int m_centroidDiv; | ||
52 | 75 | ||
76 | public int RefCount { get; set; } | ||
77 | public AMeshKey Key { get; set; } | ||
53 | 78 | ||
54 | private class vertexcomp : IEqualityComparer<Vertex> | 79 | private class vertexcomp : IEqualityComparer<Vertex> |
55 | { | 80 | { |
@@ -73,43 +98,119 @@ namespace OpenSim.Region.Physics.Meshing | |||
73 | { | 98 | { |
74 | vertexcomp vcomp = new vertexcomp(); | 99 | vertexcomp vcomp = new vertexcomp(); |
75 | 100 | ||
76 | m_vertices = new Dictionary<Vertex, int>(vcomp); | 101 | m_bdata = new MeshBuildingData(); |
77 | m_triangles = new List<Triangle>(); | 102 | m_bdata.m_vertices = new Dictionary<Vertex, int>(vcomp); |
78 | m_centroid = Vector3.Zero; | 103 | m_bdata.m_triangles = new List<Triangle>(); |
79 | m_centroidDiv = 0; | 104 | m_bdata.m_centroid = Vector3.Zero; |
105 | m_bdata.m_centroidDiv = 0; | ||
106 | m_bdata.m_obbXmin = float.MaxValue; | ||
107 | m_bdata.m_obbXmax = float.MinValue; | ||
108 | m_bdata.m_obbYmin = float.MaxValue; | ||
109 | m_bdata.m_obbYmax = float.MinValue; | ||
110 | m_bdata.m_obbZmin = float.MaxValue; | ||
111 | m_bdata.m_obbZmax = float.MinValue; | ||
112 | m_obb = new Vector3(0.5f, 0.5f, 0.5f); | ||
113 | m_obboffset = Vector3.Zero; | ||
80 | } | 114 | } |
81 | 115 | ||
82 | public int RefCount { get; set; } | ||
83 | |||
84 | public AMeshKey Key { get; set; } | ||
85 | 116 | ||
86 | public void Scale(Vector3 scale) | 117 | public Mesh Scale(Vector3 scale) |
87 | { | 118 | { |
119 | if (m_verticesPtr == null || m_indicesPtr == null) | ||
120 | return null; | ||
121 | |||
122 | Mesh result = new Mesh(); | ||
123 | |||
124 | float x = scale.X; | ||
125 | float y = scale.Y; | ||
126 | float z = scale.Z; | ||
127 | |||
128 | result.m_obb.X = m_obb.X * x; | ||
129 | result.m_obb.Y = m_obb.Y * y; | ||
130 | result.m_obb.Z = m_obb.Z * z; | ||
131 | result.m_obboffset.X = m_obboffset.X * x; | ||
132 | result.m_obboffset.Y = m_obboffset.Y * y; | ||
133 | result.m_obboffset.Z = m_obboffset.Z * z; | ||
88 | 134 | ||
135 | result.vertices = new float[vertices.Length]; | ||
136 | int j = 0; | ||
137 | for (int i = 0; i < m_vertexCount; i++) | ||
138 | { | ||
139 | result.vertices[j] = vertices[j] * x; | ||
140 | j++; | ||
141 | result.vertices[j] = vertices[j] * y; | ||
142 | j++; | ||
143 | result.vertices[j] = vertices[j] * z; | ||
144 | j++; | ||
145 | } | ||
146 | |||
147 | result.indexes = new int[indexes.Length]; | ||
148 | indexes.CopyTo(result.indexes,0); | ||
149 | |||
150 | result.pinMemory(); | ||
89 | 151 | ||
152 | return result; | ||
90 | } | 153 | } |
91 | 154 | ||
92 | public Mesh Clone() | 155 | public Mesh Clone() |
93 | { | 156 | { |
94 | Mesh result = new Mesh(); | 157 | Mesh result = new Mesh(); |
95 | 158 | ||
96 | foreach (Triangle t in m_triangles) | 159 | if (m_bdata != null) |
97 | { | 160 | { |
98 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); | 161 | result.m_bdata = new MeshBuildingData(); |
162 | foreach (Triangle t in m_bdata.m_triangles) | ||
163 | { | ||
164 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); | ||
165 | } | ||
166 | result.m_bdata.m_centroid = m_bdata.m_centroid; | ||
167 | result.m_bdata.m_centroidDiv = m_bdata.m_centroidDiv; | ||
168 | result.m_bdata.m_obbXmin = m_bdata.m_obbXmin; | ||
169 | result.m_bdata.m_obbXmax = m_bdata.m_obbXmax; | ||
170 | result.m_bdata.m_obbYmin = m_bdata.m_obbYmin; | ||
171 | result.m_bdata.m_obbYmax = m_bdata.m_obbYmax; | ||
172 | result.m_bdata.m_obbZmin = m_bdata.m_obbZmin; | ||
173 | result.m_bdata.m_obbZmax = m_bdata.m_obbZmax; | ||
99 | } | 174 | } |
100 | result.m_centroid = m_centroid; | 175 | result.m_obb = m_obb; |
101 | result.m_centroidDiv = m_centroidDiv; | 176 | result.m_obboffset = m_obboffset; |
102 | return result; | 177 | return result; |
103 | } | 178 | } |
104 | 179 | ||
180 | public void addVertexLStats(Vertex v) | ||
181 | { | ||
182 | float x = v.X; | ||
183 | float y = v.Y; | ||
184 | float z = v.Z; | ||
185 | |||
186 | m_bdata.m_centroid.X += x; | ||
187 | m_bdata.m_centroid.Y += y; | ||
188 | m_bdata.m_centroid.Z += z; | ||
189 | m_bdata.m_centroidDiv++; | ||
190 | |||
191 | if (x > m_bdata.m_obbXmax) | ||
192 | m_bdata.m_obbXmax = x; | ||
193 | else if (x < m_bdata.m_obbXmin) | ||
194 | m_bdata.m_obbXmin = x; | ||
195 | |||
196 | if (y > m_bdata.m_obbYmax) | ||
197 | m_bdata.m_obbYmax = y; | ||
198 | else if (y < m_bdata.m_obbYmin) | ||
199 | m_bdata.m_obbYmin = y; | ||
200 | |||
201 | if (z > m_bdata.m_obbZmax) | ||
202 | m_bdata.m_obbZmax = z; | ||
203 | else if (z < m_bdata.m_obbZmin) | ||
204 | m_bdata.m_obbZmin = z; | ||
205 | |||
206 | } | ||
207 | |||
208 | |||
105 | public void Add(Triangle triangle) | 209 | public void Add(Triangle triangle) |
106 | { | 210 | { |
107 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | 211 | if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) |
108 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | 212 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); |
109 | // If a vertex of the triangle is not yet in the vertices list, | 213 | |
110 | // add it and set its index to the current index count | ||
111 | // vertex == seems broken | ||
112 | // skip colapsed triangles | ||
113 | if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z == triangle.v2.Z) | 214 | if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z == triangle.v2.Z) |
114 | || (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z == triangle.v3.Z) | 215 | || (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z == triangle.v3.Z) |
115 | || (triangle.v2.X == triangle.v3.X && triangle.v2.Y == triangle.v3.Y && triangle.v2.Z == triangle.v3.Z) | 216 | || (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 | |||
118 | return; | 219 | return; |
119 | } | 220 | } |
120 | 221 | ||
121 | if (m_vertices.Count == 0) | 222 | if (m_bdata.m_vertices.Count == 0) |
122 | { | 223 | { |
123 | m_centroidDiv = 0; | 224 | m_bdata.m_centroidDiv = 0; |
124 | m_centroid = Vector3.Zero; | 225 | m_bdata.m_centroid = Vector3.Zero; |
125 | } | 226 | } |
126 | 227 | ||
127 | if (!m_vertices.ContainsKey(triangle.v1)) | 228 | if (!m_bdata.m_vertices.ContainsKey(triangle.v1)) |
128 | { | 229 | { |
129 | m_vertices[triangle.v1] = m_vertices.Count; | 230 | m_bdata.m_vertices[triangle.v1] = m_bdata.m_vertices.Count; |
130 | m_centroid.X += triangle.v1.X; | 231 | addVertexLStats(triangle.v1); |
131 | m_centroid.Y += triangle.v1.Y; | ||
132 | m_centroid.Z += triangle.v1.Z; | ||
133 | m_centroidDiv++; | ||
134 | } | 232 | } |
135 | if (!m_vertices.ContainsKey(triangle.v2)) | 233 | if (!m_bdata.m_vertices.ContainsKey(triangle.v2)) |
136 | { | 234 | { |
137 | m_vertices[triangle.v2] = m_vertices.Count; | 235 | m_bdata.m_vertices[triangle.v2] = m_bdata.m_vertices.Count; |
138 | m_centroid.X += triangle.v2.X; | 236 | addVertexLStats(triangle.v2); |
139 | m_centroid.Y += triangle.v2.Y; | ||
140 | m_centroid.Z += triangle.v2.Z; | ||
141 | m_centroidDiv++; | ||
142 | } | 237 | } |
143 | if (!m_vertices.ContainsKey(triangle.v3)) | 238 | if (!m_bdata.m_vertices.ContainsKey(triangle.v3)) |
144 | { | 239 | { |
145 | m_vertices[triangle.v3] = m_vertices.Count; | 240 | m_bdata.m_vertices[triangle.v3] = m_bdata.m_vertices.Count; |
146 | m_centroid.X += triangle.v3.X; | 241 | addVertexLStats(triangle.v3); |
147 | m_centroid.Y += triangle.v3.Y; | ||
148 | m_centroid.Z += triangle.v3.Z; | ||
149 | m_centroidDiv++; | ||
150 | } | 242 | } |
151 | m_triangles.Add(triangle); | 243 | m_bdata.m_triangles.Add(triangle); |
152 | } | 244 | } |
153 | 245 | ||
154 | public Vector3 GetCentroid() | 246 | public Vector3 GetCentroid() |
155 | { | 247 | { |
156 | if (m_centroidDiv > 0) | 248 | return m_obboffset; |
157 | return new Vector3(m_centroid.X / m_centroidDiv, m_centroid.Y / m_centroidDiv, m_centroid.Z / m_centroidDiv); | 249 | |
158 | else | ||
159 | return Vector3.Zero; | ||
160 | } | 250 | } |
161 | 251 | ||
162 | public void CalcNormals() | 252 | public Vector3 GetOBB() |
163 | { | 253 | { |
164 | int iTriangles = m_triangles.Count; | 254 | return m_obb; |
165 | 255 | float x, y, z; | |
166 | this.m_normals = new float[iTriangles * 3]; | 256 | if (m_bdata.m_centroidDiv > 0) |
167 | |||
168 | int i = 0; | ||
169 | foreach (Triangle t in m_triangles) | ||
170 | { | 257 | { |
171 | float ux, uy, uz; | 258 | x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f; |
172 | float vx, vy, vz; | 259 | y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f; |
173 | float wx, wy, wz; | 260 | z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f; |
174 | 261 | } | |
175 | ux = t.v1.X; | 262 | else // ?? |
176 | uy = t.v1.Y; | 263 | { |
177 | uz = t.v1.Z; | 264 | x = 0.5f; |
178 | 265 | y = 0.5f; | |
179 | vx = t.v2.X; | 266 | z = 0.5f; |
180 | vy = t.v2.Y; | ||
181 | vz = t.v2.Z; | ||
182 | |||
183 | wx = t.v3.X; | ||
184 | wy = t.v3.Y; | ||
185 | wz = t.v3.Z; | ||
186 | |||
187 | |||
188 | // Vectors for edges | ||
189 | float e1x, e1y, e1z; | ||
190 | float e2x, e2y, e2z; | ||
191 | |||
192 | e1x = ux - vx; | ||
193 | e1y = uy - vy; | ||
194 | e1z = uz - vz; | ||
195 | |||
196 | e2x = ux - wx; | ||
197 | e2y = uy - wy; | ||
198 | e2z = uz - wz; | ||
199 | |||
200 | |||
201 | // Cross product for normal | ||
202 | float nx, ny, nz; | ||
203 | nx = e1y * e2z - e1z * e2y; | ||
204 | ny = e1z * e2x - e1x * e2z; | ||
205 | nz = e1x * e2y - e1y * e2x; | ||
206 | |||
207 | // Length | ||
208 | float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); | ||
209 | float lReciprocal = 1.0f / l; | ||
210 | |||
211 | // Normalized "normal" | ||
212 | //nx /= l; | ||
213 | //ny /= l; | ||
214 | //nz /= l; | ||
215 | |||
216 | m_normals[i] = nx * lReciprocal; | ||
217 | m_normals[i + 1] = ny * lReciprocal; | ||
218 | m_normals[i + 2] = nz * lReciprocal; | ||
219 | |||
220 | i += 3; | ||
221 | } | 267 | } |
268 | return new Vector3(x, y, z); | ||
222 | } | 269 | } |
223 | 270 | ||
224 | public List<Vector3> getVertexList() | 271 | public List<Vector3> getVertexList() |
225 | { | 272 | { |
226 | List<Vector3> result = new List<Vector3>(); | 273 | List<Vector3> result = new List<Vector3>(); |
227 | foreach (Vertex v in m_vertices.Keys) | 274 | foreach (Vertex v in m_bdata.m_vertices.Keys) |
228 | { | 275 | { |
229 | result.Add(new Vector3(v.X, v.Y, v.Z)); | 276 | result.Add(new Vector3(v.X, v.Y, v.Z)); |
230 | } | 277 | } |
@@ -233,10 +280,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
233 | 280 | ||
234 | private float[] getVertexListAsFloat() | 281 | private float[] getVertexListAsFloat() |
235 | { | 282 | { |
236 | if (m_vertices == null) | 283 | if (m_bdata.m_vertices == null) |
237 | throw new NotSupportedException(); | 284 | throw new NotSupportedException(); |
238 | float[] result = new float[m_vertices.Count * 3]; | 285 | float[] result = new float[m_bdata.m_vertices.Count * 3]; |
239 | foreach (KeyValuePair<Vertex, int> kvp in m_vertices) | 286 | foreach (KeyValuePair<Vertex, int> kvp in m_bdata.m_vertices) |
240 | { | 287 | { |
241 | Vertex v = kvp.Key; | 288 | Vertex v = kvp.Key; |
242 | int i = kvp.Value; | 289 | int i = kvp.Value; |
@@ -249,48 +296,39 @@ namespace OpenSim.Region.Physics.Meshing | |||
249 | 296 | ||
250 | public float[] getVertexListAsFloatLocked() | 297 | public float[] getVertexListAsFloatLocked() |
251 | { | 298 | { |
252 | if (m_pinnedVertexes.IsAllocated) | 299 | return null; |
253 | return (float[])(m_pinnedVertexes.Target); | ||
254 | |||
255 | float[] result = getVertexListAsFloat(); | ||
256 | m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
257 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
258 | // the next GC round more intelligently | ||
259 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
260 | |||
261 | return result; | ||
262 | } | 300 | } |
263 | 301 | ||
264 | public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) | 302 | public void getVertexListAsPtrToFloatArray(out IntPtr _vertices, out int vertexStride, out int vertexCount) |
265 | { | 303 | { |
266 | // A vertex is 3 floats | 304 | // A vertex is 3 floats |
267 | vertexStride = 3 * sizeof(float); | 305 | vertexStride = 3 * sizeof(float); |
268 | 306 | ||
269 | // If there isn't an unmanaged array allocated yet, do it now | 307 | // If there isn't an unmanaged array allocated yet, do it now |
270 | if (m_verticesPtr == IntPtr.Zero) | 308 | if (m_verticesPtr == IntPtr.Zero && m_bdata != null) |
271 | { | 309 | { |
272 | float[] vertexList = getVertexListAsFloat(); | 310 | vertices = getVertexListAsFloat(); |
273 | // Each vertex is 3 elements (floats) | 311 | // Each vertex is 3 elements (floats) |
274 | m_vertexCount = vertexList.Length / 3; | 312 | m_vertexCount = vertices.Length / 3; |
275 | int byteCount = m_vertexCount * vertexStride; | 313 | vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned); |
276 | m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | 314 | m_verticesPtr = vhandler.AddrOfPinnedObject(); |
277 | System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); | 315 | GC.AddMemoryPressure(Buffer.ByteLength(vertices)); |
278 | } | 316 | } |
279 | vertices = m_verticesPtr; | 317 | _vertices = m_verticesPtr; |
280 | vertexCount = m_vertexCount; | 318 | vertexCount = m_vertexCount; |
281 | } | 319 | } |
282 | 320 | ||
283 | public int[] getIndexListAsInt() | 321 | public int[] getIndexListAsInt() |
284 | { | 322 | { |
285 | if (m_triangles == null) | 323 | if (m_bdata.m_triangles == null) |
286 | throw new NotSupportedException(); | 324 | throw new NotSupportedException(); |
287 | int[] result = new int[m_triangles.Count * 3]; | 325 | int[] result = new int[m_bdata.m_triangles.Count * 3]; |
288 | for (int i = 0; i < m_triangles.Count; i++) | 326 | for (int i = 0; i < m_bdata.m_triangles.Count; i++) |
289 | { | 327 | { |
290 | Triangle t = m_triangles[i]; | 328 | Triangle t = m_bdata.m_triangles[i]; |
291 | result[3 * i + 0] = m_vertices[t.v1]; | 329 | result[3 * i + 0] = m_bdata.m_vertices[t.v1]; |
292 | result[3 * i + 1] = m_vertices[t.v2]; | 330 | result[3 * i + 1] = m_bdata.m_vertices[t.v2]; |
293 | result[3 * i + 2] = m_vertices[t.v3]; | 331 | result[3 * i + 2] = m_bdata.m_vertices[t.v3]; |
294 | } | 332 | } |
295 | return result; | 333 | return result; |
296 | } | 334 | } |
@@ -301,28 +339,19 @@ namespace OpenSim.Region.Physics.Meshing | |||
301 | /// <returns></returns> | 339 | /// <returns></returns> |
302 | public int[] getIndexListAsIntLocked() | 340 | public int[] getIndexListAsIntLocked() |
303 | { | 341 | { |
304 | if (m_pinnedIndex.IsAllocated) | 342 | return null; |
305 | return (int[])(m_pinnedIndex.Target); | ||
306 | |||
307 | int[] result = getIndexListAsInt(); | ||
308 | m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
309 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
310 | // the next GC round more intelligently | ||
311 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
312 | |||
313 | return result; | ||
314 | } | 343 | } |
315 | 344 | ||
316 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) | 345 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) |
317 | { | 346 | { |
318 | // If there isn't an unmanaged array allocated yet, do it now | 347 | // If there isn't an unmanaged array allocated yet, do it now |
319 | if (m_indicesPtr == IntPtr.Zero) | 348 | if (m_indicesPtr == IntPtr.Zero && m_bdata != null) |
320 | { | 349 | { |
321 | int[] indexList = getIndexListAsInt(); | 350 | indexes = getIndexListAsInt(); |
322 | m_indexCount = indexList.Length; | 351 | m_indexCount = indexes.Length; |
323 | int byteCount = m_indexCount * sizeof(int); | 352 | ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned); |
324 | m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | 353 | m_indicesPtr = ihandler.AddrOfPinnedObject(); |
325 | System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); | 354 | GC.AddMemoryPressure(Buffer.ByteLength(indexes)); |
326 | } | 355 | } |
327 | // A triangle is 3 ints (indices) | 356 | // A triangle is 3 ints (indices) |
328 | triStride = 3 * sizeof(int); | 357 | triStride = 3 * sizeof(int); |
@@ -332,18 +361,16 @@ namespace OpenSim.Region.Physics.Meshing | |||
332 | 361 | ||
333 | public void releasePinned() | 362 | public void releasePinned() |
334 | { | 363 | { |
335 | if (m_pinnedVertexes.IsAllocated) | ||
336 | m_pinnedVertexes.Free(); | ||
337 | if (m_pinnedIndex.IsAllocated) | ||
338 | m_pinnedIndex.Free(); | ||
339 | if (m_verticesPtr != IntPtr.Zero) | 364 | if (m_verticesPtr != IntPtr.Zero) |
340 | { | 365 | { |
341 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); | 366 | vhandler.Free(); |
367 | vertices = null; | ||
342 | m_verticesPtr = IntPtr.Zero; | 368 | m_verticesPtr = IntPtr.Zero; |
343 | } | 369 | } |
344 | if (m_indicesPtr != IntPtr.Zero) | 370 | if (m_indicesPtr != IntPtr.Zero) |
345 | { | 371 | { |
346 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); | 372 | ihandler.Free(); |
373 | indexes = null; | ||
347 | m_indicesPtr = IntPtr.Zero; | 374 | m_indicesPtr = IntPtr.Zero; |
348 | } | 375 | } |
349 | } | 376 | } |
@@ -353,29 +380,42 @@ namespace OpenSim.Region.Physics.Meshing | |||
353 | /// </summary> | 380 | /// </summary> |
354 | public void releaseSourceMeshData() | 381 | public void releaseSourceMeshData() |
355 | { | 382 | { |
356 | m_triangles = null; | 383 | if (m_bdata != null) |
357 | m_vertices = null; | 384 | { |
385 | m_bdata.m_triangles = null; | ||
386 | m_bdata.m_vertices = null; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | public void releaseBuildingMeshData() | ||
391 | { | ||
392 | if (m_bdata != null) | ||
393 | { | ||
394 | m_bdata.m_triangles = null; | ||
395 | m_bdata.m_vertices = null; | ||
396 | m_bdata = null; | ||
397 | } | ||
358 | } | 398 | } |
359 | 399 | ||
360 | public void Append(IMesh newMesh) | 400 | public void Append(IMesh newMesh) |
361 | { | 401 | { |
362 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | 402 | if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) |
363 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | 403 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); |
364 | 404 | ||
365 | if (!(newMesh is Mesh)) | 405 | if (!(newMesh is Mesh)) |
366 | return; | 406 | return; |
367 | 407 | ||
368 | foreach (Triangle t in ((Mesh)newMesh).m_triangles) | 408 | foreach (Triangle t in ((Mesh)newMesh).m_bdata.m_triangles) |
369 | Add(t); | 409 | Add(t); |
370 | } | 410 | } |
371 | 411 | ||
372 | // Do a linear transformation of mesh. | 412 | // Do a linear transformation of mesh. |
373 | public void TransformLinear(float[,] matrix, float[] offset) | 413 | public void TransformLinear(float[,] matrix, float[] offset) |
374 | { | 414 | { |
375 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | 415 | if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) |
376 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | 416 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); |
377 | 417 | ||
378 | foreach (Vertex v in m_vertices.Keys) | 418 | foreach (Vertex v in m_bdata.m_vertices.Keys) |
379 | { | 419 | { |
380 | if (v == null) | 420 | if (v == null) |
381 | continue; | 421 | continue; |
@@ -393,10 +433,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
393 | { | 433 | { |
394 | if (path == null) | 434 | if (path == null) |
395 | return; | 435 | return; |
436 | if (m_bdata == null) | ||
437 | return; | ||
396 | String fileName = name + "_" + title + ".raw"; | 438 | String fileName = name + "_" + title + ".raw"; |
397 | String completePath = System.IO.Path.Combine(path, fileName); | 439 | String completePath = System.IO.Path.Combine(path, fileName); |
398 | StreamWriter sw = new StreamWriter(completePath); | 440 | StreamWriter sw = new StreamWriter(completePath); |
399 | foreach (Triangle t in m_triangles) | 441 | foreach (Triangle t in m_bdata.m_triangles) |
400 | { | 442 | { |
401 | String s = t.ToStringRaw(); | 443 | String s = t.ToStringRaw(); |
402 | sw.WriteLine(s); | 444 | sw.WriteLine(s); |
@@ -406,7 +448,144 @@ namespace OpenSim.Region.Physics.Meshing | |||
406 | 448 | ||
407 | public void TrimExcess() | 449 | public void TrimExcess() |
408 | { | 450 | { |
409 | m_triangles.TrimExcess(); | 451 | m_bdata.m_triangles.TrimExcess(); |
452 | } | ||
453 | |||
454 | public void pinMemory() | ||
455 | { | ||
456 | m_vertexCount = vertices.Length / 3; | ||
457 | vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned); | ||
458 | m_verticesPtr = vhandler.AddrOfPinnedObject(); | ||
459 | GC.AddMemoryPressure(Buffer.ByteLength(vertices)); | ||
460 | |||
461 | m_indexCount = indexes.Length; | ||
462 | ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned); | ||
463 | m_indicesPtr = ihandler.AddrOfPinnedObject(); | ||
464 | GC.AddMemoryPressure(Buffer.ByteLength(indexes)); | ||
465 | } | ||
466 | |||
467 | public void PrepForOde() | ||
468 | { | ||
469 | // If there isn't an unmanaged array allocated yet, do it now | ||
470 | if (m_verticesPtr == IntPtr.Zero) | ||
471 | vertices = getVertexListAsFloat(); | ||
472 | |||
473 | // If there isn't an unmanaged array allocated yet, do it now | ||
474 | if (m_indicesPtr == IntPtr.Zero) | ||
475 | indexes = getIndexListAsInt(); | ||
476 | |||
477 | pinMemory(); | ||
478 | |||
479 | float x, y, z; | ||
480 | |||
481 | if (m_bdata.m_centroidDiv > 0) | ||
482 | { | ||
483 | 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); | ||
484 | x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f; | ||
485 | y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f; | ||
486 | z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f; | ||
487 | } | ||
488 | |||
489 | else | ||
490 | { | ||
491 | m_obboffset = Vector3.Zero; | ||
492 | x = 0.5f; | ||
493 | y = 0.5f; | ||
494 | z = 0.5f; | ||
495 | } | ||
496 | m_obb = new Vector3(x, y, z); | ||
497 | |||
498 | releaseBuildingMeshData(); | ||
499 | } | ||
500 | public bool ToStream(Stream st) | ||
501 | { | ||
502 | if (m_indicesPtr == IntPtr.Zero || m_verticesPtr == IntPtr.Zero) | ||
503 | return false; | ||
504 | |||
505 | BinaryWriter bw = new BinaryWriter(st); | ||
506 | bool ok = true; | ||
507 | |||
508 | try | ||
509 | { | ||
510 | |||
511 | bw.Write(m_vertexCount); | ||
512 | bw.Write(m_indexCount); | ||
513 | |||
514 | for (int i = 0; i < 3 * m_vertexCount; i++) | ||
515 | bw.Write(vertices[i]); | ||
516 | for (int i = 0; i < m_indexCount; i++) | ||
517 | bw.Write(indexes[i]); | ||
518 | bw.Write(m_obb.X); | ||
519 | bw.Write(m_obb.Y); | ||
520 | bw.Write(m_obb.Z); | ||
521 | bw.Write(m_obboffset.X); | ||
522 | bw.Write(m_obboffset.Y); | ||
523 | bw.Write(m_obboffset.Z); | ||
524 | } | ||
525 | catch | ||
526 | { | ||
527 | ok = false; | ||
528 | } | ||
529 | |||
530 | if (bw != null) | ||
531 | { | ||
532 | bw.Flush(); | ||
533 | bw.Close(); | ||
534 | } | ||
535 | |||
536 | return ok; | ||
537 | } | ||
538 | |||
539 | public static Mesh FromStream(Stream st, AMeshKey key) | ||
540 | { | ||
541 | Mesh mesh = new Mesh(); | ||
542 | mesh.releaseBuildingMeshData(); | ||
543 | |||
544 | BinaryReader br = new BinaryReader(st); | ||
545 | |||
546 | bool ok = true; | ||
547 | try | ||
548 | { | ||
549 | mesh.m_vertexCount = br.ReadInt32(); | ||
550 | mesh.m_indexCount = br.ReadInt32(); | ||
551 | |||
552 | int n = 3 * mesh.m_vertexCount; | ||
553 | mesh.vertices = new float[n]; | ||
554 | for (int i = 0; i < n; i++) | ||
555 | mesh.vertices[i] = br.ReadSingle(); | ||
556 | |||
557 | mesh.indexes = new int[mesh.m_indexCount]; | ||
558 | for (int i = 0; i < mesh.m_indexCount; i++) | ||
559 | mesh.indexes[i] = br.ReadInt32(); | ||
560 | |||
561 | mesh.m_obb.X = br.ReadSingle(); | ||
562 | mesh.m_obb.Y = br.ReadSingle(); | ||
563 | mesh.m_obb.Z = br.ReadSingle(); | ||
564 | |||
565 | mesh.m_obboffset.X = br.ReadSingle(); | ||
566 | mesh.m_obboffset.Y = br.ReadSingle(); | ||
567 | mesh.m_obboffset.Z = br.ReadSingle(); | ||
568 | } | ||
569 | catch | ||
570 | { | ||
571 | ok = false; | ||
572 | } | ||
573 | |||
574 | br.Close(); | ||
575 | |||
576 | if (ok) | ||
577 | { | ||
578 | mesh.pinMemory(); | ||
579 | |||
580 | mesh.Key = key; | ||
581 | mesh.RefCount = 1; | ||
582 | |||
583 | return mesh; | ||
584 | } | ||
585 | |||
586 | mesh.vertices = null; | ||
587 | mesh.indexes = null; | ||
588 | return null; | ||
410 | } | 589 | } |
411 | } | 590 | } |
412 | } | 591 | } |
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs index 4c40175..29fdda4 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs | |||
@@ -42,6 +42,8 @@ using System.Reflection; | |||
42 | using System.IO; | 42 | using System.IO; |
43 | using ComponentAce.Compression.Libs.zlib; | 43 | using ComponentAce.Compression.Libs.zlib; |
44 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | 44 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; |
45 | using System.Runtime.Serialization; | ||
46 | using System.Runtime.Serialization.Formatters.Binary; | ||
45 | 47 | ||
46 | namespace OpenSim.Region.Physics.Meshing | 48 | namespace OpenSim.Region.Physics.Meshing |
47 | { | 49 | { |
@@ -68,22 +70,22 @@ namespace OpenSim.Region.Physics.Meshing | |||
68 | 70 | ||
69 | // Setting baseDir to a path will enable the dumping of raw files | 71 | // Setting baseDir to a path will enable the dumping of raw files |
70 | // raw files can be imported by blender so a visual inspection of the results can be done | 72 | // raw files can be imported by blender so a visual inspection of the results can be done |
71 | #if SPAM | ||
72 | const string baseDir = "rawFiles"; | ||
73 | #else | ||
74 | private const string baseDir = null; //"rawFiles"; | ||
75 | #endif | ||
76 | 73 | ||
77 | private bool cacheSculptMaps = true; | 74 | public object diskLock = new object(); |
78 | private bool cacheSculptAlphaMaps = true; | 75 | |
76 | public bool doMeshFileCache = true; | ||
77 | |||
78 | public string cachePath = "MeshCache"; | ||
79 | public TimeSpan CacheExpire; | ||
80 | public bool doCacheExpire = true; | ||
81 | |||
82 | // const string baseDir = "rawFiles"; | ||
83 | private const string baseDir = null; //"rawFiles"; | ||
79 | 84 | ||
80 | private string decodedSculptMapPath = null; | ||
81 | private bool useMeshiesPhysicsMesh = false; | 85 | private bool useMeshiesPhysicsMesh = false; |
82 | 86 | ||
83 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh | 87 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh |
84 | 88 | ||
85 | // private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | ||
86 | // private Dictionary<ulong, Mesh> m_uniqueReleasedMeshes = new Dictionary<ulong, Mesh>(); | ||
87 | private Dictionary<AMeshKey, Mesh> m_uniqueMeshes = new Dictionary<AMeshKey, Mesh>(); | 89 | private Dictionary<AMeshKey, Mesh> m_uniqueMeshes = new Dictionary<AMeshKey, Mesh>(); |
88 | private Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes = new Dictionary<AMeshKey, Mesh>(); | 90 | private Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes = new Dictionary<AMeshKey, Mesh>(); |
89 | 91 | ||
@@ -92,29 +94,29 @@ namespace OpenSim.Region.Physics.Meshing | |||
92 | IConfig start_config = config.Configs["Startup"]; | 94 | IConfig start_config = config.Configs["Startup"]; |
93 | IConfig mesh_config = config.Configs["Mesh"]; | 95 | IConfig mesh_config = config.Configs["Mesh"]; |
94 | 96 | ||
95 | decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); | ||
96 | 97 | ||
97 | cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); | 98 | float fcache = 48.0f; |
99 | // float fcache = 0.02f; | ||
98 | 100 | ||
99 | if (Environment.OSVersion.Platform == PlatformID.Unix) | 101 | if(mesh_config != null) |
100 | { | 102 | { |
101 | cacheSculptAlphaMaps = false; | 103 | useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); |
104 | if (useMeshiesPhysicsMesh) | ||
105 | { | ||
106 | doMeshFileCache = mesh_config.GetBoolean("MeshFileCache", doMeshFileCache); | ||
107 | cachePath = mesh_config.GetString("MeshFileCachePath", cachePath); | ||
108 | fcache = mesh_config.GetFloat("MeshFileCacheExpireHours", fcache); | ||
109 | doCacheExpire = mesh_config.GetBoolean("MeshFileCacheDoExpire", doCacheExpire); | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | doMeshFileCache = false; | ||
114 | doCacheExpire = false; | ||
115 | } | ||
102 | } | 116 | } |
103 | else | ||
104 | cacheSculptAlphaMaps = cacheSculptMaps; | ||
105 | 117 | ||
106 | if(mesh_config != null) | 118 | CacheExpire = TimeSpan.FromHours(fcache); |
107 | useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); | ||
108 | 119 | ||
109 | try | ||
110 | { | ||
111 | if (!Directory.Exists(decodedSculptMapPath)) | ||
112 | Directory.CreateDirectory(decodedSculptMapPath); | ||
113 | } | ||
114 | catch (Exception e) | ||
115 | { | ||
116 | m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message); | ||
117 | } | ||
118 | } | 120 | } |
119 | 121 | ||
120 | /// <summary> | 122 | /// <summary> |
@@ -212,7 +214,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
212 | /// <param name="size">Size of entire object</param> | 214 | /// <param name="size">Size of entire object</param> |
213 | /// <param name="coords"></param> | 215 | /// <param name="coords"></param> |
214 | /// <param name="faces"></param> | 216 | /// <param name="faces"></param> |
215 | private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces) | 217 | private void AddSubMesh(OSDMap subMeshData, List<Coord> coords, List<Face> faces) |
216 | { | 218 | { |
217 | // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap)); | 219 | // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap)); |
218 | 220 | ||
@@ -245,9 +247,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
245 | ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); | 247 | ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); |
246 | 248 | ||
247 | Coord c = new Coord( | 249 | Coord c = new Coord( |
248 | Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X, | 250 | Utils.UInt16ToFloat(uX, posMin.X, posMax.X), |
249 | Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y, | 251 | Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y), |
250 | Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z); | 252 | Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z)); |
251 | 253 | ||
252 | coords.Add(c); | 254 | coords.Add(c); |
253 | } | 255 | } |
@@ -271,7 +273,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
271 | /// <param name="size"></param> | 273 | /// <param name="size"></param> |
272 | /// <param name="lod"></param> | 274 | /// <param name="lod"></param> |
273 | /// <returns></returns> | 275 | /// <returns></returns> |
274 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool convex) | 276 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, float lod, bool convex) |
275 | { | 277 | { |
276 | // m_log.DebugFormat( | 278 | // m_log.DebugFormat( |
277 | // "[MESH]: Creating physics proxy for {0}, shape {1}", | 279 | // "[MESH]: Creating physics proxy for {0}, shape {1}", |
@@ -287,18 +289,18 @@ namespace OpenSim.Region.Physics.Meshing | |||
287 | if (!useMeshiesPhysicsMesh) | 289 | if (!useMeshiesPhysicsMesh) |
288 | return null; | 290 | return null; |
289 | 291 | ||
290 | if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces, convex)) | 292 | if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, out coords, out faces, convex)) |
291 | return null; | 293 | return null; |
292 | } | 294 | } |
293 | else | 295 | else |
294 | { | 296 | { |
295 | if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) | 297 | if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, lod, out coords, out faces)) |
296 | return null; | 298 | return null; |
297 | } | 299 | } |
298 | } | 300 | } |
299 | else | 301 | else |
300 | { | 302 | { |
301 | if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces)) | 303 | if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, out coords, out faces)) |
302 | return null; | 304 | return null; |
303 | } | 305 | } |
304 | 306 | ||
@@ -333,7 +335,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
333 | /// <param name="faces">Faces are added to this list by the method.</param> | 335 | /// <param name="faces">Faces are added to this list by the method.</param> |
334 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | 336 | /// <returns>true if coords and faces were successfully generated, false if not</returns> |
335 | private bool GenerateCoordsAndFacesFromPrimMeshData( | 337 | private bool GenerateCoordsAndFacesFromPrimMeshData( |
336 | string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces, bool convex) | 338 | string primName, PrimitiveBaseShape primShape, out List<Coord> coords, out List<Face> faces, bool convex) |
337 | { | 339 | { |
338 | // m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); | 340 | // m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); |
339 | 341 | ||
@@ -345,7 +347,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
345 | 347 | ||
346 | if (primShape.SculptData.Length <= 0) | 348 | if (primShape.SculptData.Length <= 0) |
347 | { | 349 | { |
348 | m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName); | 350 | // m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName); |
349 | return false; | 351 | return false; |
350 | } | 352 | } |
351 | 353 | ||
@@ -406,7 +408,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
406 | OSD decodedMeshOsd = new OSD(); | 408 | OSD decodedMeshOsd = new OSD(); |
407 | byte[] meshBytes = new byte[physSize]; | 409 | byte[] meshBytes = new byte[physSize]; |
408 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); | 410 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); |
409 | // byte[] decompressed = new byte[physSize * 5]; | 411 | |
410 | try | 412 | try |
411 | { | 413 | { |
412 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | 414 | using (MemoryStream inMs = new MemoryStream(meshBytes)) |
@@ -444,13 +446,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
444 | // physics_shape is an array of OSDMaps, one for each submesh | 446 | // physics_shape is an array of OSDMaps, one for each submesh |
445 | if (decodedMeshOsd is OSDArray) | 447 | if (decodedMeshOsd is OSDArray) |
446 | { | 448 | { |
447 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); | 449 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); |
448 | 450 | ||
449 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; | 451 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; |
450 | foreach (OSD subMeshOsd in decodedMeshOsdArray) | 452 | foreach (OSD subMeshOsd in decodedMeshOsdArray) |
451 | { | 453 | { |
452 | if (subMeshOsd is OSDMap) | 454 | if (subMeshOsd is OSDMap) |
453 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); | 455 | AddSubMesh(subMeshOsd as OSDMap, coords, faces); |
454 | } | 456 | } |
455 | } | 457 | } |
456 | } | 458 | } |
@@ -522,9 +524,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
522 | t3 = data[ptr++]; | 524 | t3 = data[ptr++]; |
523 | t3 += data[ptr++] << 8; | 525 | t3 += data[ptr++] << 8; |
524 | 526 | ||
525 | f3 = new float3((t1 * range.X + min.X) * size.X, | 527 | f3 = new float3((t1 * range.X + min.X), |
526 | (t2 * range.Y + min.Y) * size.Y, | 528 | (t2 * range.Y + min.Y), |
527 | (t3 * range.Z + min.Z) * size.Z); | 529 | (t3 * range.Z + min.Z)); |
528 | vs.Add(f3); | 530 | vs.Add(f3); |
529 | } | 531 | } |
530 | 532 | ||
@@ -621,9 +623,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
621 | t3 = data[i++]; | 623 | t3 = data[i++]; |
622 | t3 += data[i++] << 8; | 624 | t3 += data[i++] << 8; |
623 | 625 | ||
624 | f3 = new float3((t1 * range.X + min.X) * size.X, | 626 | f3 = new float3((t1 * range.X + min.X), |
625 | (t2 * range.Y + min.Y) * size.Y, | 627 | (t2 * range.Y + min.Y), |
626 | (t3 * range.Z + min.Z) * size.Z); | 628 | (t3 * range.Z + min.Z)); |
627 | vs.Add(f3); | 629 | vs.Add(f3); |
628 | } | 630 | } |
629 | 631 | ||
@@ -711,35 +713,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
711 | /// <param name="faces">Faces are added to this list by the method.</param> | 713 | /// <param name="faces">Faces are added to this list by the method.</param> |
712 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | 714 | /// <returns>true if coords and faces were successfully generated, false if not</returns> |
713 | private bool GenerateCoordsAndFacesFromPrimSculptData( | 715 | private bool GenerateCoordsAndFacesFromPrimSculptData( |
714 | string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) | 716 | string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces) |
715 | { | 717 | { |
716 | coords = new List<Coord>(); | 718 | coords = new List<Coord>(); |
717 | faces = new List<Face>(); | 719 | faces = new List<Face>(); |
718 | PrimMesher.SculptMesh sculptMesh; | 720 | PrimMesher.SculptMesh sculptMesh; |
719 | Image idata = null; | 721 | Image idata = null; |
720 | string decodedSculptFileName = ""; | ||
721 | |||
722 | if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) | ||
723 | { | ||
724 | decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); | ||
725 | try | ||
726 | { | ||
727 | if (File.Exists(decodedSculptFileName)) | ||
728 | { | ||
729 | idata = Image.FromFile(decodedSculptFileName); | ||
730 | } | ||
731 | } | ||
732 | catch (Exception e) | ||
733 | { | ||
734 | m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); | ||
735 | 722 | ||
736 | } | ||
737 | //if (idata != null) | ||
738 | // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); | ||
739 | } | ||
740 | |||
741 | if (idata == null) | ||
742 | { | ||
743 | if (primShape.SculptData == null || primShape.SculptData.Length == 0) | 723 | if (primShape.SculptData == null || primShape.SculptData.Length == 0) |
744 | return false; | 724 | return false; |
745 | 725 | ||
@@ -748,25 +728,15 @@ namespace OpenSim.Region.Physics.Meshing | |||
748 | OpenMetaverse.Imaging.ManagedImage unusedData; | 728 | OpenMetaverse.Imaging.ManagedImage unusedData; |
749 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); | 729 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); |
750 | 730 | ||
731 | unusedData = null; | ||
732 | |||
751 | if (idata == null) | 733 | if (idata == null) |
752 | { | 734 | { |
753 | // In some cases it seems that the decode can return a null bitmap without throwing | 735 | // In some cases it seems that the decode can return a null bitmap without throwing |
754 | // an exception | 736 | // an exception |
755 | m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); | 737 | m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); |
756 | |||
757 | return false; | 738 | return false; |
758 | } | 739 | } |
759 | |||
760 | unusedData = null; | ||
761 | |||
762 | //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); | ||
763 | |||
764 | if (cacheSculptMaps && (cacheSculptAlphaMaps || (((ImageFlags)(idata.Flags) & ImageFlags.HasAlpha) ==0))) | ||
765 | // don't cache images with alpha channel in linux since mono can't load them correctly) | ||
766 | { | ||
767 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } | ||
768 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } | ||
769 | } | ||
770 | } | 740 | } |
771 | catch (DllNotFoundException) | 741 | catch (DllNotFoundException) |
772 | { | 742 | { |
@@ -783,7 +753,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
783 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); | 753 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); |
784 | return false; | 754 | return false; |
785 | } | 755 | } |
786 | } | ||
787 | 756 | ||
788 | PrimMesher.SculptMesh.SculptType sculptType; | 757 | PrimMesher.SculptMesh.SculptType sculptType; |
789 | // remove mirror and invert bits | 758 | // remove mirror and invert bits |
@@ -814,9 +783,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
814 | 783 | ||
815 | idata.Dispose(); | 784 | idata.Dispose(); |
816 | 785 | ||
817 | sculptMesh.DumpRaw(baseDir, primName, "primMesh"); | 786 | // sculptMesh.DumpRaw(baseDir, primName, "primMesh"); |
818 | |||
819 | sculptMesh.Scale(size.X, size.Y, size.Z); | ||
820 | 787 | ||
821 | coords = sculptMesh.coords; | 788 | coords = sculptMesh.coords; |
822 | faces = sculptMesh.faces; | 789 | faces = sculptMesh.faces; |
@@ -834,7 +801,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
834 | /// <param name="faces">Faces are added to this list by the method.</param> | 801 | /// <param name="faces">Faces are added to this list by the method.</param> |
835 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | 802 | /// <returns>true if coords and faces were successfully generated, false if not</returns> |
836 | private bool GenerateCoordsAndFacesFromPrimShapeData( | 803 | private bool GenerateCoordsAndFacesFromPrimShapeData( |
837 | string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) | 804 | string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces) |
838 | { | 805 | { |
839 | PrimMesh primMesh; | 806 | PrimMesh primMesh; |
840 | coords = new List<Coord>(); | 807 | coords = new List<Coord>(); |
@@ -969,9 +936,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
969 | } | 936 | } |
970 | } | 937 | } |
971 | 938 | ||
972 | primMesh.DumpRaw(baseDir, primName, "primMesh"); | 939 | // primMesh.DumpRaw(baseDir, primName, "primMesh"); |
973 | |||
974 | primMesh.Scale(size.X, size.Y, size.Z); | ||
975 | 940 | ||
976 | coords = primMesh.coords; | 941 | coords = primMesh.coords; |
977 | faces = primMesh.faces; | 942 | faces = primMesh.faces; |
@@ -985,12 +950,14 @@ namespace OpenSim.Region.Physics.Meshing | |||
985 | Byte[] someBytes; | 950 | Byte[] someBytes; |
986 | 951 | ||
987 | key.hashB = 5181; | 952 | key.hashB = 5181; |
953 | key.hashC = 5181; | ||
988 | ulong hash = 5381; | 954 | ulong hash = 5381; |
989 | 955 | ||
990 | if (primShape.SculptEntry) | 956 | if (primShape.SculptEntry) |
991 | { | 957 | { |
992 | key.uuid = primShape.SculptTexture; | 958 | key.uuid = primShape.SculptTexture; |
993 | key.hashB = mdjb2(key.hashB, primShape.SculptType); | 959 | key.hashC = mdjb2(key.hashC, primShape.SculptType); |
960 | key.hashC = mdjb2(key.hashC, primShape.PCode); | ||
994 | } | 961 | } |
995 | else | 962 | else |
996 | { | 963 | { |
@@ -1002,6 +969,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
1002 | hash = mdjb2(hash, primShape.PathScaleX); | 969 | hash = mdjb2(hash, primShape.PathScaleX); |
1003 | hash = mdjb2(hash, primShape.PathScaleY); | 970 | hash = mdjb2(hash, primShape.PathScaleY); |
1004 | hash = mdjb2(hash, primShape.PathShearX); | 971 | hash = mdjb2(hash, primShape.PathShearX); |
972 | key.hashA = hash; | ||
973 | hash = key.hashB; | ||
1005 | hash = mdjb2(hash, primShape.PathShearY); | 974 | hash = mdjb2(hash, primShape.PathShearY); |
1006 | hash = mdjb2(hash, (byte)primShape.PathTwist); | 975 | hash = mdjb2(hash, (byte)primShape.PathTwist); |
1007 | hash = mdjb2(hash, (byte)primShape.PathTwistBegin); | 976 | hash = mdjb2(hash, (byte)primShape.PathTwistBegin); |
@@ -1013,26 +982,38 @@ namespace OpenSim.Region.Physics.Meshing | |||
1013 | hash = mdjb2(hash, primShape.ProfileBegin); | 982 | hash = mdjb2(hash, primShape.ProfileBegin); |
1014 | hash = mdjb2(hash, primShape.ProfileEnd); | 983 | hash = mdjb2(hash, primShape.ProfileEnd); |
1015 | hash = mdjb2(hash, primShape.ProfileHollow); | 984 | hash = mdjb2(hash, primShape.ProfileHollow); |
1016 | key.hashA = hash; | 985 | hash = mdjb2(hash, primShape.PCode); |
986 | key.hashB = hash; | ||
1017 | } | 987 | } |
1018 | 988 | ||
1019 | hash = key.hashB; | 989 | hash = key.hashC; |
1020 | |||
1021 | someBytes = size.GetBytes(); | ||
1022 | for (int i = 0; i < someBytes.Length; i++) | ||
1023 | hash = mdjb2(hash, someBytes[i]); | ||
1024 | 990 | ||
1025 | hash = mdjb2(hash, lod); | 991 | hash = mdjb2(hash, lod); |
1026 | 992 | ||
1027 | hash &= 0x3fffffffffffffff; | 993 | if (size == m_MeshUnitSize) |
994 | { | ||
995 | hash = hash << 8; | ||
996 | hash |= 8; | ||
997 | } | ||
998 | else | ||
999 | { | ||
1000 | someBytes = size.GetBytes(); | ||
1001 | for (int i = 0; i < someBytes.Length; i++) | ||
1002 | hash = mdjb2(hash, someBytes[i]); | ||
1003 | hash = hash << 8; | ||
1004 | } | ||
1028 | 1005 | ||
1029 | if (convex) | 1006 | if (convex) |
1030 | hash |= 0x4000000000000000; | 1007 | hash |= 4; |
1031 | 1008 | ||
1032 | if (primShape.SculptEntry) | 1009 | if (primShape.SculptEntry) |
1033 | hash |= 0x8000000000000000; | 1010 | { |
1011 | hash |= 1; | ||
1012 | if (primShape.SculptType == (byte)SculptType.Mesh) | ||
1013 | hash |= 2; | ||
1014 | } | ||
1034 | 1015 | ||
1035 | key.hashB = hash; | 1016 | key.hashC = hash; |
1036 | 1017 | ||
1037 | return key; | 1018 | return key; |
1038 | } | 1019 | } |
@@ -1048,35 +1029,74 @@ namespace OpenSim.Region.Physics.Meshing | |||
1048 | return ((hash << 5) + hash) + (ulong)(c >> 8); | 1029 | return ((hash << 5) + hash) + (ulong)(c >> 8); |
1049 | } | 1030 | } |
1050 | 1031 | ||
1051 | |||
1052 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
1053 | { | 1033 | { |
1054 | return CreateMesh(primName, primShape, size, lod, false,false); | 1034 | return CreateMesh(primName, primShape, size, lod, false,false,false); |
1055 | } | 1035 | } |
1056 | 1036 | ||
1057 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
1058 | { | 1038 | { |
1059 | return CreateMesh(primName, primShape, size, lod, false,false); | 1039 | return CreateMesh(primName, primShape, size, lod, false,false,false); |
1060 | } | 1040 | } |
1061 | 1041 | ||
1062 | private static Vector3 m_MeshUnitSize = new Vector3(0.5f, 0.5f, 0.5f); | 1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) |
1043 | { | ||
1044 | Mesh mesh = null; | ||
1045 | |||
1046 | if (size.X < 0.01f) size.X = 0.01f; | ||
1047 | if (size.Y < 0.01f) size.Y = 0.01f; | ||
1048 | if (size.Z < 0.01f) size.Z = 0.01f; | ||
1049 | |||
1050 | AMeshKey key = GetMeshUniqueKey(primShape, size, (byte)lod, convex); | ||
1051 | lock (m_uniqueMeshes) | ||
1052 | { | ||
1053 | m_uniqueMeshes.TryGetValue(key, out mesh); | ||
1054 | |||
1055 | if (mesh != null) | ||
1056 | { | ||
1057 | mesh.RefCount++; | ||
1058 | return mesh; | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1062 | // try to find a identical mesh on meshs recently released | ||
1063 | lock (m_uniqueReleasedMeshes) | ||
1064 | { | ||
1065 | m_uniqueReleasedMeshes.TryGetValue(key, out mesh); | ||
1066 | if (mesh != null) | ||
1067 | { | ||
1068 | m_uniqueReleasedMeshes.Remove(key); | ||
1069 | lock (m_uniqueMeshes) | ||
1070 | { | ||
1071 | try | ||
1072 | { | ||
1073 | m_uniqueMeshes.Add(key, mesh); | ||
1074 | } | ||
1075 | catch { } | ||
1076 | } | ||
1077 | mesh.RefCount = 1; | ||
1078 | return mesh; | ||
1079 | } | ||
1080 | } | ||
1081 | return null; | ||
1082 | } | ||
1063 | 1083 | ||
1064 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) | 1084 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); |
1085 | |||
1086 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | ||
1065 | { | 1087 | { |
1066 | #if SPAM | 1088 | #if SPAM |
1067 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 1089 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
1068 | #endif | 1090 | #endif |
1069 | 1091 | ||
1070 | Mesh mesh = null; | 1092 | Mesh mesh = null; |
1071 | // ulong key = 0; | ||
1072 | |||
1073 | 1093 | ||
1074 | if (size.X < 0.01f) size.X = 0.01f; | 1094 | if (size.X < 0.01f) size.X = 0.01f; |
1075 | if (size.Y < 0.01f) size.Y = 0.01f; | 1095 | if (size.Y < 0.01f) size.Y = 0.01f; |
1076 | if (size.Z < 0.01f) size.Z = 0.01f; | 1096 | if (size.Z < 0.01f) size.Z = 0.01f; |
1077 | 1097 | ||
1078 | // try to find a identical mesh on meshs in use | 1098 | // try to find a identical mesh on meshs in use |
1079 | // key = primShape.GetMeshKey(size, lod, convex); | 1099 | |
1080 | AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex); | 1100 | AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex); |
1081 | 1101 | ||
1082 | lock (m_uniqueMeshes) | 1102 | lock (m_uniqueMeshes) |
@@ -1098,35 +1118,78 @@ namespace OpenSim.Region.Physics.Meshing | |||
1098 | { | 1118 | { |
1099 | m_uniqueReleasedMeshes.Remove(key); | 1119 | m_uniqueReleasedMeshes.Remove(key); |
1100 | lock (m_uniqueMeshes) | 1120 | lock (m_uniqueMeshes) |
1101 | m_uniqueMeshes.Add(key, mesh); | 1121 | { |
1122 | try | ||
1123 | { | ||
1124 | m_uniqueMeshes.Add(key, mesh); | ||
1125 | } | ||
1126 | catch { } | ||
1127 | } | ||
1102 | mesh.RefCount = 1; | 1128 | mesh.RefCount = 1; |
1103 | return mesh; | 1129 | return mesh; |
1104 | } | 1130 | } |
1105 | } | 1131 | } |
1106 | 1132 | ||
1107 | mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod,convex); | 1133 | Mesh UnitMesh = null; |
1134 | AMeshKey unitKey = GetMeshUniqueKey(primShape, m_MeshUnitSize, (byte)lod, convex); | ||
1108 | 1135 | ||
1109 | if (mesh != null) | 1136 | lock (m_uniqueReleasedMeshes) |
1110 | { | 1137 | { |
1111 | if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh) | 1138 | m_uniqueReleasedMeshes.TryGetValue(unitKey, out UnitMesh); |
1139 | if (UnitMesh != null) | ||
1112 | { | 1140 | { |
1113 | #if SPAM | 1141 | UnitMesh.RefCount = 1; |
1114 | m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " + | ||
1115 | minSizeForComplexMesh.ToString() + " - creating simple bounding box"); | ||
1116 | #endif | ||
1117 | mesh = CreateBoundingBoxMesh(mesh); | ||
1118 | mesh.DumpRaw(baseDir, primName, "Z extruded"); | ||
1119 | } | 1142 | } |
1143 | } | ||
1120 | 1144 | ||
1121 | // trim the vertex and triangle lists to free up memory | 1145 | if (UnitMesh == null && primShape.SculptEntry && doMeshFileCache) |
1122 | mesh.TrimExcess(); | 1146 | UnitMesh = GetFromFileCache(unitKey); |
1123 | mesh.Key = key; | ||
1124 | mesh.RefCount = 1; | ||
1125 | 1147 | ||
1126 | lock(m_uniqueMeshes) | 1148 | if (UnitMesh == null) |
1127 | m_uniqueMeshes.Add(key, mesh); | 1149 | { |
1150 | UnitMesh = CreateMeshFromPrimMesher(primName, primShape, lod, convex); | ||
1151 | |||
1152 | if (UnitMesh == null) | ||
1153 | return null; | ||
1154 | |||
1155 | UnitMesh.DumpRaw(baseDir, unitKey.ToString(), "Z"); | ||
1156 | |||
1157 | if (forOde) | ||
1158 | { | ||
1159 | // force pinned mem allocation | ||
1160 | UnitMesh.PrepForOde(); | ||
1161 | } | ||
1162 | else | ||
1163 | UnitMesh.TrimExcess(); | ||
1164 | |||
1165 | UnitMesh.Key = unitKey; | ||
1166 | UnitMesh.RefCount = 1; | ||
1167 | |||
1168 | if (doMeshFileCache && primShape.SculptEntry) | ||
1169 | StoreToFileCache(unitKey, UnitMesh); | ||
1170 | |||
1171 | lock (m_uniqueReleasedMeshes) | ||
1172 | { | ||
1173 | try | ||
1174 | { | ||
1175 | m_uniqueReleasedMeshes.Add(unitKey, UnitMesh); | ||
1176 | } | ||
1177 | catch { } | ||
1178 | } | ||
1128 | } | 1179 | } |
1129 | 1180 | ||
1181 | mesh = UnitMesh.Scale(size); | ||
1182 | mesh.Key = key; | ||
1183 | mesh.RefCount = 1; | ||
1184 | lock (m_uniqueMeshes) | ||
1185 | { | ||
1186 | try | ||
1187 | { | ||
1188 | m_uniqueMeshes.Add(key, mesh); | ||
1189 | } | ||
1190 | catch { } | ||
1191 | } | ||
1192 | |||
1130 | return mesh; | 1193 | return mesh; |
1131 | } | 1194 | } |
1132 | 1195 | ||
@@ -1137,21 +1200,27 @@ namespace OpenSim.Region.Physics.Meshing | |||
1137 | 1200 | ||
1138 | Mesh mesh = (Mesh)imesh; | 1201 | Mesh mesh = (Mesh)imesh; |
1139 | 1202 | ||
1140 | int curRefCount = mesh.RefCount; | ||
1141 | curRefCount--; | ||
1142 | |||
1143 | if (curRefCount > 0) | ||
1144 | { | ||
1145 | mesh.RefCount = curRefCount; | ||
1146 | return; | ||
1147 | } | ||
1148 | |||
1149 | lock (m_uniqueMeshes) | 1203 | lock (m_uniqueMeshes) |
1150 | { | 1204 | { |
1205 | int curRefCount = mesh.RefCount; | ||
1206 | curRefCount--; | ||
1207 | |||
1208 | if (curRefCount > 0) | ||
1209 | { | ||
1210 | mesh.RefCount = curRefCount; | ||
1211 | return; | ||
1212 | } | ||
1213 | |||
1151 | mesh.RefCount = 0; | 1214 | mesh.RefCount = 0; |
1152 | m_uniqueMeshes.Remove(mesh.Key); | 1215 | m_uniqueMeshes.Remove(mesh.Key); |
1153 | lock (m_uniqueReleasedMeshes) | 1216 | lock (m_uniqueReleasedMeshes) |
1154 | m_uniqueReleasedMeshes.Add(mesh.Key, mesh); | 1217 | { |
1218 | try | ||
1219 | { | ||
1220 | m_uniqueReleasedMeshes.Add(mesh.Key, mesh); | ||
1221 | } | ||
1222 | catch { } | ||
1223 | } | ||
1155 | } | 1224 | } |
1156 | } | 1225 | } |
1157 | 1226 | ||
@@ -1178,10 +1247,170 @@ namespace OpenSim.Region.Physics.Meshing | |||
1178 | foreach (Mesh m in meshstodelete) | 1247 | foreach (Mesh m in meshstodelete) |
1179 | { | 1248 | { |
1180 | m_uniqueReleasedMeshes.Remove(m.Key); | 1249 | m_uniqueReleasedMeshes.Remove(m.Key); |
1181 | m.releaseSourceMeshData(); | 1250 | m.releaseBuildingMeshData(); |
1182 | m.releasePinned(); | 1251 | m.releasePinned(); |
1183 | } | 1252 | } |
1184 | } | 1253 | } |
1185 | } | 1254 | } |
1255 | |||
1256 | public void FileNames(AMeshKey key, out string dir,out string fullFileName) | ||
1257 | { | ||
1258 | string id = key.ToString(); | ||
1259 | string init = id.Substring(0, 1); | ||
1260 | dir = System.IO.Path.Combine(cachePath, init); | ||
1261 | fullFileName = System.IO.Path.Combine(dir, id); | ||
1262 | } | ||
1263 | |||
1264 | public string FullFileName(AMeshKey key) | ||
1265 | { | ||
1266 | string id = key.ToString(); | ||
1267 | string init = id.Substring(0,1); | ||
1268 | id = System.IO.Path.Combine(init, id); | ||
1269 | id = System.IO.Path.Combine(cachePath, id); | ||
1270 | return id; | ||
1271 | } | ||
1272 | |||
1273 | private Mesh GetFromFileCache(AMeshKey key) | ||
1274 | { | ||
1275 | Mesh mesh = null; | ||
1276 | string filename = FullFileName(key); | ||
1277 | bool ok = true; | ||
1278 | |||
1279 | lock (diskLock) | ||
1280 | { | ||
1281 | if (File.Exists(filename)) | ||
1282 | { | ||
1283 | FileStream stream = null; | ||
1284 | try | ||
1285 | { | ||
1286 | stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); | ||
1287 | BinaryFormatter bformatter = new BinaryFormatter(); | ||
1288 | |||
1289 | mesh = Mesh.FromStream(stream, key); | ||
1290 | |||
1291 | } | ||
1292 | catch (Exception e) | ||
1293 | { | ||
1294 | ok = false; | ||
1295 | m_log.ErrorFormat( | ||
1296 | "[MESH CACHE]: Failed to get file {0}. Exception {1} {2}", | ||
1297 | filename, e.Message, e.StackTrace); | ||
1298 | } | ||
1299 | |||
1300 | if (stream != null) | ||
1301 | stream.Close(); | ||
1302 | |||
1303 | if (mesh == null || !ok) | ||
1304 | File.Delete(filename); | ||
1305 | else | ||
1306 | File.SetLastAccessTimeUtc(filename, DateTime.UtcNow); | ||
1307 | } | ||
1308 | } | ||
1309 | |||
1310 | return mesh; | ||
1311 | } | ||
1312 | |||
1313 | private void StoreToFileCache(AMeshKey key, Mesh mesh) | ||
1314 | { | ||
1315 | Stream stream = null; | ||
1316 | bool ok = false; | ||
1317 | |||
1318 | // Make sure the target cache directory exists | ||
1319 | string dir = String.Empty; | ||
1320 | string filename = String.Empty; | ||
1321 | |||
1322 | FileNames(key, out dir, out filename); | ||
1323 | |||
1324 | lock (diskLock) | ||
1325 | { | ||
1326 | try | ||
1327 | { | ||
1328 | if (!Directory.Exists(dir)) | ||
1329 | { | ||
1330 | Directory.CreateDirectory(dir); | ||
1331 | } | ||
1332 | |||
1333 | stream = File.Open(filename, FileMode.Create); | ||
1334 | ok = mesh.ToStream(stream); | ||
1335 | } | ||
1336 | catch (IOException e) | ||
1337 | { | ||
1338 | m_log.ErrorFormat( | ||
1339 | "[MESH CACHE]: Failed to write file {0}. Exception {1} {2}.", | ||
1340 | filename, e.Message, e.StackTrace); | ||
1341 | ok = false; | ||
1342 | } | ||
1343 | |||
1344 | if (stream != null) | ||
1345 | stream.Close(); | ||
1346 | |||
1347 | if (File.Exists(filename)) | ||
1348 | { | ||
1349 | if (ok) | ||
1350 | File.SetLastAccessTimeUtc(filename, DateTime.UtcNow); | ||
1351 | else | ||
1352 | File.Delete(filename); | ||
1353 | } | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | public void ExpireFileCache() | ||
1358 | { | ||
1359 | if (!doCacheExpire) | ||
1360 | return; | ||
1361 | |||
1362 | string controlfile = System.IO.Path.Combine(cachePath, "cntr"); | ||
1363 | |||
1364 | lock (diskLock) | ||
1365 | { | ||
1366 | try | ||
1367 | { | ||
1368 | if (File.Exists(controlfile)) | ||
1369 | { | ||
1370 | int ndeleted = 0; | ||
1371 | int totalfiles = 0; | ||
1372 | int ndirs = 0; | ||
1373 | DateTime OlderTime = File.GetLastAccessTimeUtc(controlfile) - CacheExpire; | ||
1374 | File.SetLastAccessTimeUtc(controlfile, DateTime.UtcNow); | ||
1375 | |||
1376 | foreach (string dir in Directory.GetDirectories(cachePath)) | ||
1377 | { | ||
1378 | try | ||
1379 | { | ||
1380 | foreach (string file in Directory.GetFiles(dir)) | ||
1381 | { | ||
1382 | try | ||
1383 | { | ||
1384 | if (File.GetLastAccessTimeUtc(file) < OlderTime) | ||
1385 | { | ||
1386 | File.Delete(file); | ||
1387 | ndeleted++; | ||
1388 | } | ||
1389 | } | ||
1390 | catch { } | ||
1391 | totalfiles++; | ||
1392 | } | ||
1393 | } | ||
1394 | catch { } | ||
1395 | ndirs++; | ||
1396 | } | ||
1397 | |||
1398 | if (ndeleted == 0) | ||
1399 | m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, no expires", | ||
1400 | totalfiles,ndirs); | ||
1401 | else | ||
1402 | m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, expired {2} files accessed before {3}", | ||
1403 | totalfiles,ndirs, ndeleted, OlderTime.ToString()); | ||
1404 | } | ||
1405 | else | ||
1406 | { | ||
1407 | m_log.Info("[MESH CACHE]: Expire delayed to next startup"); | ||
1408 | FileStream fs = File.Create(controlfile,4096,FileOptions.WriteThrough); | ||
1409 | fs.Close(); | ||
1410 | } | ||
1411 | } | ||
1412 | catch { } | ||
1413 | } | ||
1414 | } | ||
1186 | } | 1415 | } |
1187 | } | 1416 | } |