Mesh.cs 11 KB

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