diff options
Diffstat (limited to 'OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs')
-rw-r--r-- | OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs new file mode 100644 index 0000000..8c97f2f --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Runtime.InteropServices; | ||
32 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
33 | using PrimMesher; | ||
34 | using OpenMetaverse; | ||
35 | |||
36 | namespace OpenSim.Region.PhysicsModules.Meshing | ||
37 | { | ||
38 | public class Mesh : IMesh | ||
39 | { | ||
40 | private Dictionary<Vertex, int> m_vertices; | ||
41 | private List<Triangle> m_triangles; | ||
42 | GCHandle m_pinnedVertexes; | ||
43 | GCHandle m_pinnedIndex; | ||
44 | IntPtr m_verticesPtr = IntPtr.Zero; | ||
45 | int m_vertexCount = 0; | ||
46 | IntPtr m_indicesPtr = IntPtr.Zero; | ||
47 | int m_indexCount = 0; | ||
48 | public float[] m_normals; | ||
49 | Vector3 _centroid; | ||
50 | int _centroidDiv; | ||
51 | |||
52 | private class vertexcomp : IEqualityComparer<Vertex> | ||
53 | { | ||
54 | public bool Equals(Vertex v1, Vertex v2) | ||
55 | { | ||
56 | if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z) | ||
57 | return true; | ||
58 | else | ||
59 | return false; | ||
60 | } | ||
61 | public int GetHashCode(Vertex v) | ||
62 | { | ||
63 | int a = v.X.GetHashCode(); | ||
64 | int b = v.Y.GetHashCode(); | ||
65 | int c = v.Z.GetHashCode(); | ||
66 | return (a << 16) ^ (b << 8) ^ c; | ||
67 | } | ||
68 | |||
69 | } | ||
70 | |||
71 | public Mesh() | ||
72 | { | ||
73 | vertexcomp vcomp = new vertexcomp(); | ||
74 | |||
75 | m_vertices = new Dictionary<Vertex, int>(vcomp); | ||
76 | m_triangles = new List<Triangle>(); | ||
77 | _centroid = Vector3.Zero; | ||
78 | _centroidDiv = 0; | ||
79 | } | ||
80 | |||
81 | public Mesh Clone() | ||
82 | { | ||
83 | Mesh result = new Mesh(); | ||
84 | |||
85 | foreach (Triangle t in m_triangles) | ||
86 | { | ||
87 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); | ||
88 | } | ||
89 | result._centroid = _centroid; | ||
90 | result._centroidDiv = _centroidDiv; | ||
91 | return result; | ||
92 | } | ||
93 | |||
94 | public void Add(Triangle triangle) | ||
95 | { | ||
96 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
97 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | ||
98 | // If a vertex of the triangle is not yet in the vertices list, | ||
99 | // add it and set its index to the current index count | ||
100 | // vertex == seems broken | ||
101 | // skip colapsed triangles | ||
102 | if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z == triangle.v2.Z) | ||
103 | || (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z == triangle.v3.Z) | ||
104 | || (triangle.v2.X == triangle.v3.X && triangle.v2.Y == triangle.v3.Y && triangle.v2.Z == triangle.v3.Z) | ||
105 | ) | ||
106 | { | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | if (m_vertices.Count == 0) | ||
111 | { | ||
112 | _centroidDiv = 0; | ||
113 | _centroid = Vector3.Zero; | ||
114 | } | ||
115 | |||
116 | if (!m_vertices.ContainsKey(triangle.v1)) | ||
117 | { | ||
118 | m_vertices[triangle.v1] = m_vertices.Count; | ||
119 | _centroid.X += triangle.v1.X; | ||
120 | _centroid.Y += triangle.v1.Y; | ||
121 | _centroid.Z += triangle.v1.Z; | ||
122 | _centroidDiv++; | ||
123 | } | ||
124 | if (!m_vertices.ContainsKey(triangle.v2)) | ||
125 | { | ||
126 | m_vertices[triangle.v2] = m_vertices.Count; | ||
127 | _centroid.X += triangle.v2.X; | ||
128 | _centroid.Y += triangle.v2.Y; | ||
129 | _centroid.Z += triangle.v2.Z; | ||
130 | _centroidDiv++; | ||
131 | } | ||
132 | if (!m_vertices.ContainsKey(triangle.v3)) | ||
133 | { | ||
134 | m_vertices[triangle.v3] = m_vertices.Count; | ||
135 | _centroid.X += triangle.v3.X; | ||
136 | _centroid.Y += triangle.v3.Y; | ||
137 | _centroid.Z += triangle.v3.Z; | ||
138 | _centroidDiv++; | ||
139 | } | ||
140 | m_triangles.Add(triangle); | ||
141 | } | ||
142 | |||
143 | public Vector3 GetCentroid() | ||
144 | { | ||
145 | if (_centroidDiv > 0) | ||
146 | return new Vector3(_centroid.X / _centroidDiv, _centroid.Y / _centroidDiv, _centroid.Z / _centroidDiv); | ||
147 | else | ||
148 | return Vector3.Zero; | ||
149 | } | ||
150 | |||
151 | // not functional | ||
152 | public Vector3 GetOBB() | ||
153 | { | ||
154 | return new Vector3(0.5f, 0.5f, 0.5f); | ||
155 | } | ||
156 | |||
157 | public void CalcNormals() | ||
158 | { | ||
159 | int iTriangles = m_triangles.Count; | ||
160 | |||
161 | this.m_normals = new float[iTriangles * 3]; | ||
162 | |||
163 | int i = 0; | ||
164 | foreach (Triangle t in m_triangles) | ||
165 | { | ||
166 | float ux, uy, uz; | ||
167 | float vx, vy, vz; | ||
168 | float wx, wy, wz; | ||
169 | |||
170 | ux = t.v1.X; | ||
171 | uy = t.v1.Y; | ||
172 | uz = t.v1.Z; | ||
173 | |||
174 | vx = t.v2.X; | ||
175 | vy = t.v2.Y; | ||
176 | vz = t.v2.Z; | ||
177 | |||
178 | wx = t.v3.X; | ||
179 | wy = t.v3.Y; | ||
180 | wz = t.v3.Z; | ||
181 | |||
182 | |||
183 | // Vectors for edges | ||
184 | float e1x, e1y, e1z; | ||
185 | float e2x, e2y, e2z; | ||
186 | |||
187 | e1x = ux - vx; | ||
188 | e1y = uy - vy; | ||
189 | e1z = uz - vz; | ||
190 | |||
191 | e2x = ux - wx; | ||
192 | e2y = uy - wy; | ||
193 | e2z = uz - wz; | ||
194 | |||
195 | |||
196 | // Cross product for normal | ||
197 | float nx, ny, nz; | ||
198 | nx = e1y * e2z - e1z * e2y; | ||
199 | ny = e1z * e2x - e1x * e2z; | ||
200 | nz = e1x * e2y - e1y * e2x; | ||
201 | |||
202 | // Length | ||
203 | float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); | ||
204 | float lReciprocal = 1.0f / l; | ||
205 | |||
206 | // Normalized "normal" | ||
207 | //nx /= l; | ||
208 | //ny /= l; | ||
209 | //nz /= l; | ||
210 | |||
211 | m_normals[i] = nx * lReciprocal; | ||
212 | m_normals[i + 1] = ny * lReciprocal; | ||
213 | m_normals[i + 2] = nz * lReciprocal; | ||
214 | |||
215 | i += 3; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | public List<Vector3> getVertexList() | ||
220 | { | ||
221 | List<Vector3> result = new List<Vector3>(); | ||
222 | foreach (Vertex v in m_vertices.Keys) | ||
223 | { | ||
224 | result.Add(new Vector3(v.X, v.Y, v.Z)); | ||
225 | } | ||
226 | return result; | ||
227 | } | ||
228 | |||
229 | public float[] getVertexListAsFloat() | ||
230 | { | ||
231 | if (m_vertices == null) | ||
232 | throw new NotSupportedException(); | ||
233 | float[] result = new float[m_vertices.Count * 3]; | ||
234 | foreach (KeyValuePair<Vertex, int> kvp in m_vertices) | ||
235 | { | ||
236 | Vertex v = kvp.Key; | ||
237 | int i = kvp.Value; | ||
238 | result[3 * i + 0] = v.X; | ||
239 | result[3 * i + 1] = v.Y; | ||
240 | result[3 * i + 2] = v.Z; | ||
241 | } | ||
242 | return result; | ||
243 | } | ||
244 | |||
245 | public float[] getVertexListAsFloatLocked() | ||
246 | { | ||
247 | if (m_pinnedVertexes.IsAllocated) | ||
248 | return (float[])(m_pinnedVertexes.Target); | ||
249 | |||
250 | float[] result = getVertexListAsFloat(); | ||
251 | m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
252 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
253 | // the next GC round more intelligently | ||
254 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
255 | |||
256 | return result; | ||
257 | } | ||
258 | |||
259 | public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) | ||
260 | { | ||
261 | // A vertex is 3 floats | ||
262 | |||
263 | vertexStride = 3 * sizeof(float); | ||
264 | |||
265 | // If there isn't an unmanaged array allocated yet, do it now | ||
266 | if (m_verticesPtr == IntPtr.Zero) | ||
267 | { | ||
268 | float[] vertexList = getVertexListAsFloat(); | ||
269 | // Each vertex is 3 elements (floats) | ||
270 | m_vertexCount = vertexList.Length / 3; | ||
271 | int byteCount = m_vertexCount * vertexStride; | ||
272 | m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
273 | System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); | ||
274 | } | ||
275 | vertices = m_verticesPtr; | ||
276 | vertexCount = m_vertexCount; | ||
277 | } | ||
278 | |||
279 | public int[] getIndexListAsInt() | ||
280 | { | ||
281 | if (m_triangles == null) | ||
282 | throw new NotSupportedException(); | ||
283 | int[] result = new int[m_triangles.Count * 3]; | ||
284 | for (int i = 0; i < m_triangles.Count; i++) | ||
285 | { | ||
286 | Triangle t = m_triangles[i]; | ||
287 | result[3 * i + 0] = m_vertices[t.v1]; | ||
288 | result[3 * i + 1] = m_vertices[t.v2]; | ||
289 | result[3 * i + 2] = m_vertices[t.v3]; | ||
290 | } | ||
291 | return result; | ||
292 | } | ||
293 | |||
294 | /// <summary> | ||
295 | /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA | ||
296 | /// </summary> | ||
297 | /// <returns></returns> | ||
298 | public int[] getIndexListAsIntLocked() | ||
299 | { | ||
300 | if (m_pinnedIndex.IsAllocated) | ||
301 | return (int[])(m_pinnedIndex.Target); | ||
302 | |||
303 | int[] result = getIndexListAsInt(); | ||
304 | m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
305 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
306 | // the next GC round more intelligently | ||
307 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
308 | |||
309 | return result; | ||
310 | } | ||
311 | |||
312 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) | ||
313 | { | ||
314 | // If there isn't an unmanaged array allocated yet, do it now | ||
315 | if (m_indicesPtr == IntPtr.Zero) | ||
316 | { | ||
317 | int[] indexList = getIndexListAsInt(); | ||
318 | m_indexCount = indexList.Length; | ||
319 | int byteCount = m_indexCount * sizeof(int); | ||
320 | m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
321 | System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); | ||
322 | } | ||
323 | // A triangle is 3 ints (indices) | ||
324 | triStride = 3 * sizeof(int); | ||
325 | indices = m_indicesPtr; | ||
326 | indexCount = m_indexCount; | ||
327 | } | ||
328 | |||
329 | public void releasePinned() | ||
330 | { | ||
331 | if (m_pinnedVertexes.IsAllocated) | ||
332 | m_pinnedVertexes.Free(); | ||
333 | if (m_pinnedIndex.IsAllocated) | ||
334 | m_pinnedIndex.Free(); | ||
335 | if (m_verticesPtr != IntPtr.Zero) | ||
336 | { | ||
337 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); | ||
338 | m_verticesPtr = IntPtr.Zero; | ||
339 | } | ||
340 | if (m_indicesPtr != IntPtr.Zero) | ||
341 | { | ||
342 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); | ||
343 | m_indicesPtr = IntPtr.Zero; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /// <summary> | ||
348 | /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions | ||
349 | /// </summary> | ||
350 | public void releaseSourceMeshData() | ||
351 | { | ||
352 | m_triangles = null; | ||
353 | m_vertices = null; | ||
354 | } | ||
355 | |||
356 | public void Append(IMesh newMesh) | ||
357 | { | ||
358 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
359 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | ||
360 | |||
361 | if (!(newMesh is Mesh)) | ||
362 | return; | ||
363 | |||
364 | foreach (Triangle t in ((Mesh)newMesh).m_triangles) | ||
365 | Add(t); | ||
366 | } | ||
367 | |||
368 | // Do a linear transformation of mesh. | ||
369 | public void TransformLinear(float[,] matrix, float[] offset) | ||
370 | { | ||
371 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
372 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | ||
373 | |||
374 | foreach (Vertex v in m_vertices.Keys) | ||
375 | { | ||
376 | if (v == null) | ||
377 | continue; | ||
378 | float x, y, z; | ||
379 | x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0]; | ||
380 | y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1]; | ||
381 | z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2]; | ||
382 | v.X = x + offset[0]; | ||
383 | v.Y = y + offset[1]; | ||
384 | v.Z = z + offset[2]; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | public void DumpRaw(String path, String name, String title) | ||
389 | { | ||
390 | if (path == null) | ||
391 | return; | ||
392 | String fileName = name + "_" + title + ".raw"; | ||
393 | String completePath = System.IO.Path.Combine(path, fileName); | ||
394 | StreamWriter sw = new StreamWriter(completePath); | ||
395 | foreach (Triangle t in m_triangles) | ||
396 | { | ||
397 | String s = t.ToStringRaw(); | ||
398 | sw.WriteLine(s); | ||
399 | } | ||
400 | sw.Close(); | ||
401 | } | ||
402 | |||
403 | public void TrimExcess() | ||
404 | { | ||
405 | m_triangles.TrimExcess(); | ||
406 | } | ||
407 | } | ||
408 | } | ||