OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
Mesh.cs
Go to the documentation of this file.
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.PhysicsModule.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 
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 
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 }
void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount)
Definition: Mesh.cs:312
float Z
Definition: HelperTypes.cs:53
void TransformLinear(float[,] matrix, float[] offset)
Definition: Mesh.cs:369
float X
Definition: HelperTypes.cs:41
void Add(Triangle triangle)
Definition: Mesh.cs:94
Vertex v1
Definition: HelperTypes.cs:269
void releaseSourceMeshData()
frees up the source mesh data to minimize memory - call this method after calling get*Locked() functi...
Definition: Mesh.cs:350
Vertex v3
Definition: HelperTypes.cs:271
int[] getIndexListAsIntLocked()
creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DAT...
Definition: Mesh.cs:298
void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount)
Definition: Mesh.cs:259
void DumpRaw(String path, String name, String title)
Definition: Mesh.cs:388
Interactive OpenSim region server
Definition: OpenSim.cs:55
float Y
Definition: HelperTypes.cs:47
Vertex v2
Definition: HelperTypes.cs:270
Vertex Clone()
Definition: HelperTypes.cs:190