OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
Meshmerizer.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 //#define SPAM
28 
29 using System;
30 using System.Collections.Generic;
31 using OpenSim.Framework;
32 using OpenSim.Region.Framework.Scenes;
33 using OpenSim.Region.Framework.Interfaces;
34 using OpenSim.Region.PhysicsModules.SharedBase;
35 using OpenSim.Region.PhysicsModules.ConvexDecompositionDotNet;
36 using OpenMetaverse;
37 using OpenMetaverse.StructuredData;
38 using System.Drawing;
39 using System.Drawing.Imaging;
40 using System.IO.Compression;
41 using PrimMesher;
42 using log4net;
43 using Nini.Config;
44 using System.Reflection;
45 using System.IO;
46 using System.Runtime.Serialization;
47 using System.Runtime.Serialization.Formatters.Binary;
48 
49 using Mono.Addins;
50 
51 namespace OpenSim.Region.PhysicsModule.ubODEMeshing
52 {
53  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ubODEMeshmerizer")]
55  {
56  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 
58  // Setting baseDir to a path will enable the dumping of raw files
59  // raw files can be imported by blender so a visual inspection of the results can be done
60 
61  private bool m_Enabled = false;
62 
63  public object diskLock = new object();
64 
65  public bool doMeshFileCache = true;
66 
67  public string cachePath = "MeshCache";
68  public TimeSpan CacheExpire;
69  public bool doCacheExpire = true;
70 
71 // const string baseDir = "rawFiles";
72  private const string baseDir = null; //"rawFiles";
73 
74  private bool useMeshiesPhysicsMesh = false;
75 
76  private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
77 
78  private Dictionary<AMeshKey, Mesh> m_uniqueMeshes = new Dictionary<AMeshKey, Mesh>();
79  private Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes = new Dictionary<AMeshKey, Mesh>();
80 
81  #region INonSharedRegionModule
82  public string Name
83  {
84  get { return "ubODEMeshmerizer"; }
85  }
86 
87  public Type ReplaceableInterface
88  {
89  get { return null; }
90  }
91 
92  public void Initialise(IConfigSource config)
93  {
94  IConfig start_config = config.Configs["Startup"];
95 
96  string mesher = start_config.GetString("meshing", string.Empty);
97  if (mesher == Name)
98  {
99  float fcache = 48.0f;
100  // float fcache = 0.02f;
101 
102  IConfig mesh_config = config.Configs["Mesh"];
103  if (mesh_config != null)
104  {
105  useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
106  if (useMeshiesPhysicsMesh)
107  {
108  doMeshFileCache = mesh_config.GetBoolean("MeshFileCache", doMeshFileCache);
109  cachePath = mesh_config.GetString("MeshFileCachePath", cachePath);
110  fcache = mesh_config.GetFloat("MeshFileCacheExpireHours", fcache);
111  doCacheExpire = mesh_config.GetBoolean("MeshFileCacheDoExpire", doCacheExpire);
112  }
113  else
114  {
115  doMeshFileCache = false;
116  doCacheExpire = false;
117  }
118 
119  m_Enabled = true;
120  }
121 
122  CacheExpire = TimeSpan.FromHours(fcache);
123 
124  if(doMeshFileCache && cachePath != "")
125  {
126  lock (diskLock)
127  {
128  try
129  {
130  if (!Directory.Exists(cachePath))
131  Directory.CreateDirectory(cachePath);
132  }
133  catch
134  {
135  doMeshFileCache = false;
136  doCacheExpire = false;
137  }
138  }
139  }
140  }
141  }
142 
143  public void Close()
144  {
145  }
146 
147  public void AddRegion(Scene scene)
148  {
149  if (!m_Enabled)
150  return;
151 
152  scene.RegisterModuleInterface<IMesher>(this);
153  }
154 
155  public void RemoveRegion(Scene scene)
156  {
157  if (!m_Enabled)
158  return;
159 
160  scene.UnregisterModuleInterface<IMesher>(this);
161  }
162 
163  public void RegionLoaded(Scene scene)
164  {
165  if (!m_Enabled)
166  return;
167  }
168 
169  #endregion
170 
183  private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
184  {
185  Mesh box = new Mesh();
186  List<Vertex> vertices = new List<Vertex>();
187  // bottom
188 
189  vertices.Add(new Vertex(minX, maxY, minZ));
190  vertices.Add(new Vertex(maxX, maxY, minZ));
191  vertices.Add(new Vertex(maxX, minY, minZ));
192  vertices.Add(new Vertex(minX, minY, minZ));
193 
194  box.Add(new Triangle(vertices[0], vertices[1], vertices[2]));
195  box.Add(new Triangle(vertices[0], vertices[2], vertices[3]));
196 
197  // top
198 
199  vertices.Add(new Vertex(maxX, maxY, maxZ));
200  vertices.Add(new Vertex(minX, maxY, maxZ));
201  vertices.Add(new Vertex(minX, minY, maxZ));
202  vertices.Add(new Vertex(maxX, minY, maxZ));
203 
204  box.Add(new Triangle(vertices[4], vertices[5], vertices[6]));
205  box.Add(new Triangle(vertices[4], vertices[6], vertices[7]));
206 
207  // sides
208 
209  box.Add(new Triangle(vertices[5], vertices[0], vertices[3]));
210  box.Add(new Triangle(vertices[5], vertices[3], vertices[6]));
211 
212  box.Add(new Triangle(vertices[1], vertices[0], vertices[5]));
213  box.Add(new Triangle(vertices[1], vertices[5], vertices[4]));
214 
215  box.Add(new Triangle(vertices[7], vertices[1], vertices[4]));
216  box.Add(new Triangle(vertices[7], vertices[2], vertices[1]));
217 
218  box.Add(new Triangle(vertices[3], vertices[2], vertices[7]));
219  box.Add(new Triangle(vertices[3], vertices[7], vertices[6]));
220 
221  return box;
222  }
223 
229  private static Mesh CreateBoundingBoxMesh(Mesh meshIn)
230  {
231  float minX = float.MaxValue;
232  float maxX = float.MinValue;
233  float minY = float.MaxValue;
234  float maxY = float.MinValue;
235  float minZ = float.MaxValue;
236  float maxZ = float.MinValue;
237 
238  foreach (Vector3 v in meshIn.getVertexList())
239  {
240  if (v.X < minX) minX = v.X;
241  if (v.Y < minY) minY = v.Y;
242  if (v.Z < minZ) minZ = v.Z;
243 
244  if (v.X > maxX) maxX = v.X;
245  if (v.Y > maxY) maxY = v.Y;
246  if (v.Z > maxZ) maxZ = v.Z;
247  }
248 
249  return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
250  }
251 
252  private void ReportPrimError(string message, string primName, PrimMesh primMesh)
253  {
254  m_log.Error(message);
255  m_log.Error("\nPrim Name: " + primName);
256  m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
257  }
258 
266  private void AddSubMesh(OSDMap subMeshData, List<Coord> coords, List<Face> faces)
267  {
268  // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
269 
270  // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
271  // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
272  // geometry for this submesh.
273  if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"]))
274  return;
275 
276  OpenMetaverse.Vector3 posMax;
277  OpenMetaverse.Vector3 posMin;
278  if (subMeshData.ContainsKey("PositionDomain"))
279  {
280  posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3();
281  posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3();
282  }
283  else
284  {
285  posMax = new Vector3(0.5f, 0.5f, 0.5f);
286  posMin = new Vector3(-0.5f, -0.5f, -0.5f);
287  }
288 
289  ushort faceIndexOffset = (ushort)coords.Count;
290 
291  byte[] posBytes = subMeshData["Position"].AsBinary();
292  for (int i = 0; i < posBytes.Length; i += 6)
293  {
294  ushort uX = Utils.BytesToUInt16(posBytes, i);
295  ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
296  ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
297 
298  Coord c = new Coord(
299  Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
300  Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
301  Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));
302 
303  coords.Add(c);
304  }
305 
306  byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
307  for (int i = 0; i < triangleBytes.Length; i += 6)
308  {
309  ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
310  ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
311  ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
312  Face f = new Face(v1, v2, v3);
313  faces.Add(f);
314  }
315  }
316 
325  private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, float lod, bool convex)
326  {
327 // m_log.DebugFormat(
328 // "[MESH]: Creating physics proxy for {0}, shape {1}",
329 // primName, (OpenMetaverse.SculptType)primShape.SculptType);
330 
331  List<Coord> coords;
332  List<Face> faces;
333 
334  if (primShape.SculptEntry)
335  {
336  if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh)
337  {
338  if (!useMeshiesPhysicsMesh)
339  return null;
340 
341  if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, out coords, out faces, convex))
342  return null;
343  }
344  else
345  {
346  if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, lod, out coords, out faces))
347  return null;
348  }
349  }
350  else
351  {
352  if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, out coords, out faces))
353  return null;
354  }
355 
356 
357  int numCoords = coords.Count;
358  int numFaces = faces.Count;
359 
360  Mesh mesh = new Mesh();
361  // Add the corresponding triangles to the mesh
362  for (int i = 0; i < numFaces; i++)
363  {
364  Face f = faces[i];
365  mesh.Add(new Triangle(coords[f.v1].X, coords[f.v1].Y, coords[f.v1].Z,
366  coords[f.v2].X, coords[f.v2].Y, coords[f.v2].Z,
367  coords[f.v3].X, coords[f.v3].Y, coords[f.v3].Z));
368  }
369 
370  coords.Clear();
371  faces.Clear();
372 
373  if(mesh.numberVertices() < 3 || mesh.numberTriangles() < 1)
374  {
375  m_log.ErrorFormat("[MESH]: invalid degenerated mesh for prim " + primName + " ignored");
376  return null;
377  }
378 
379  primShape.SculptData = Utils.EmptyBytes;
380 
381  return mesh;
382  }
383 
393  private bool GenerateCoordsAndFacesFromPrimMeshData(
394  string primName, PrimitiveBaseShape primShape, out List<Coord> coords, out List<Face> faces, bool convex)
395  {
396 // m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
397 
398  bool usemesh = false;
399 
400  coords = new List<Coord>();
401  faces = new List<Face>();
402  OSD meshOsd = null;
403 
404  if (primShape.SculptData.Length <= 0)
405  {
406 // m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName);
407  return false;
408  }
409 
410  long start = 0;
411  using (MemoryStream data = new MemoryStream(primShape.SculptData))
412  {
413  try
414  {
415  OSD osd = OSDParser.DeserializeLLSDBinary(data);
416  if (osd is OSDMap)
417  meshOsd = (OSDMap)osd;
418  else
419  {
420  m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
421  return false;
422  }
423  }
424  catch (Exception e)
425  {
426  m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
427  }
428 
429  start = data.Position;
430  }
431 
432  if (meshOsd is OSDMap)
433  {
434  OSDMap physicsParms = null;
435  OSDMap map = (OSDMap)meshOsd;
436 
437  if (!convex)
438  {
439  if (map.ContainsKey("physics_shape"))
440  physicsParms = (OSDMap)map["physics_shape"]; // old asset format
441  else if (map.ContainsKey("physics_mesh"))
442  physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
443 
444  if (physicsParms != null)
445  usemesh = true;
446  }
447 
448  if(!usemesh && (map.ContainsKey("physics_convex")))
449  physicsParms = (OSDMap)map["physics_convex"];
450 
451 
452  if (physicsParms == null)
453  {
454  m_log.Warn("[MESH]: unknown mesh type");
455  return false;
456  }
457 
458  int physOffset = physicsParms["offset"].AsInteger() + (int)start;
459  int physSize = physicsParms["size"].AsInteger();
460 
461  if (physOffset < 0 || physSize == 0)
462  return false; // no mesh data in asset
463 
464  OSD decodedMeshOsd = new OSD();
465  byte[] meshBytes = new byte[physSize];
466  System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
467 
468  try
469  {
470  using (MemoryStream inMs = new MemoryStream(meshBytes))
471  {
472  using (MemoryStream outMs = new MemoryStream())
473  {
474  using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress))
475  {
476  byte[] readBuffer = new byte[2048];
477  inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header
478  int readLen = 0;
479 
480  while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
481  outMs.Write(readBuffer, 0, readLen);
482 
483  outMs.Flush();
484  outMs.Seek(0, SeekOrigin.Begin);
485 
486  byte[] decompressedBuf = outMs.GetBuffer();
487 
488  decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
489  }
490  }
491  }
492  }
493  catch (Exception e)
494  {
495  m_log.Error("[MESH]: exception decoding physical mesh prim " + primName +" : " + e.ToString());
496  return false;
497  }
498 
499  if (usemesh)
500  {
501  OSDArray decodedMeshOsdArray = null;
502 
503  // physics_shape is an array of OSDMaps, one for each submesh
504  if (decodedMeshOsd is OSDArray)
505  {
506 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
507 
508  decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
509  foreach (OSD subMeshOsd in decodedMeshOsdArray)
510  {
511  if (subMeshOsd is OSDMap)
512  AddSubMesh(subMeshOsd as OSDMap, coords, faces);
513  }
514  }
515  }
516  else
517  {
518  OSDMap cmap = (OSDMap)decodedMeshOsd;
519  if (cmap == null)
520  return false;
521 
522  byte[] data;
523 
524  List<float3> vs = new List<float3>();
525  PHullResult hullr = new PHullResult();
526  float3 f3;
527  Coord c;
528  Face f;
529  Vector3 range;
530  Vector3 min;
531 
532  const float invMaxU16 = 1.0f / 65535f;
533  int t1;
534  int t2;
535  int t3;
536  int i;
537  int nverts;
538  int nindexs;
539 
540  if (cmap.ContainsKey("Max"))
541  range = cmap["Max"].AsVector3();
542  else
543  range = new Vector3(0.5f, 0.5f, 0.5f);
544 
545  if (cmap.ContainsKey("Min"))
546  min = cmap["Min"].AsVector3();
547  else
548  min = new Vector3(-0.5f, -0.5f, -0.5f);
549 
550  range = range - min;
551  range *= invMaxU16;
552 
553  if (!convex && cmap.ContainsKey("HullList") && cmap.ContainsKey("Positions"))
554  {
555  List<int> hsizes = new List<int>();
556  int totalpoints = 0;
557  data = cmap["HullList"].AsBinary();
558  for (i = 0; i < data.Length; i++)
559  {
560  t1 = data[i];
561  if (t1 == 0)
562  t1 = 256;
563  totalpoints += t1;
564  hsizes.Add(t1);
565  }
566 
567  data = cmap["Positions"].AsBinary();
568  int ptr = 0;
569  int vertsoffset = 0;
570 
571  if (totalpoints == data.Length / 6) // 2 bytes per coord, 3 coords per point
572  {
573  foreach (int hullsize in hsizes)
574  {
575  for (i = 0; i < hullsize; i++ )
576  {
577  t1 = data[ptr++];
578  t1 += data[ptr++] << 8;
579  t2 = data[ptr++];
580  t2 += data[ptr++] << 8;
581  t3 = data[ptr++];
582  t3 += data[ptr++] << 8;
583 
584  f3 = new float3((t1 * range.X + min.X),
585  (t2 * range.Y + min.Y),
586  (t3 * range.Z + min.Z));
587  vs.Add(f3);
588  }
589 
590  if(hullsize <3)
591  {
592  vs.Clear();
593  continue;
594  }
595 
596  if (hullsize <5)
597  {
598  foreach (float3 point in vs)
599  {
600  c.X = point.x;
601  c.Y = point.y;
602  c.Z = point.z;
603  coords.Add(c);
604  }
605  f = new Face(vertsoffset, vertsoffset + 1, vertsoffset + 2);
606  faces.Add(f);
607 
608  if (hullsize == 4)
609  {
610  // not sure about orientation..
611  f = new Face(vertsoffset, vertsoffset + 2, vertsoffset + 3);
612  faces.Add(f);
613  f = new Face(vertsoffset, vertsoffset + 3, vertsoffset + 1);
614  faces.Add(f);
615  f = new Face(vertsoffset + 3, vertsoffset + 2, vertsoffset + 1);
616  faces.Add(f);
617  }
618  vertsoffset += vs.Count;
619  vs.Clear();
620  continue;
621  }
622 
623  if (!HullUtils.ComputeHull(vs, ref hullr, 0, 0.0f))
624  {
625  vs.Clear();
626  continue;
627  }
628 
629  nverts = hullr.Vertices.Count;
630  nindexs = hullr.Indices.Count;
631 
632  if (nindexs % 3 != 0)
633  {
634  vs.Clear();
635  continue;
636  }
637 
638  for (i = 0; i < nverts; i++)
639  {
640  c.X = hullr.Vertices[i].x;
641  c.Y = hullr.Vertices[i].y;
642  c.Z = hullr.Vertices[i].z;
643  coords.Add(c);
644  }
645 
646  for (i = 0; i < nindexs; i += 3)
647  {
648  t1 = hullr.Indices[i];
649  if (t1 > nverts)
650  break;
651  t2 = hullr.Indices[i + 1];
652  if (t2 > nverts)
653  break;
654  t3 = hullr.Indices[i + 2];
655  if (t3 > nverts)
656  break;
657  f = new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3);
658  faces.Add(f);
659  }
660  vertsoffset += nverts;
661  vs.Clear();
662  }
663  }
664  if (coords.Count > 0 && faces.Count > 0)
665  return true;
666  }
667 
668  vs.Clear();
669 
670  if (cmap.ContainsKey("BoundingVerts"))
671  {
672  data = cmap["BoundingVerts"].AsBinary();
673 
674  for (i = 0; i < data.Length; )
675  {
676  t1 = data[i++];
677  t1 += data[i++] << 8;
678  t2 = data[i++];
679  t2 += data[i++] << 8;
680  t3 = data[i++];
681  t3 += data[i++] << 8;
682 
683  f3 = new float3((t1 * range.X + min.X),
684  (t2 * range.Y + min.Y),
685  (t3 * range.Z + min.Z));
686  vs.Add(f3);
687  }
688 
689  if (vs.Count < 3)
690  {
691  vs.Clear();
692  return false;
693  }
694 
695  if (vs.Count < 5)
696  {
697  foreach (float3 point in vs)
698  {
699  c.X = point.x;
700  c.Y = point.y;
701  c.Z = point.z;
702  coords.Add(c);
703  }
704  f = new Face(0, 1, 2);
705  faces.Add(f);
706 
707  if (vs.Count == 4)
708  {
709  f = new Face(0, 2, 3);
710  faces.Add(f);
711  f = new Face(0, 3, 1);
712  faces.Add(f);
713  f = new Face( 3, 2, 1);
714  faces.Add(f);
715  }
716  vs.Clear();
717  return true;
718  }
719 
720  if (!HullUtils.ComputeHull(vs, ref hullr, 0, 0.0f))
721  return false;
722 
723  nverts = hullr.Vertices.Count;
724  nindexs = hullr.Indices.Count;
725 
726  if (nindexs % 3 != 0)
727  return false;
728 
729  for (i = 0; i < nverts; i++)
730  {
731  c.X = hullr.Vertices[i].x;
732  c.Y = hullr.Vertices[i].y;
733  c.Z = hullr.Vertices[i].z;
734  coords.Add(c);
735  }
736  for (i = 0; i < nindexs; i += 3)
737  {
738  t1 = hullr.Indices[i];
739  if (t1 > nverts)
740  break;
741  t2 = hullr.Indices[i + 1];
742  if (t2 > nverts)
743  break;
744  t3 = hullr.Indices[i + 2];
745  if (t3 > nverts)
746  break;
747  f = new Face(t1, t2, t3);
748  faces.Add(f);
749  }
750 
751  if (coords.Count > 0 && faces.Count > 0)
752  return true;
753  }
754  else
755  return false;
756  }
757  }
758 
759  return true;
760  }
761 
772  private bool GenerateCoordsAndFacesFromPrimSculptData(
773  string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces)
774  {
775  coords = new List<Coord>();
776  faces = new List<Face>();
777  PrimMesher.SculptMesh sculptMesh;
778  Image idata = null;
779 
780  if (primShape.SculptData == null || primShape.SculptData.Length == 0)
781  return false;
782 
783  try
784  {
785  OpenMetaverse.Imaging.ManagedImage unusedData;
786  OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
787 
788  unusedData = null;
789 
790  if (idata == null)
791  {
792  // In some cases it seems that the decode can return a null bitmap without throwing
793  // an exception
794  m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
795  return false;
796  }
797  }
798  catch (DllNotFoundException)
799  {
800  m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!");
801  return false;
802  }
803  catch (IndexOutOfRangeException)
804  {
805  m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
806  return false;
807  }
808  catch (Exception ex)
809  {
810  m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
811  return false;
812  }
813 
815  // remove mirror and invert bits
816  OpenMetaverse.SculptType pbsSculptType = ((OpenMetaverse.SculptType)(primShape.SculptType & 0x3f));
817  switch (pbsSculptType)
818  {
819  case OpenMetaverse.SculptType.Cylinder:
820  sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
821  break;
822  case OpenMetaverse.SculptType.Plane:
823  sculptType = PrimMesher.SculptMesh.SculptType.plane;
824  break;
825  case OpenMetaverse.SculptType.Torus:
826  sculptType = PrimMesher.SculptMesh.SculptType.torus;
827  break;
828  case OpenMetaverse.SculptType.Sphere:
829  sculptType = PrimMesher.SculptMesh.SculptType.sphere;
830  break;
831  default:
832  sculptType = PrimMesher.SculptMesh.SculptType.plane;
833  break;
834  }
835 
836  bool mirror = ((primShape.SculptType & 128) != 0);
837  bool invert = ((primShape.SculptType & 64) != 0);
838 
839  sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, mirror, invert);
840 
841  idata.Dispose();
842 
843 // sculptMesh.DumpRaw(baseDir, primName, "primMesh");
844 
845  coords = sculptMesh.coords;
846  faces = sculptMesh.faces;
847 
848  return true;
849  }
850 
860  private bool GenerateCoordsAndFacesFromPrimShapeData(
861  string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces)
862  {
863  PrimMesh primMesh;
864  coords = new List<Coord>();
865  faces = new List<Face>();
866 
867  float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
868  float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
869  float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
870  float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
871  float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
872  float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
873 
874  float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
875  float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
876 
877  if (profileBegin < 0.0f)
878  profileBegin = 0.0f;
879 
880  if (profileEnd < 0.02f)
881  profileEnd = 0.02f;
882  else if (profileEnd > 1.0f)
883  profileEnd = 1.0f;
884 
885  if (profileBegin >= profileEnd)
886  profileBegin = profileEnd - 0.02f;
887 
888  float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
889  if (profileHollow > 0.95f)
890  profileHollow = 0.95f;
891 
892  int sides = 4;
893  LevelOfDetail iLOD = (LevelOfDetail)lod;
894  byte profshape = (byte)(primShape.ProfileCurve & 0x07);
895 
896  if (profshape == (byte)ProfileShape.EquilateralTriangle
897  || profshape == (byte)ProfileShape.IsometricTriangle
898  || profshape == (byte)ProfileShape.RightTriangle)
899  sides = 3;
900  else if (profshape == (byte)ProfileShape.Circle)
901  {
902  switch (iLOD)
903  {
904  case LevelOfDetail.High: sides = 24; break;
905  case LevelOfDetail.Medium: sides = 12; break;
906  case LevelOfDetail.Low: sides = 6; break;
907  case LevelOfDetail.VeryLow: sides = 3; break;
908  default: sides = 24; break;
909  }
910  }
911  else if (profshape == (byte)ProfileShape.HalfCircle)
912  { // half circle, prim is a sphere
913  switch (iLOD)
914  {
915  case LevelOfDetail.High: sides = 24; break;
916  case LevelOfDetail.Medium: sides = 12; break;
917  case LevelOfDetail.Low: sides = 6; break;
918  case LevelOfDetail.VeryLow: sides = 3; break;
919  default: sides = 24; break;
920  }
921 
922  profileBegin = 0.5f * profileBegin + 0.5f;
923  profileEnd = 0.5f * profileEnd + 0.5f;
924  }
925 
926  int hollowSides = sides;
927  if (primShape.HollowShape == HollowShape.Circle)
928  {
929  switch (iLOD)
930  {
931  case LevelOfDetail.High: hollowSides = 24; break;
932  case LevelOfDetail.Medium: hollowSides = 12; break;
933  case LevelOfDetail.Low: hollowSides = 6; break;
934  case LevelOfDetail.VeryLow: hollowSides = 3; break;
935  default: hollowSides = 24; break;
936  }
937  }
938  else if (primShape.HollowShape == HollowShape.Square)
939  hollowSides = 4;
940  else if (primShape.HollowShape == HollowShape.Triangle)
941  {
942  if (profshape == (byte)ProfileShape.HalfCircle)
943  hollowSides = 6;
944  else
945  hollowSides = 3;
946  }
947 
948  primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
949 
950  if (primMesh.errorMessage != null)
951  if (primMesh.errorMessage.Length > 0)
952  m_log.Error("[ERROR] " + primMesh.errorMessage);
953 
954  primMesh.topShearX = pathShearX;
955  primMesh.topShearY = pathShearY;
956  primMesh.pathCutBegin = pathBegin;
957  primMesh.pathCutEnd = pathEnd;
958 
959  if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
960  {
961  primMesh.twistBegin = (primShape.PathTwistBegin * 18) / 10;
962  primMesh.twistEnd = (primShape.PathTwist * 18) / 10;
963  primMesh.taperX = pathScaleX;
964  primMesh.taperY = pathScaleY;
965 
966 #if SPAM
967  m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
968 #endif
969  try
970  {
971  primMesh.ExtrudeLinear();
972  }
973  catch (Exception ex)
974  {
975  ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
976  return false;
977  }
978  }
979  else
980  {
981  primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
982  primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
983  primMesh.radius = 0.01f * primShape.PathRadiusOffset;
984  primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
985  primMesh.skew = 0.01f * primShape.PathSkew;
986  primMesh.twistBegin = (primShape.PathTwistBegin * 36) / 10;
987  primMesh.twistEnd = (primShape.PathTwist * 36) / 10;
988  primMesh.taperX = primShape.PathTaperX * 0.01f;
989  primMesh.taperY = primShape.PathTaperY * 0.01f;
990 
991  if(profshape == (byte)ProfileShape.HalfCircle)
992  {
993  if(primMesh.holeSizeY < 0.01f)
994  primMesh.holeSizeY = 0.01f;
995  else if(primMesh.holeSizeY > 1.0f)
996  primMesh.holeSizeY = 1.0f;
997  }
998 
999 #if SPAM
1000  m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
1001 #endif
1002  try
1003  {
1004  primMesh.ExtrudeCircular();
1005  }
1006  catch (Exception ex)
1007  {
1008  ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
1009  return false;
1010  }
1011  }
1012 
1013 // primMesh.DumpRaw(baseDir, primName, "primMesh");
1014 
1015  coords = primMesh.coords;
1016  faces = primMesh.faces;
1017 
1018  return true;
1019  }
1020 
1021  public AMeshKey GetMeshUniqueKey(PrimitiveBaseShape primShape, Vector3 size, byte lod, bool convex)
1022  {
1023  AMeshKey key = new AMeshKey();
1024  Byte[] someBytes;
1025 
1026  key.hashB = 5181;
1027  key.hashC = 5181;
1028  ulong hash = 5381;
1029 
1030  if (primShape.SculptEntry)
1031  {
1032  key.uuid = primShape.SculptTexture;
1033  key.hashC = mdjb2(key.hashC, primShape.SculptType);
1034  key.hashC = mdjb2(key.hashC, primShape.PCode);
1035  }
1036  else
1037  {
1038  hash = mdjb2(hash, primShape.PathCurve);
1039  hash = mdjb2(hash, (byte)primShape.HollowShape);
1040  hash = mdjb2(hash, (byte)primShape.ProfileShape);
1041  hash = mdjb2(hash, primShape.PathBegin);
1042  hash = mdjb2(hash, primShape.PathEnd);
1043  hash = mdjb2(hash, primShape.PathScaleX);
1044  hash = mdjb2(hash, primShape.PathScaleY);
1045  hash = mdjb2(hash, primShape.PathShearX);
1046  key.hashA = hash;
1047  hash = key.hashB;
1048  hash = mdjb2(hash, primShape.PathShearY);
1049  hash = mdjb2(hash, (byte)primShape.PathTwist);
1050  hash = mdjb2(hash, (byte)primShape.PathTwistBegin);
1051  hash = mdjb2(hash, (byte)primShape.PathRadiusOffset);
1052  hash = mdjb2(hash, (byte)primShape.PathTaperX);
1053  hash = mdjb2(hash, (byte)primShape.PathTaperY);
1054  hash = mdjb2(hash, primShape.PathRevolutions);
1055  hash = mdjb2(hash, (byte)primShape.PathSkew);
1056  hash = mdjb2(hash, primShape.ProfileBegin);
1057  hash = mdjb2(hash, primShape.ProfileEnd);
1058  hash = mdjb2(hash, primShape.ProfileHollow);
1059  hash = mdjb2(hash, primShape.PCode);
1060  key.hashB = hash;
1061  }
1062 
1063  hash = key.hashC;
1064 
1065  hash = mdjb2(hash, lod);
1066 
1067  if (size == m_MeshUnitSize)
1068  {
1069  hash = hash << 8;
1070  hash |= 8;
1071  }
1072  else
1073  {
1074  someBytes = size.GetBytes();
1075  for (int i = 0; i < someBytes.Length; i++)
1076  hash = mdjb2(hash, someBytes[i]);
1077  hash = hash << 8;
1078  }
1079 
1080  if (convex)
1081  hash |= 4;
1082 
1083  if (primShape.SculptEntry)
1084  {
1085  hash |= 1;
1086  if (primShape.SculptType == (byte)SculptType.Mesh)
1087  hash |= 2;
1088  }
1089 
1090  key.hashC = hash;
1091 
1092  return key;
1093  }
1094 
1095  private ulong mdjb2(ulong hash, byte c)
1096  {
1097  return ((hash << 5) + hash) + (ulong)c;
1098  }
1099 
1100  private ulong mdjb2(ulong hash, ushort c)
1101  {
1102  hash = ((hash << 5) + hash) + (ulong)((byte)c);
1103  return ((hash << 5) + hash) + (ulong)(c >> 8);
1104  }
1105 
1106  public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
1107  {
1108  return CreateMesh(primName, primShape, size, lod, false,false,false);
1109  }
1110 
1111  public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
1112  {
1113  return CreateMesh(primName, primShape, size, lod, false,false,false);
1114  }
1115 
1116  public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
1117  {
1118  return CreateMesh(primName, primShape, size, lod, false, false, false);
1119  }
1120 
1121  public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
1122  {
1123  Mesh mesh = null;
1124 
1125  if (size.X < 0.01f) size.X = 0.01f;
1126  if (size.Y < 0.01f) size.Y = 0.01f;
1127  if (size.Z < 0.01f) size.Z = 0.01f;
1128 
1129  AMeshKey key = GetMeshUniqueKey(primShape, size, (byte)lod, convex);
1130  lock (m_uniqueMeshes)
1131  {
1132  m_uniqueMeshes.TryGetValue(key, out mesh);
1133 
1134  if (mesh != null)
1135  {
1136  mesh.RefCount++;
1137  return mesh;
1138  }
1139 
1140  // try to find a identical mesh on meshs recently released
1141  lock (m_uniqueReleasedMeshes)
1142  {
1143  m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
1144  if (mesh != null)
1145  {
1146  m_uniqueReleasedMeshes.Remove(key);
1147  try
1148  {
1149  m_uniqueMeshes.Add(key, mesh);
1150  }
1151  catch { }
1152  mesh.RefCount = 1;
1153  return mesh;
1154  }
1155  }
1156  }
1157  return null;
1158  }
1159 
1160  private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f);
1161 
1162  public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde)
1163  {
1164 #if SPAM
1165  m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
1166 #endif
1167 
1168  Mesh mesh = null;
1169 
1170  if (size.X < 0.01f) size.X = 0.01f;
1171  if (size.Y < 0.01f) size.Y = 0.01f;
1172  if (size.Z < 0.01f) size.Z = 0.01f;
1173 
1174  // try to find a identical mesh on meshs in use
1175 
1176  AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex);
1177 
1178  lock (m_uniqueMeshes)
1179  {
1180  m_uniqueMeshes.TryGetValue(key, out mesh);
1181 
1182  if (mesh != null)
1183  {
1184  mesh.RefCount++;
1185  return mesh;
1186  }
1187 
1188  // try to find a identical mesh on meshs recently released
1189  lock (m_uniqueReleasedMeshes)
1190  {
1191  m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
1192  if (mesh != null)
1193  {
1194  m_uniqueReleasedMeshes.Remove(key);
1195  try
1196  {
1197  m_uniqueMeshes.Add(key, mesh);
1198  }
1199  catch { }
1200  mesh.RefCount = 1;
1201  return mesh;
1202  }
1203  }
1204  }
1205 
1206  Mesh UnitMesh = null;
1207  AMeshKey unitKey = GetMeshUniqueKey(primShape, m_MeshUnitSize, (byte)lod, convex);
1208 
1209  lock (m_uniqueReleasedMeshes)
1210  {
1211  m_uniqueReleasedMeshes.TryGetValue(unitKey, out UnitMesh);
1212  if (UnitMesh != null)
1213  {
1214  UnitMesh.RefCount = 1;
1215  }
1216  }
1217 
1218  if (UnitMesh == null && primShape.SculptEntry && doMeshFileCache)
1219  UnitMesh = GetFromFileCache(unitKey);
1220 
1221  if (UnitMesh == null)
1222  {
1223  UnitMesh = CreateMeshFromPrimMesher(primName, primShape, lod, convex);
1224 
1225  if (UnitMesh == null)
1226  return null;
1227 
1228  UnitMesh.DumpRaw(baseDir, unitKey.ToString(), "Z");
1229 
1230  if (forOde)
1231  {
1232  // force pinned mem allocation
1233  UnitMesh.PrepForOde();
1234  }
1235  else
1236  UnitMesh.TrimExcess();
1237 
1238  UnitMesh.Key = unitKey;
1239  UnitMesh.RefCount = 1;
1240 
1241  if (doMeshFileCache && primShape.SculptEntry)
1242  StoreToFileCache(unitKey, UnitMesh);
1243 
1244  lock (m_uniqueReleasedMeshes)
1245  {
1246  try
1247  {
1248  m_uniqueReleasedMeshes.Add(unitKey, UnitMesh);
1249  }
1250  catch { }
1251  }
1252  }
1253 
1254  mesh = UnitMesh.Scale(size);
1255  mesh.Key = key;
1256  mesh.RefCount = 1;
1257  lock (m_uniqueMeshes)
1258  {
1259  try
1260  {
1261  m_uniqueMeshes.Add(key, mesh);
1262  }
1263  catch { }
1264  }
1265 
1266  return mesh;
1267  }
1268 
1269  public void ReleaseMesh(IMesh imesh)
1270  {
1271  if (imesh == null)
1272  return;
1273 
1274  Mesh mesh = (Mesh)imesh;
1275 
1276  lock (m_uniqueMeshes)
1277  {
1278  int curRefCount = mesh.RefCount;
1279  curRefCount--;
1280 
1281  if (curRefCount > 0)
1282  {
1283  mesh.RefCount = curRefCount;
1284  return;
1285  }
1286 
1287  mesh.RefCount = 0;
1288  m_uniqueMeshes.Remove(mesh.Key);
1289  lock (m_uniqueReleasedMeshes)
1290  {
1291  try
1292  {
1293  m_uniqueReleasedMeshes.Add(mesh.Key, mesh);
1294  }
1295  catch { }
1296  }
1297  }
1298  }
1299 
1300  public void ExpireReleaseMeshs()
1301  {
1302  if (m_uniqueReleasedMeshes.Count == 0)
1303  return;
1304 
1305  List<Mesh> meshstodelete = new List<Mesh>();
1306  int refcntr;
1307 
1308  lock (m_uniqueReleasedMeshes)
1309  {
1310  foreach (Mesh m in m_uniqueReleasedMeshes.Values)
1311  {
1312  refcntr = m.RefCount;
1313  refcntr--;
1314  if (refcntr > -6)
1315  m.RefCount = refcntr;
1316  else
1317  meshstodelete.Add(m);
1318  }
1319 
1320  foreach (Mesh m in meshstodelete)
1321  {
1322  m_uniqueReleasedMeshes.Remove(m.Key);
1323  m.releaseBuildingMeshData();
1324  m.releasePinned();
1325  }
1326  }
1327  }
1328 
1329  public void FileNames(AMeshKey key, out string dir,out string fullFileName)
1330  {
1331  string id = key.ToString();
1332  string init = id.Substring(0, 1);
1333  dir = System.IO.Path.Combine(cachePath, init);
1334  fullFileName = System.IO.Path.Combine(dir, id);
1335  }
1336 
1337  public string FullFileName(AMeshKey key)
1338  {
1339  string id = key.ToString();
1340  string init = id.Substring(0,1);
1341  id = System.IO.Path.Combine(init, id);
1342  id = System.IO.Path.Combine(cachePath, id);
1343  return id;
1344  }
1345 
1346  private Mesh GetFromFileCache(AMeshKey key)
1347  {
1348  Mesh mesh = null;
1349  string filename = FullFileName(key);
1350  bool ok = true;
1351 
1352  lock (diskLock)
1353  {
1354  if (File.Exists(filename))
1355  {
1356  FileStream stream = null;
1357  try
1358  {
1359  stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
1360  BinaryFormatter bformatter = new BinaryFormatter();
1361 
1362  mesh = Mesh.FromStream(stream, key);
1363 
1364  }
1365  catch (Exception e)
1366  {
1367  ok = false;
1368  m_log.ErrorFormat(
1369  "[MESH CACHE]: Failed to get file {0}. Exception {1} {2}",
1370  filename, e.Message, e.StackTrace);
1371  }
1372 
1373  if (stream != null)
1374  stream.Close();
1375 
1376  if (mesh == null || !ok)
1377  File.Delete(filename);
1378  else
1379  File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
1380  }
1381  }
1382 
1383  return mesh;
1384  }
1385 
1386  private void StoreToFileCache(AMeshKey key, Mesh mesh)
1387  {
1388  Stream stream = null;
1389  bool ok = false;
1390 
1391  // Make sure the target cache directory exists
1392  string dir = String.Empty;
1393  string filename = String.Empty;
1394 
1395  FileNames(key, out dir, out filename);
1396 
1397  lock (diskLock)
1398  {
1399  try
1400  {
1401  if (!Directory.Exists(dir))
1402  {
1403  Directory.CreateDirectory(dir);
1404  }
1405 
1406  stream = File.Open(filename, FileMode.Create);
1407  ok = mesh.ToStream(stream);
1408  }
1409  catch (IOException e)
1410  {
1411  m_log.ErrorFormat(
1412  "[MESH CACHE]: Failed to write file {0}. Exception {1} {2}.",
1413  filename, e.Message, e.StackTrace);
1414  ok = false;
1415  }
1416 
1417  if (stream != null)
1418  stream.Close();
1419 
1420  if (File.Exists(filename))
1421  {
1422  if (ok)
1423  File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
1424  else
1425  File.Delete(filename);
1426  }
1427  }
1428  }
1429 
1430  public void ExpireFileCache()
1431  {
1432  if (!doCacheExpire)
1433  return;
1434 
1435  string controlfile = System.IO.Path.Combine(cachePath, "cntr");
1436 
1437  lock (diskLock)
1438  {
1439  try
1440  {
1441  if (File.Exists(controlfile))
1442  {
1443  int ndeleted = 0;
1444  int totalfiles = 0;
1445  int ndirs = 0;
1446  DateTime OlderTime = File.GetLastAccessTimeUtc(controlfile) - CacheExpire;
1447  File.SetLastAccessTimeUtc(controlfile, DateTime.UtcNow);
1448 
1449  foreach (string dir in Directory.GetDirectories(cachePath))
1450  {
1451  try
1452  {
1453  foreach (string file in Directory.GetFiles(dir))
1454  {
1455  try
1456  {
1457  if (File.GetLastAccessTimeUtc(file) < OlderTime)
1458  {
1459  File.Delete(file);
1460  ndeleted++;
1461  }
1462  }
1463  catch { }
1464  totalfiles++;
1465  }
1466  }
1467  catch { }
1468  ndirs++;
1469  }
1470 
1471  if (ndeleted == 0)
1472  m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, no expires",
1473  totalfiles,ndirs);
1474  else
1475  m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, expired {2} files accessed before {3}",
1476  totalfiles,ndirs, ndeleted, OlderTime.ToString());
1477  }
1478  else
1479  {
1480  m_log.Info("[MESH CACHE]: Expire delayed to next startup");
1481  FileStream fs = File.Create(controlfile,4096,FileOptions.WriteThrough);
1482  fs.Close();
1483  }
1484  }
1485  catch { }
1486  }
1487  }
1488  }
1489 }
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Definition: Meshmerizer.cs:143
OpenMetaverse.StructuredData.OSDArray OSDArray
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde)
OpenSim.Server.Handlers.Simulation.Utils Utils
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Definition: Meshmerizer.cs:147
OpenMetaverse.StructuredData.OSDMap OSDMap
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31
OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType SculptType
Definition: SOPObject.cs:39
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
OpenMetaverse.StructuredData.OSD OSD
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Definition: Meshmerizer.cs:163
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
Definition: Meshmerizer.cs:155
IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
Ionic.Zlib.CompressionMode CompressionMode
AMeshKey GetMeshUniqueKey(PrimitiveBaseShape primShape, Vector3 size, byte lod, bool convex)
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
Definition: Meshmerizer.cs:92
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
void FileNames(AMeshKey key, out string dir, out string fullFileName)