Mesh.cs 12 KB

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