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 using System.Runtime.Serialization;
36 using System.Runtime.Serialization.Formatters.Binary;
37 
38 namespace OpenSim.Region.PhysicsModule.ubODEMeshing
39 {
40  public class MeshBuildingData
41  {
42  public Dictionary<Vertex, int> m_vertices;
43  public List<Triangle> m_triangles;
44  public float m_obbXmin;
45  public float m_obbXmax;
46  public float m_obbYmin;
47  public float m_obbYmax;
48  public float m_obbZmin;
49  public float m_obbZmax;
50  public Vector3 m_centroid;
51  public int m_centroidDiv;
52  }
53 
54  [Serializable()]
55  public class Mesh : IMesh
56  {
57  float[] vertices;
58  int[] indexes;
59  Vector3 m_obb;
60  Vector3 m_obboffset;
61  [NonSerialized()]
62  MeshBuildingData m_bdata;
63  [NonSerialized()]
64  GCHandle vhandler;
65  [NonSerialized()]
66  GCHandle ihandler;
67  [NonSerialized()]
68  IntPtr m_verticesPtr = IntPtr.Zero;
69  [NonSerialized()]
70  IntPtr m_indicesPtr = IntPtr.Zero;
71  [NonSerialized()]
72  int m_vertexCount = 0;
73  [NonSerialized()]
74  int m_indexCount = 0;
75 
76  public int RefCount { get; set; }
77  public AMeshKey Key { get; set; }
78 
79  private class vertexcomp : IEqualityComparer<Vertex>
80  {
81  public bool Equals(Vertex v1, Vertex v2)
82  {
83  if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z)
84  return true;
85  else
86  return false;
87  }
88  public int GetHashCode(Vertex v)
89  {
90  int a = v.X.GetHashCode();
91  int b = v.Y.GetHashCode();
92  int c = v.Z.GetHashCode();
93  return (a << 16) ^ (b << 8) ^ c;
94  }
95  }
96 
97  public Mesh()
98  {
99  vertexcomp vcomp = new vertexcomp();
100 
101  m_bdata = new MeshBuildingData();
102  m_bdata.m_vertices = new Dictionary<Vertex, int>(vcomp);
103  m_bdata.m_triangles = new List<Triangle>();
104  m_bdata.m_centroid = Vector3.Zero;
105  m_bdata.m_centroidDiv = 0;
106  m_bdata.m_obbXmin = float.MaxValue;
107  m_bdata.m_obbXmax = float.MinValue;
108  m_bdata.m_obbYmin = float.MaxValue;
109  m_bdata.m_obbYmax = float.MinValue;
110  m_bdata.m_obbZmin = float.MaxValue;
111  m_bdata.m_obbZmax = float.MinValue;
112  m_obb = new Vector3(0.5f, 0.5f, 0.5f);
113  m_obboffset = Vector3.Zero;
114  }
115 
116 
117  public Mesh Scale(Vector3 scale)
118  {
119  if (m_verticesPtr == null || m_indicesPtr == null)
120  return null;
121 
122  Mesh result = new Mesh();
123 
124  float x = scale.X;
125  float y = scale.Y;
126  float z = scale.Z;
127 
128  float tmp;
129  tmp = m_obb.X * x;
130  if(tmp < 0.0005f)
131  tmp = 0.0005f;
132  result.m_obb.X = tmp;
133 
134  tmp = m_obb.Y * y;
135  if(tmp < 0.0005f)
136  tmp = 0.0005f;
137  result.m_obb.Y = tmp;
138 
139  tmp = m_obb.Z * z;
140  if(tmp < 0.0005f)
141  tmp = 0.0005f;
142  result.m_obb.Z = tmp;
143 
144  result.m_obboffset.X = m_obboffset.X * x;
145  result.m_obboffset.Y = m_obboffset.Y * y;
146  result.m_obboffset.Z = m_obboffset.Z * z;
147 
148  result.vertices = new float[vertices.Length];
149  int j = 0;
150  for (int i = 0; i < m_vertexCount; i++)
151  {
152  result.vertices[j] = vertices[j] * x;
153  j++;
154  result.vertices[j] = vertices[j] * y;
155  j++;
156  result.vertices[j] = vertices[j] * z;
157  j++;
158  }
159 
160  result.indexes = new int[indexes.Length];
161  indexes.CopyTo(result.indexes,0);
162 
163  result.pinMemory();
164 
165  return result;
166  }
167 
168  public Mesh Clone()
169  {
170  Mesh result = new Mesh();
171 
172  if (m_bdata != null)
173  {
174  result.m_bdata = new MeshBuildingData();
175  foreach (Triangle t in m_bdata.m_triangles)
176  {
177  result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
178  }
179  result.m_bdata.m_centroid = m_bdata.m_centroid;
180  result.m_bdata.m_centroidDiv = m_bdata.m_centroidDiv;
181  result.m_bdata.m_obbXmin = m_bdata.m_obbXmin;
182  result.m_bdata.m_obbXmax = m_bdata.m_obbXmax;
183  result.m_bdata.m_obbYmin = m_bdata.m_obbYmin;
184  result.m_bdata.m_obbYmax = m_bdata.m_obbYmax;
185  result.m_bdata.m_obbZmin = m_bdata.m_obbZmin;
186  result.m_bdata.m_obbZmax = m_bdata.m_obbZmax;
187  }
188  result.m_obb = m_obb;
189  result.m_obboffset = m_obboffset;
190  return result;
191  }
192 
193  public void addVertexLStats(Vertex v)
194  {
195  float x = v.X;
196  float y = v.Y;
197  float z = v.Z;
198 
199  m_bdata.m_centroid.X += x;
200  m_bdata.m_centroid.Y += y;
201  m_bdata.m_centroid.Z += z;
202  m_bdata.m_centroidDiv++;
203 
204  if (x > m_bdata.m_obbXmax)
205  m_bdata.m_obbXmax = x;
206  if (x < m_bdata.m_obbXmin)
207  m_bdata.m_obbXmin = x;
208 
209  if (y > m_bdata.m_obbYmax)
210  m_bdata.m_obbYmax = y;
211  if (y < m_bdata.m_obbYmin)
212  m_bdata.m_obbYmin = y;
213 
214  if (z > m_bdata.m_obbZmax)
215  m_bdata.m_obbZmax = z;
216  if (z < m_bdata.m_obbZmin)
217  m_bdata.m_obbZmin = z;
218 
219  }
220 
221  public void Add(Triangle triangle)
222  {
223  if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
224  throw new NotSupportedException("Attempt to Add to a pinned Mesh");
225 
226 
227  triangle.v1.X = (float)Math.Round(triangle.v1.X, 6);
228  triangle.v1.Y = (float)Math.Round(triangle.v1.Y, 6);
229  triangle.v1.Z = (float)Math.Round(triangle.v1.Z, 6);
230  triangle.v2.X = (float)Math.Round(triangle.v2.X, 6);
231  triangle.v2.Y = (float)Math.Round(triangle.v2.Y, 6);
232  triangle.v2.Z = (float)Math.Round(triangle.v2.Z, 6);
233  triangle.v3.X = (float)Math.Round(triangle.v3.X, 6);
234  triangle.v3.Y = (float)Math.Round(triangle.v3.Y, 6);
235  triangle.v3.Z = (float)Math.Round(triangle.v3.Z, 6);
236 
237  if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z ==
238  triangle.v2.Z)
239  || (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z ==
240  triangle.v3.Z)
241  || (triangle.v2.X == triangle.v3.X && triangle.v2.Y == triangle.v3.Y && triangle.v2.Z ==
242  triangle.v3.Z)
243  )
244  {
245  return;
246  }
247 
248  if (m_bdata.m_vertices.Count == 0)
249  {
250  m_bdata.m_centroidDiv = 0;
251  m_bdata.m_centroid = Vector3.Zero;
252  }
253 
254  if (!m_bdata.m_vertices.ContainsKey(triangle.v1))
255  {
256  m_bdata.m_vertices[triangle.v1] = m_bdata.m_vertices.Count;
257  addVertexLStats(triangle.v1);
258  }
259  if (!m_bdata.m_vertices.ContainsKey(triangle.v2))
260  {
261  m_bdata.m_vertices[triangle.v2] = m_bdata.m_vertices.Count;
262  addVertexLStats(triangle.v2);
263  }
264  if (!m_bdata.m_vertices.ContainsKey(triangle.v3))
265  {
266  m_bdata.m_vertices[triangle.v3] = m_bdata.m_vertices.Count;
267  addVertexLStats(triangle.v3);
268  }
269  m_bdata.m_triangles.Add(triangle);
270  }
271 
272  public Vector3 GetCentroid()
273  {
274  return m_obboffset;
275 
276  }
277 
278  public Vector3 GetOBB()
279  {
280  return m_obb;
281 /*
282  float x, y, z;
283  if (m_bdata.m_centroidDiv > 0)
284  {
285  x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f;
286  y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f;
287  z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f;
288  }
289  else // ??
290  {
291  x = 0.5f;
292  y = 0.5f;
293  z = 0.5f;
294  }
295  return new Vector3(x, y, z);
296 */
297  }
298 
299  public int numberVertices()
300  {
301  return m_bdata.m_vertices.Count;
302  }
303 
304  public int numberTriangles()
305  {
306  return m_bdata.m_triangles.Count;
307  }
308 
309  public List<Vector3> getVertexList()
310  {
311  List<Vector3> result = new List<Vector3>();
312  foreach (Vertex v in m_bdata.m_vertices.Keys)
313  {
314  result.Add(new Vector3(v.X, v.Y, v.Z));
315  }
316  return result;
317  }
318 
319  public float[] getVertexListAsFloat()
320  {
321  if (m_bdata.m_vertices == null)
322  throw new NotSupportedException();
323  float[] result = new float[m_bdata.m_vertices.Count * 3];
324  foreach (KeyValuePair<Vertex, int> kvp in m_bdata.m_vertices)
325  {
326  Vertex v = kvp.Key;
327  int i = kvp.Value;
328  result[3 * i + 0] = v.X;
329  result[3 * i + 1] = v.Y;
330  result[3 * i + 2] = v.Z;
331  }
332  return result;
333  }
334 
335  public float[] getVertexListAsFloatLocked()
336  {
337  return null;
338  }
339 
340  public void getVertexListAsPtrToFloatArray(out IntPtr _vertices, out int vertexStride, out int vertexCount)
341  {
342  // A vertex is 3 floats
343  vertexStride = 3 * sizeof(float);
344 
345  // If there isn't an unmanaged array allocated yet, do it now
346  if (m_verticesPtr == IntPtr.Zero && m_bdata != null)
347  {
348  vertices = getVertexListAsFloat();
349  // Each vertex is 3 elements (floats)
350  m_vertexCount = vertices.Length / 3;
351  vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
352  m_verticesPtr = vhandler.AddrOfPinnedObject();
353  GC.AddMemoryPressure(Buffer.ByteLength(vertices));
354  }
355  _vertices = m_verticesPtr;
356  vertexCount = m_vertexCount;
357  }
358 
359  public int[] getIndexListAsInt()
360  {
361  if (m_bdata.m_triangles == null)
362  throw new NotSupportedException();
363  int[] result = new int[m_bdata.m_triangles.Count * 3];
364  for (int i = 0; i < m_bdata.m_triangles.Count; i++)
365  {
366  Triangle t = m_bdata.m_triangles[i];
367  result[3 * i + 0] = m_bdata.m_vertices[t.v1];
368  result[3 * i + 1] = m_bdata.m_vertices[t.v2];
369  result[3 * i + 2] = m_bdata.m_vertices[t.v3];
370  }
371  return result;
372  }
373 
378  public int[] getIndexListAsIntLocked()
379  {
380  return null;
381  }
382 
383  public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount)
384  {
385  // If there isn't an unmanaged array allocated yet, do it now
386  if (m_indicesPtr == IntPtr.Zero && m_bdata != null)
387  {
388  indexes = getIndexListAsInt();
389  m_indexCount = indexes.Length;
390  ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
391  m_indicesPtr = ihandler.AddrOfPinnedObject();
392  GC.AddMemoryPressure(Buffer.ByteLength(indexes));
393  }
394  // A triangle is 3 ints (indices)
395  triStride = 3 * sizeof(int);
396  indices = m_indicesPtr;
397  indexCount = m_indexCount;
398  }
399 
400  public void releasePinned()
401  {
402  if (m_verticesPtr != IntPtr.Zero)
403  {
404  vhandler.Free();
405  GC.RemoveMemoryPressure(Buffer.ByteLength(vertices));
406  vertices = null;
407  m_verticesPtr = IntPtr.Zero;
408  }
409  if (m_indicesPtr != IntPtr.Zero)
410  {
411  ihandler.Free();
412  GC.RemoveMemoryPressure(Buffer.ByteLength(indexes));
413  indexes = null;
414  m_indicesPtr = IntPtr.Zero;
415  }
416  }
417 
421  public void releaseSourceMeshData()
422  {
423  if (m_bdata != null)
424  {
425  m_bdata.m_triangles = null;
426  m_bdata.m_vertices = null;
427  }
428  }
429 
431  {
432  if (m_bdata != null)
433  {
434  m_bdata.m_triangles = null;
435  m_bdata.m_vertices = null;
436  m_bdata = null;
437  }
438  }
439 
440  public void Append(IMesh newMesh)
441  {
442  if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
443  throw new NotSupportedException("Attempt to Append to a pinned Mesh");
444 
445  if (!(newMesh is Mesh))
446  return;
447 
448  foreach (Triangle t in ((Mesh)newMesh).m_bdata.m_triangles)
449  Add(t);
450  }
451 
452  // Do a linear transformation of mesh.
453  public void TransformLinear(float[,] matrix, float[] offset)
454  {
455  if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
456  throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh");
457 
458  foreach (Vertex v in m_bdata.m_vertices.Keys)
459  {
460  if (v == null)
461  continue;
462  float x, y, z;
463  x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0];
464  y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1];
465  z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2];
466  v.X = x + offset[0];
467  v.Y = y + offset[1];
468  v.Z = z + offset[2];
469  }
470  }
471 
472  public void DumpRaw(String path, String name, String title)
473  {
474  if (path == null)
475  return;
476  if (m_bdata == null)
477  return;
478  String fileName = name + "_" + title + ".raw";
479  String completePath = System.IO.Path.Combine(path, fileName);
480  StreamWriter sw = new StreamWriter(completePath);
481  foreach (Triangle t in m_bdata.m_triangles)
482  {
483  String s = t.ToStringRaw();
484  sw.WriteLine(s);
485  }
486  sw.Close();
487  }
488 
489  public void TrimExcess()
490  {
491  m_bdata.m_triangles.TrimExcess();
492  }
493 
494  public void pinMemory()
495  {
496  m_vertexCount = vertices.Length / 3;
497  vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
498  m_verticesPtr = vhandler.AddrOfPinnedObject();
499  GC.AddMemoryPressure(Buffer.ByteLength(vertices));
500 
501  m_indexCount = indexes.Length;
502  ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
503  m_indicesPtr = ihandler.AddrOfPinnedObject();
504  GC.AddMemoryPressure(Buffer.ByteLength(indexes));
505  }
506 
507  public void PrepForOde()
508  {
509  // If there isn't an unmanaged array allocated yet, do it now
510  if (m_verticesPtr == IntPtr.Zero)
511  vertices = getVertexListAsFloat();
512 
513  // If there isn't an unmanaged array allocated yet, do it now
514  if (m_indicesPtr == IntPtr.Zero)
515  indexes = getIndexListAsInt();
516 
517  pinMemory();
518 
519  float x, y, z;
520 
521  if (m_bdata.m_centroidDiv > 0)
522  {
523  m_obboffset = new Vector3(m_bdata.m_centroid.X / m_bdata.m_centroidDiv, m_bdata.m_centroid.Y / m_bdata.m_centroidDiv, m_bdata.m_centroid.Z / m_bdata.m_centroidDiv);
524  x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f;
525  if(x < 0.0005f)
526  x = 0.0005f;
527  y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f;
528  if(y < 0.0005f)
529  y = 0.0005f;
530  z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f;
531  if(z < 0.0005f)
532  z = 0.0005f;
533  }
534 
535  else
536  {
537  m_obboffset = Vector3.Zero;
538  x = 0.5f;
539  y = 0.5f;
540  z = 0.5f;
541  }
542 
543  m_obb = new Vector3(x, y, z);
544 
545  releaseBuildingMeshData();
546  }
547  public bool ToStream(Stream st)
548  {
549  if (m_indicesPtr == IntPtr.Zero || m_verticesPtr == IntPtr.Zero)
550  return false;
551 
552  BinaryWriter bw = new BinaryWriter(st);
553  bool ok = true;
554 
555  try
556  {
557 
558  bw.Write(m_vertexCount);
559  bw.Write(m_indexCount);
560 
561  for (int i = 0; i < 3 * m_vertexCount; i++)
562  bw.Write(vertices[i]);
563  for (int i = 0; i < m_indexCount; i++)
564  bw.Write(indexes[i]);
565  bw.Write(m_obb.X);
566  bw.Write(m_obb.Y);
567  bw.Write(m_obb.Z);
568  bw.Write(m_obboffset.X);
569  bw.Write(m_obboffset.Y);
570  bw.Write(m_obboffset.Z);
571  }
572  catch
573  {
574  ok = false;
575  }
576 
577  if (bw != null)
578  {
579  bw.Flush();
580  bw.Close();
581  }
582 
583  return ok;
584  }
585 
586  public static Mesh FromStream(Stream st, AMeshKey key)
587  {
588  Mesh mesh = new Mesh();
589  mesh.releaseBuildingMeshData();
590 
591  BinaryReader br = new BinaryReader(st);
592 
593  bool ok = true;
594  try
595  {
596  mesh.m_vertexCount = br.ReadInt32();
597  mesh.m_indexCount = br.ReadInt32();
598 
599  int n = 3 * mesh.m_vertexCount;
600  mesh.vertices = new float[n];
601  for (int i = 0; i < n; i++)
602  mesh.vertices[i] = br.ReadSingle();
603 
604  mesh.indexes = new int[mesh.m_indexCount];
605  for (int i = 0; i < mesh.m_indexCount; i++)
606  mesh.indexes[i] = br.ReadInt32();
607 
608  mesh.m_obb.X = br.ReadSingle();
609  mesh.m_obb.Y = br.ReadSingle();
610  mesh.m_obb.Z = br.ReadSingle();
611 
612  mesh.m_obboffset.X = br.ReadSingle();
613  mesh.m_obboffset.Y = br.ReadSingle();
614  mesh.m_obboffset.Z = br.ReadSingle();
615  }
616  catch
617  {
618  ok = false;
619  }
620 
621  br.Close();
622 
623  if (ok)
624  {
625  mesh.pinMemory();
626 
627  mesh.Key = key;
628  mesh.RefCount = 1;
629 
630  return mesh;
631  }
632 
633  mesh.vertices = null;
634  mesh.indexes = null;
635  return null;
636  }
637  }
638 }
float Z
Definition: HelperTypes.cs:53
float X
Definition: HelperTypes.cs:41
Vertex v1
Definition: HelperTypes.cs:269
Vertex v3
Definition: HelperTypes.cs:271
void releaseSourceMeshData()
frees up the source mesh data to minimize memory - call this method after calling get*Locked() functi...
Definition: Mesh.cs:421
void DumpRaw(String path, String name, String title)
Definition: Mesh.cs:472
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31
static Mesh FromStream(Stream st, AMeshKey key)
Definition: Mesh.cs:586
void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount)
Definition: Mesh.cs:383
Interactive OpenSim region server
Definition: OpenSim.cs:55
int[] getIndexListAsIntLocked()
creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DAT...
Definition: Mesh.cs:378
float Y
Definition: HelperTypes.cs:47
Vertex v2
Definition: HelperTypes.cs:270
void TransformLinear(float[,] matrix, float[] offset)
Definition: Mesh.cs:453
Vertex Clone()
Definition: HelperTypes.cs:190
void getVertexListAsPtrToFloatArray(out IntPtr _vertices, out int vertexStride, out int vertexCount)
Definition: Mesh.cs:340