diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/UbitMeshing/Mesh.cs | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs new file mode 100644 index 0000000..98c0f0b --- /dev/null +++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs | |||
@@ -0,0 +1,412 @@ | |||
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.Physics.Manager; | ||
33 | using PrimMesher; | ||
34 | using OpenMetaverse; | ||
35 | |||
36 | namespace OpenSim.Region.Physics.Meshing | ||
37 | { | ||
38 | public class Mesh : IMesh | ||
39 | { | ||
40 | |||
41 | private Dictionary<Vertex, int> m_vertices; | ||
42 | private List<Triangle> m_triangles; | ||
43 | GCHandle m_pinnedVertexes; | ||
44 | GCHandle m_pinnedIndex; | ||
45 | IntPtr m_verticesPtr = IntPtr.Zero; | ||
46 | int m_vertexCount = 0; | ||
47 | IntPtr m_indicesPtr = IntPtr.Zero; | ||
48 | int m_indexCount = 0; | ||
49 | public float[] m_normals; | ||
50 | Vector3 m_centroid; | ||
51 | int m_centroidDiv; | ||
52 | |||
53 | |||
54 | private class vertexcomp : IEqualityComparer<Vertex> | ||
55 | { | ||
56 | public bool Equals(Vertex v1, Vertex v2) | ||
57 | { | ||
58 | if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z) | ||
59 | return true; | ||
60 | else | ||
61 | return false; | ||
62 | } | ||
63 | public int GetHashCode(Vertex v) | ||
64 | { | ||
65 | int a = v.X.GetHashCode(); | ||
66 | int b = v.Y.GetHashCode(); | ||
67 | int c = v.Z.GetHashCode(); | ||
68 | return (a << 16) ^ (b << 8) ^ c; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | public Mesh() | ||
73 | { | ||
74 | vertexcomp vcomp = new vertexcomp(); | ||
75 | |||
76 | m_vertices = new Dictionary<Vertex, int>(vcomp); | ||
77 | m_triangles = new List<Triangle>(); | ||
78 | m_centroid = Vector3.Zero; | ||
79 | m_centroidDiv = 0; | ||
80 | } | ||
81 | |||
82 | public int RefCount { get; set; } | ||
83 | |||
84 | public AMeshKey Key { get; set; } | ||
85 | |||
86 | public void Scale(Vector3 scale) | ||
87 | { | ||
88 | |||
89 | |||
90 | } | ||
91 | |||
92 | public Mesh Clone() | ||
93 | { | ||
94 | Mesh result = new Mesh(); | ||
95 | |||
96 | foreach (Triangle t in m_triangles) | ||
97 | { | ||
98 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); | ||
99 | } | ||
100 | result.m_centroid = m_centroid; | ||
101 | result.m_centroidDiv = m_centroidDiv; | ||
102 | return result; | ||
103 | } | ||
104 | |||
105 | public void Add(Triangle triangle) | ||
106 | { | ||
107 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
108 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | ||
109 | // If a vertex of the triangle is not yet in the vertices list, | ||
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) | ||
114 | || (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) | ||
116 | ) | ||
117 | { | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | if (m_vertices.Count == 0) | ||
122 | { | ||
123 | m_centroidDiv = 0; | ||
124 | m_centroid = Vector3.Zero; | ||
125 | } | ||
126 | |||
127 | if (!m_vertices.ContainsKey(triangle.v1)) | ||
128 | { | ||
129 | m_vertices[triangle.v1] = m_vertices.Count; | ||
130 | m_centroid.X += triangle.v1.X; | ||
131 | m_centroid.Y += triangle.v1.Y; | ||
132 | m_centroid.Z += triangle.v1.Z; | ||
133 | m_centroidDiv++; | ||
134 | } | ||
135 | if (!m_vertices.ContainsKey(triangle.v2)) | ||
136 | { | ||
137 | m_vertices[triangle.v2] = m_vertices.Count; | ||
138 | m_centroid.X += triangle.v2.X; | ||
139 | m_centroid.Y += triangle.v2.Y; | ||
140 | m_centroid.Z += triangle.v2.Z; | ||
141 | m_centroidDiv++; | ||
142 | } | ||
143 | if (!m_vertices.ContainsKey(triangle.v3)) | ||
144 | { | ||
145 | m_vertices[triangle.v3] = m_vertices.Count; | ||
146 | m_centroid.X += triangle.v3.X; | ||
147 | m_centroid.Y += triangle.v3.Y; | ||
148 | m_centroid.Z += triangle.v3.Z; | ||
149 | m_centroidDiv++; | ||
150 | } | ||
151 | m_triangles.Add(triangle); | ||
152 | } | ||
153 | |||
154 | public Vector3 GetCentroid() | ||
155 | { | ||
156 | if (m_centroidDiv > 0) | ||
157 | return new Vector3(m_centroid.X / m_centroidDiv, m_centroid.Y / m_centroidDiv, m_centroid.Z / m_centroidDiv); | ||
158 | else | ||
159 | return Vector3.Zero; | ||
160 | } | ||
161 | |||
162 | public void CalcNormals() | ||
163 | { | ||
164 | int iTriangles = m_triangles.Count; | ||
165 | |||
166 | this.m_normals = new float[iTriangles * 3]; | ||
167 | |||
168 | int i = 0; | ||
169 | foreach (Triangle t in m_triangles) | ||
170 | { | ||
171 | float ux, uy, uz; | ||
172 | float vx, vy, vz; | ||
173 | float wx, wy, wz; | ||
174 | |||
175 | ux = t.v1.X; | ||
176 | uy = t.v1.Y; | ||
177 | uz = t.v1.Z; | ||
178 | |||
179 | vx = t.v2.X; | ||
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 | } | ||
222 | } | ||
223 | |||
224 | public List<Vector3> getVertexList() | ||
225 | { | ||
226 | List<Vector3> result = new List<Vector3>(); | ||
227 | foreach (Vertex v in m_vertices.Keys) | ||
228 | { | ||
229 | result.Add(new Vector3(v.X, v.Y, v.Z)); | ||
230 | } | ||
231 | return result; | ||
232 | } | ||
233 | |||
234 | private float[] getVertexListAsFloat() | ||
235 | { | ||
236 | if (m_vertices == null) | ||
237 | throw new NotSupportedException(); | ||
238 | float[] result = new float[m_vertices.Count * 3]; | ||
239 | foreach (KeyValuePair<Vertex, int> kvp in m_vertices) | ||
240 | { | ||
241 | Vertex v = kvp.Key; | ||
242 | int i = kvp.Value; | ||
243 | result[3 * i + 0] = v.X; | ||
244 | result[3 * i + 1] = v.Y; | ||
245 | result[3 * i + 2] = v.Z; | ||
246 | } | ||
247 | return result; | ||
248 | } | ||
249 | |||
250 | public float[] getVertexListAsFloatLocked() | ||
251 | { | ||
252 | if (m_pinnedVertexes.IsAllocated) | ||
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 | } | ||
263 | |||
264 | public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) | ||
265 | { | ||
266 | // A vertex is 3 floats | ||
267 | vertexStride = 3 * sizeof(float); | ||
268 | |||
269 | // If there isn't an unmanaged array allocated yet, do it now | ||
270 | if (m_verticesPtr == IntPtr.Zero) | ||
271 | { | ||
272 | float[] vertexList = getVertexListAsFloat(); | ||
273 | // Each vertex is 3 elements (floats) | ||
274 | m_vertexCount = vertexList.Length / 3; | ||
275 | int byteCount = m_vertexCount * vertexStride; | ||
276 | m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
277 | System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); | ||
278 | } | ||
279 | vertices = m_verticesPtr; | ||
280 | vertexCount = m_vertexCount; | ||
281 | } | ||
282 | |||
283 | public int[] getIndexListAsInt() | ||
284 | { | ||
285 | if (m_triangles == null) | ||
286 | throw new NotSupportedException(); | ||
287 | int[] result = new int[m_triangles.Count * 3]; | ||
288 | for (int i = 0; i < m_triangles.Count; i++) | ||
289 | { | ||
290 | Triangle t = m_triangles[i]; | ||
291 | result[3 * i + 0] = m_vertices[t.v1]; | ||
292 | result[3 * i + 1] = m_vertices[t.v2]; | ||
293 | result[3 * i + 2] = m_vertices[t.v3]; | ||
294 | } | ||
295 | return result; | ||
296 | } | ||
297 | |||
298 | /// <summary> | ||
299 | /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA | ||
300 | /// </summary> | ||
301 | /// <returns></returns> | ||
302 | public int[] getIndexListAsIntLocked() | ||
303 | { | ||
304 | if (m_pinnedIndex.IsAllocated) | ||
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 | } | ||
315 | |||
316 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) | ||
317 | { | ||
318 | // If there isn't an unmanaged array allocated yet, do it now | ||
319 | if (m_indicesPtr == IntPtr.Zero) | ||
320 | { | ||
321 | int[] indexList = getIndexListAsInt(); | ||
322 | m_indexCount = indexList.Length; | ||
323 | int byteCount = m_indexCount * sizeof(int); | ||
324 | m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
325 | System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); | ||
326 | } | ||
327 | // A triangle is 3 ints (indices) | ||
328 | triStride = 3 * sizeof(int); | ||
329 | indices = m_indicesPtr; | ||
330 | indexCount = m_indexCount; | ||
331 | } | ||
332 | |||
333 | public void releasePinned() | ||
334 | { | ||
335 | if (m_pinnedVertexes.IsAllocated) | ||
336 | m_pinnedVertexes.Free(); | ||
337 | if (m_pinnedIndex.IsAllocated) | ||
338 | m_pinnedIndex.Free(); | ||
339 | if (m_verticesPtr != IntPtr.Zero) | ||
340 | { | ||
341 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); | ||
342 | m_verticesPtr = IntPtr.Zero; | ||
343 | } | ||
344 | if (m_indicesPtr != IntPtr.Zero) | ||
345 | { | ||
346 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); | ||
347 | m_indicesPtr = IntPtr.Zero; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | /// <summary> | ||
352 | /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions | ||
353 | /// </summary> | ||
354 | public void releaseSourceMeshData() | ||
355 | { | ||
356 | m_triangles = null; | ||
357 | m_vertices = null; | ||
358 | } | ||
359 | |||
360 | public void Append(IMesh newMesh) | ||
361 | { | ||
362 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
363 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | ||
364 | |||
365 | if (!(newMesh is Mesh)) | ||
366 | return; | ||
367 | |||
368 | foreach (Triangle t in ((Mesh)newMesh).m_triangles) | ||
369 | Add(t); | ||
370 | } | ||
371 | |||
372 | // Do a linear transformation of mesh. | ||
373 | public void TransformLinear(float[,] matrix, float[] offset) | ||
374 | { | ||
375 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
376 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | ||
377 | |||
378 | foreach (Vertex v in m_vertices.Keys) | ||
379 | { | ||
380 | if (v == null) | ||
381 | continue; | ||
382 | float x, y, z; | ||
383 | x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0]; | ||
384 | y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1]; | ||
385 | z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2]; | ||
386 | v.X = x + offset[0]; | ||
387 | v.Y = y + offset[1]; | ||
388 | v.Z = z + offset[2]; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | public void DumpRaw(String path, String name, String title) | ||
393 | { | ||
394 | if (path == null) | ||
395 | return; | ||
396 | String fileName = name + "_" + title + ".raw"; | ||
397 | String completePath = System.IO.Path.Combine(path, fileName); | ||
398 | StreamWriter sw = new StreamWriter(completePath); | ||
399 | foreach (Triangle t in m_triangles) | ||
400 | { | ||
401 | String s = t.ToStringRaw(); | ||
402 | sw.WriteLine(s); | ||
403 | } | ||
404 | sw.Close(); | ||
405 | } | ||
406 | |||
407 | public void TrimExcess() | ||
408 | { | ||
409 | m_triangles.TrimExcess(); | ||
410 | } | ||
411 | } | ||
412 | } | ||