Mesh.cs 14 KB

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