diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/UbitMeshing/Mesh.cs | 401 |
1 files changed, 401 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..c715642 --- /dev/null +++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs | |||
@@ -0,0 +1,401 @@ | |||
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 | 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 | public void CalcNormals() | ||
152 | { | ||
153 | int iTriangles = m_triangles.Count; | ||
154 | |||
155 | this.m_normals = new float[iTriangles * 3]; | ||
156 | |||
157 | int i = 0; | ||
158 | foreach (Triangle t in m_triangles) | ||
159 | { | ||
160 | float ux, uy, uz; | ||
161 | float vx, vy, vz; | ||
162 | float wx, wy, wz; | ||
163 | |||
164 | ux = t.v1.X; | ||
165 | uy = t.v1.Y; | ||
166 | uz = t.v1.Z; | ||
167 | |||
168 | vx = t.v2.X; | ||
169 | vy = t.v2.Y; | ||
170 | vz = t.v2.Z; | ||
171 | |||
172 | wx = t.v3.X; | ||
173 | wy = t.v3.Y; | ||
174 | wz = t.v3.Z; | ||
175 | |||
176 | |||
177 | // Vectors for edges | ||
178 | float e1x, e1y, e1z; | ||
179 | float e2x, e2y, e2z; | ||
180 | |||
181 | e1x = ux - vx; | ||
182 | e1y = uy - vy; | ||
183 | e1z = uz - vz; | ||
184 | |||
185 | e2x = ux - wx; | ||
186 | e2y = uy - wy; | ||
187 | e2z = uz - wz; | ||
188 | |||
189 | |||
190 | // Cross product for normal | ||
191 | float nx, ny, nz; | ||
192 | nx = e1y * e2z - e1z * e2y; | ||
193 | ny = e1z * e2x - e1x * e2z; | ||
194 | nz = e1x * e2y - e1y * e2x; | ||
195 | |||
196 | // Length | ||
197 | float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); | ||
198 | float lReciprocal = 1.0f / l; | ||
199 | |||
200 | // Normalized "normal" | ||
201 | //nx /= l; | ||
202 | //ny /= l; | ||
203 | //nz /= l; | ||
204 | |||
205 | m_normals[i] = nx * lReciprocal; | ||
206 | m_normals[i + 1] = ny * lReciprocal; | ||
207 | m_normals[i + 2] = nz * lReciprocal; | ||
208 | |||
209 | i += 3; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | public List<Vector3> getVertexList() | ||
214 | { | ||
215 | List<Vector3> result = new List<Vector3>(); | ||
216 | foreach (Vertex v in m_vertices.Keys) | ||
217 | { | ||
218 | result.Add(new Vector3(v.X, v.Y, v.Z)); | ||
219 | } | ||
220 | return result; | ||
221 | } | ||
222 | |||
223 | private float[] getVertexListAsFloat() | ||
224 | { | ||
225 | if (m_vertices == null) | ||
226 | throw new NotSupportedException(); | ||
227 | float[] result = new float[m_vertices.Count * 3]; | ||
228 | foreach (KeyValuePair<Vertex, int> kvp in m_vertices) | ||
229 | { | ||
230 | Vertex v = kvp.Key; | ||
231 | int i = kvp.Value; | ||
232 | result[3 * i + 0] = v.X; | ||
233 | result[3 * i + 1] = v.Y; | ||
234 | result[3 * i + 2] = v.Z; | ||
235 | } | ||
236 | return result; | ||
237 | } | ||
238 | |||
239 | public float[] getVertexListAsFloatLocked() | ||
240 | { | ||
241 | if (m_pinnedVertexes.IsAllocated) | ||
242 | return (float[])(m_pinnedVertexes.Target); | ||
243 | |||
244 | float[] result = getVertexListAsFloat(); | ||
245 | m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
246 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
247 | // the next GC round more intelligently | ||
248 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
249 | |||
250 | return result; | ||
251 | } | ||
252 | |||
253 | public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) | ||
254 | { | ||
255 | // A vertex is 3 floats | ||
256 | vertexStride = 3 * sizeof(float); | ||
257 | |||
258 | // If there isn't an unmanaged array allocated yet, do it now | ||
259 | if (m_verticesPtr == IntPtr.Zero) | ||
260 | { | ||
261 | float[] vertexList = getVertexListAsFloat(); | ||
262 | // Each vertex is 3 elements (floats) | ||
263 | m_vertexCount = vertexList.Length / 3; | ||
264 | int byteCount = m_vertexCount * vertexStride; | ||
265 | m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
266 | System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); | ||
267 | } | ||
268 | vertices = m_verticesPtr; | ||
269 | vertexCount = m_vertexCount; | ||
270 | } | ||
271 | |||
272 | public int[] getIndexListAsInt() | ||
273 | { | ||
274 | if (m_triangles == null) | ||
275 | throw new NotSupportedException(); | ||
276 | int[] result = new int[m_triangles.Count * 3]; | ||
277 | for (int i = 0; i < m_triangles.Count; i++) | ||
278 | { | ||
279 | Triangle t = m_triangles[i]; | ||
280 | result[3 * i + 0] = m_vertices[t.v1]; | ||
281 | result[3 * i + 1] = m_vertices[t.v2]; | ||
282 | result[3 * i + 2] = m_vertices[t.v3]; | ||
283 | } | ||
284 | return result; | ||
285 | } | ||
286 | |||
287 | /// <summary> | ||
288 | /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA | ||
289 | /// </summary> | ||
290 | /// <returns></returns> | ||
291 | public int[] getIndexListAsIntLocked() | ||
292 | { | ||
293 | if (m_pinnedIndex.IsAllocated) | ||
294 | return (int[])(m_pinnedIndex.Target); | ||
295 | |||
296 | int[] result = getIndexListAsInt(); | ||
297 | m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
298 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
299 | // the next GC round more intelligently | ||
300 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
301 | |||
302 | return result; | ||
303 | } | ||
304 | |||
305 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) | ||
306 | { | ||
307 | // If there isn't an unmanaged array allocated yet, do it now | ||
308 | if (m_indicesPtr == IntPtr.Zero) | ||
309 | { | ||
310 | int[] indexList = getIndexListAsInt(); | ||
311 | m_indexCount = indexList.Length; | ||
312 | int byteCount = m_indexCount * sizeof(int); | ||
313 | m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
314 | System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); | ||
315 | } | ||
316 | // A triangle is 3 ints (indices) | ||
317 | triStride = 3 * sizeof(int); | ||
318 | indices = m_indicesPtr; | ||
319 | indexCount = m_indexCount; | ||
320 | } | ||
321 | |||
322 | public void releasePinned() | ||
323 | { | ||
324 | if (m_pinnedVertexes.IsAllocated) | ||
325 | m_pinnedVertexes.Free(); | ||
326 | if (m_pinnedIndex.IsAllocated) | ||
327 | m_pinnedIndex.Free(); | ||
328 | if (m_verticesPtr != IntPtr.Zero) | ||
329 | { | ||
330 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); | ||
331 | m_verticesPtr = IntPtr.Zero; | ||
332 | } | ||
333 | if (m_indicesPtr != IntPtr.Zero) | ||
334 | { | ||
335 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); | ||
336 | m_indicesPtr = IntPtr.Zero; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | /// <summary> | ||
341 | /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions | ||
342 | /// </summary> | ||
343 | public void releaseSourceMeshData() | ||
344 | { | ||
345 | m_triangles = null; | ||
346 | m_vertices = null; | ||
347 | } | ||
348 | |||
349 | public void Append(IMesh newMesh) | ||
350 | { | ||
351 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
352 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | ||
353 | |||
354 | if (!(newMesh is Mesh)) | ||
355 | return; | ||
356 | |||
357 | foreach (Triangle t in ((Mesh)newMesh).m_triangles) | ||
358 | Add(t); | ||
359 | } | ||
360 | |||
361 | // Do a linear transformation of mesh. | ||
362 | public void TransformLinear(float[,] matrix, float[] offset) | ||
363 | { | ||
364 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
365 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | ||
366 | |||
367 | foreach (Vertex v in m_vertices.Keys) | ||
368 | { | ||
369 | if (v == null) | ||
370 | continue; | ||
371 | float x, y, z; | ||
372 | x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0]; | ||
373 | y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1]; | ||
374 | z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2]; | ||
375 | v.X = x + offset[0]; | ||
376 | v.Y = y + offset[1]; | ||
377 | v.Z = z + offset[2]; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | public void DumpRaw(String path, String name, String title) | ||
382 | { | ||
383 | if (path == null) | ||
384 | return; | ||
385 | String fileName = name + "_" + title + ".raw"; | ||
386 | String completePath = System.IO.Path.Combine(path, fileName); | ||
387 | StreamWriter sw = new StreamWriter(completePath); | ||
388 | foreach (Triangle t in m_triangles) | ||
389 | { | ||
390 | String s = t.ToStringRaw(); | ||
391 | sw.WriteLine(s); | ||
392 | } | ||
393 | sw.Close(); | ||
394 | } | ||
395 | |||
396 | public void TrimExcess() | ||
397 | { | ||
398 | m_triangles.TrimExcess(); | ||
399 | } | ||
400 | } | ||
401 | } | ||