diff options
Diffstat (limited to 'OpenSim/Region/PhysicsModules/Meshing/Mesh.cs')
-rw-r--r-- | OpenSim/Region/PhysicsModules/Meshing/Mesh.cs | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/Meshing/Mesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Mesh.cs new file mode 100644 index 0000000..bd8e306 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Mesh.cs | |||
@@ -0,0 +1,333 @@ | |||
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 | |||
50 | public Mesh() | ||
51 | { | ||
52 | m_vertices = new Dictionary<Vertex, int>(); | ||
53 | m_triangles = new List<Triangle>(); | ||
54 | } | ||
55 | |||
56 | public Mesh Clone() | ||
57 | { | ||
58 | Mesh result = new Mesh(); | ||
59 | |||
60 | foreach (Triangle t in m_triangles) | ||
61 | { | ||
62 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); | ||
63 | } | ||
64 | |||
65 | return result; | ||
66 | } | ||
67 | |||
68 | public void Add(Triangle triangle) | ||
69 | { | ||
70 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
71 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | ||
72 | // If a vertex of the triangle is not yet in the vertices list, | ||
73 | // add it and set its index to the current index count | ||
74 | if (!m_vertices.ContainsKey(triangle.v1)) | ||
75 | m_vertices[triangle.v1] = m_vertices.Count; | ||
76 | if (!m_vertices.ContainsKey(triangle.v2)) | ||
77 | m_vertices[triangle.v2] = m_vertices.Count; | ||
78 | if (!m_vertices.ContainsKey(triangle.v3)) | ||
79 | m_vertices[triangle.v3] = m_vertices.Count; | ||
80 | m_triangles.Add(triangle); | ||
81 | } | ||
82 | |||
83 | public void CalcNormals() | ||
84 | { | ||
85 | int iTriangles = m_triangles.Count; | ||
86 | |||
87 | this.m_normals = new float[iTriangles * 3]; | ||
88 | |||
89 | int i = 0; | ||
90 | foreach (Triangle t in m_triangles) | ||
91 | { | ||
92 | float ux, uy, uz; | ||
93 | float vx, vy, vz; | ||
94 | float wx, wy, wz; | ||
95 | |||
96 | ux = t.v1.X; | ||
97 | uy = t.v1.Y; | ||
98 | uz = t.v1.Z; | ||
99 | |||
100 | vx = t.v2.X; | ||
101 | vy = t.v2.Y; | ||
102 | vz = t.v2.Z; | ||
103 | |||
104 | wx = t.v3.X; | ||
105 | wy = t.v3.Y; | ||
106 | wz = t.v3.Z; | ||
107 | |||
108 | |||
109 | // Vectors for edges | ||
110 | float e1x, e1y, e1z; | ||
111 | float e2x, e2y, e2z; | ||
112 | |||
113 | e1x = ux - vx; | ||
114 | e1y = uy - vy; | ||
115 | e1z = uz - vz; | ||
116 | |||
117 | e2x = ux - wx; | ||
118 | e2y = uy - wy; | ||
119 | e2z = uz - wz; | ||
120 | |||
121 | |||
122 | // Cross product for normal | ||
123 | float nx, ny, nz; | ||
124 | nx = e1y * e2z - e1z * e2y; | ||
125 | ny = e1z * e2x - e1x * e2z; | ||
126 | nz = e1x * e2y - e1y * e2x; | ||
127 | |||
128 | // Length | ||
129 | float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); | ||
130 | float lReciprocal = 1.0f / l; | ||
131 | |||
132 | // Normalized "normal" | ||
133 | //nx /= l; | ||
134 | //ny /= l; | ||
135 | //nz /= l; | ||
136 | |||
137 | m_normals[i] = nx * lReciprocal; | ||
138 | m_normals[i + 1] = ny * lReciprocal; | ||
139 | m_normals[i + 2] = nz * lReciprocal; | ||
140 | |||
141 | i += 3; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | public List<Vector3> getVertexList() | ||
146 | { | ||
147 | List<Vector3> result = new List<Vector3>(); | ||
148 | foreach (Vertex v in m_vertices.Keys) | ||
149 | { | ||
150 | result.Add(new Vector3(v.X, v.Y, v.Z)); | ||
151 | } | ||
152 | return result; | ||
153 | } | ||
154 | |||
155 | public float[] getVertexListAsFloat() | ||
156 | { | ||
157 | if (m_vertices == null) | ||
158 | throw new NotSupportedException(); | ||
159 | float[] result = new float[m_vertices.Count * 3]; | ||
160 | foreach (KeyValuePair<Vertex, int> kvp in m_vertices) | ||
161 | { | ||
162 | Vertex v = kvp.Key; | ||
163 | int i = kvp.Value; | ||
164 | result[3 * i + 0] = v.X; | ||
165 | result[3 * i + 1] = v.Y; | ||
166 | result[3 * i + 2] = v.Z; | ||
167 | } | ||
168 | return result; | ||
169 | } | ||
170 | |||
171 | public float[] getVertexListAsFloatLocked() | ||
172 | { | ||
173 | if (m_pinnedVertexes.IsAllocated) | ||
174 | return (float[])(m_pinnedVertexes.Target); | ||
175 | |||
176 | float[] result = getVertexListAsFloat(); | ||
177 | m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
178 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
179 | // the next GC round more intelligently | ||
180 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
181 | |||
182 | return result; | ||
183 | } | ||
184 | |||
185 | public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) | ||
186 | { | ||
187 | // A vertex is 3 floats | ||
188 | vertexStride = 3 * sizeof(float); | ||
189 | |||
190 | // If there isn't an unmanaged array allocated yet, do it now | ||
191 | if (m_verticesPtr == IntPtr.Zero) | ||
192 | { | ||
193 | float[] vertexList = getVertexListAsFloat(); | ||
194 | // Each vertex is 3 elements (floats) | ||
195 | m_vertexCount = vertexList.Length / 3; | ||
196 | int byteCount = m_vertexCount * vertexStride; | ||
197 | m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
198 | System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); | ||
199 | } | ||
200 | vertices = m_verticesPtr; | ||
201 | vertexCount = m_vertexCount; | ||
202 | } | ||
203 | |||
204 | public int[] getIndexListAsInt() | ||
205 | { | ||
206 | if (m_triangles == null) | ||
207 | throw new NotSupportedException(); | ||
208 | int[] result = new int[m_triangles.Count * 3]; | ||
209 | for (int i = 0; i < m_triangles.Count; i++) | ||
210 | { | ||
211 | Triangle t = m_triangles[i]; | ||
212 | result[3 * i + 0] = m_vertices[t.v1]; | ||
213 | result[3 * i + 1] = m_vertices[t.v2]; | ||
214 | result[3 * i + 2] = m_vertices[t.v3]; | ||
215 | } | ||
216 | return result; | ||
217 | } | ||
218 | |||
219 | /// <summary> | ||
220 | /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA | ||
221 | /// </summary> | ||
222 | /// <returns></returns> | ||
223 | public int[] getIndexListAsIntLocked() | ||
224 | { | ||
225 | if (m_pinnedIndex.IsAllocated) | ||
226 | return (int[])(m_pinnedIndex.Target); | ||
227 | |||
228 | int[] result = getIndexListAsInt(); | ||
229 | m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
230 | // Inform the garbage collector of this unmanaged allocation so it can schedule | ||
231 | // the next GC round more intelligently | ||
232 | GC.AddMemoryPressure(Buffer.ByteLength(result)); | ||
233 | |||
234 | return result; | ||
235 | } | ||
236 | |||
237 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) | ||
238 | { | ||
239 | // If there isn't an unmanaged array allocated yet, do it now | ||
240 | if (m_indicesPtr == IntPtr.Zero) | ||
241 | { | ||
242 | int[] indexList = getIndexListAsInt(); | ||
243 | m_indexCount = indexList.Length; | ||
244 | int byteCount = m_indexCount * sizeof(int); | ||
245 | m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
246 | System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); | ||
247 | } | ||
248 | // A triangle is 3 ints (indices) | ||
249 | triStride = 3 * sizeof(int); | ||
250 | indices = m_indicesPtr; | ||
251 | indexCount = m_indexCount; | ||
252 | } | ||
253 | |||
254 | public void releasePinned() | ||
255 | { | ||
256 | if (m_pinnedVertexes.IsAllocated) | ||
257 | m_pinnedVertexes.Free(); | ||
258 | if (m_pinnedIndex.IsAllocated) | ||
259 | m_pinnedIndex.Free(); | ||
260 | if (m_verticesPtr != IntPtr.Zero) | ||
261 | { | ||
262 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); | ||
263 | m_verticesPtr = IntPtr.Zero; | ||
264 | } | ||
265 | if (m_indicesPtr != IntPtr.Zero) | ||
266 | { | ||
267 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); | ||
268 | m_indicesPtr = IntPtr.Zero; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | /// <summary> | ||
273 | /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions | ||
274 | /// </summary> | ||
275 | public void releaseSourceMeshData() | ||
276 | { | ||
277 | m_triangles = null; | ||
278 | m_vertices = null; | ||
279 | } | ||
280 | |||
281 | public void Append(IMesh newMesh) | ||
282 | { | ||
283 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
284 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | ||
285 | |||
286 | if (!(newMesh is Mesh)) | ||
287 | return; | ||
288 | |||
289 | foreach (Triangle t in ((Mesh)newMesh).m_triangles) | ||
290 | Add(t); | ||
291 | } | ||
292 | |||
293 | // Do a linear transformation of mesh. | ||
294 | public void TransformLinear(float[,] matrix, float[] offset) | ||
295 | { | ||
296 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) | ||
297 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | ||
298 | |||
299 | foreach (Vertex v in m_vertices.Keys) | ||
300 | { | ||
301 | if (v == null) | ||
302 | continue; | ||
303 | float x, y, z; | ||
304 | x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0]; | ||
305 | y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1]; | ||
306 | z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2]; | ||
307 | v.X = x + offset[0]; | ||
308 | v.Y = y + offset[1]; | ||
309 | v.Z = z + offset[2]; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | public void DumpRaw(String path, String name, String title) | ||
314 | { | ||
315 | if (path == null) | ||
316 | return; | ||
317 | String fileName = name + "_" + title + ".raw"; | ||
318 | String completePath = System.IO.Path.Combine(path, fileName); | ||
319 | StreamWriter sw = new StreamWriter(completePath); | ||
320 | foreach (Triangle t in m_triangles) | ||
321 | { | ||
322 | String s = t.ToStringRaw(); | ||
323 | sw.WriteLine(s); | ||
324 | } | ||
325 | sw.Close(); | ||
326 | } | ||
327 | |||
328 | public void TrimExcess() | ||
329 | { | ||
330 | m_triangles.TrimExcess(); | ||
331 | } | ||
332 | } | ||
333 | } | ||