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;
37 using OpenMetaverse.StructuredData;
39 using System.Drawing.Imaging;
40 using System.IO.Compression;
44 using System.Reflection;
46 using System.Runtime.Serialization;
47 using System.Runtime.Serialization.Formatters.Binary;
51 namespace OpenSim.
Region.PhysicsModule.ubODEMeshing
53 [Extension(
Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"ubODEMeshmerizer")]
56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 private bool m_Enabled =
false;
63 public object diskLock =
new object();
65 public bool doMeshFileCache =
true;
67 public string cachePath =
"MeshCache";
69 public bool doCacheExpire =
true;
72 private const string baseDir = null;
74 private bool useMeshiesPhysicsMesh =
false;
76 private float minSizeForComplexMesh = 0.2f;
78 private Dictionary<AMeshKey, Mesh> m_uniqueMeshes =
new Dictionary<AMeshKey, Mesh>();
79 private Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes =
new Dictionary<AMeshKey, Mesh>();
81 #region INonSharedRegionModule
84 get {
return "ubODEMeshmerizer"; }
87 public Type ReplaceableInterface
94 IConfig start_config = config.Configs[
"Startup"];
96 string mesher = start_config.GetString(
"meshing", string.Empty);
102 IConfig mesh_config = config.Configs[
"Mesh"];
103 if (mesh_config != null)
105 useMeshiesPhysicsMesh = mesh_config.GetBoolean(
"UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
106 if (useMeshiesPhysicsMesh)
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);
115 doMeshFileCache =
false;
116 doCacheExpire =
false;
122 CacheExpire = TimeSpan.FromHours(fcache);
124 if(doMeshFileCache && cachePath !=
"")
130 if (!Directory.Exists(cachePath))
131 Directory.CreateDirectory(cachePath);
135 doMeshFileCache =
false;
136 doCacheExpire =
false;
152 scene.RegisterModuleInterface<
IMesher>(
this);
160 scene.UnregisterModuleInterface<
IMesher>(
this);
183 private static Mesh CreateSimpleBoxMesh(
float minX,
float maxX,
float minY,
float maxY,
float minZ,
float maxZ)
186 List<Vertex> vertices =
new List<Vertex>();
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));
194 box.Add(
new Triangle(vertices[0], vertices[1], vertices[2]));
195 box.Add(
new Triangle(vertices[0], vertices[2], vertices[3]));
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));
204 box.Add(
new Triangle(vertices[4], vertices[5], vertices[6]));
205 box.Add(
new Triangle(vertices[4], vertices[6], vertices[7]));
209 box.Add(
new Triangle(vertices[5], vertices[0], vertices[3]));
210 box.Add(
new Triangle(vertices[5], vertices[3], vertices[6]));
212 box.Add(
new Triangle(vertices[1], vertices[0], vertices[5]));
213 box.Add(
new Triangle(vertices[1], vertices[5], vertices[4]));
215 box.Add(
new Triangle(vertices[7], vertices[1], vertices[4]));
216 box.Add(
new Triangle(vertices[7], vertices[2], vertices[1]));
218 box.Add(
new Triangle(vertices[3], vertices[2], vertices[7]));
219 box.Add(
new Triangle(vertices[3], vertices[7], vertices[6]));
229 private static Mesh CreateBoundingBoxMesh(Mesh meshIn)
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;
238 foreach (Vector3 v
in meshIn.getVertexList())
240 if (v.X < minX) minX = v.X;
241 if (v.Y < minY) minY = v.Y;
242 if (v.Z < minZ) minZ = v.Z;
244 if (v.X > maxX) maxX = v.X;
245 if (v.Y > maxY) maxY = v.Y;
246 if (v.Z > maxZ) maxZ = v.Z;
249 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
252 private void ReportPrimError(
string message,
string primName,
PrimMesh primMesh)
254 m_log.Error(message);
255 m_log.Error(
"\nPrim Name: " + primName);
256 m_log.Error(
"****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
266 private void AddSubMesh(
OSDMap subMeshData, List<Coord> coords, List<Face> faces)
273 if (subMeshData.ContainsKey(
"NoGeometry") && ((OSDBoolean)subMeshData[
"NoGeometry"]))
276 OpenMetaverse.Vector3 posMax;
277 OpenMetaverse.Vector3 posMin;
278 if (subMeshData.ContainsKey(
"PositionDomain"))
280 posMax = ((
OSDMap)subMeshData[
"PositionDomain"])[
"Max"].AsVector3();
281 posMin = ((
OSDMap)subMeshData[
"PositionDomain"])[
"Min"].AsVector3();
285 posMax =
new Vector3(0.5f, 0.5f, 0.5f);
286 posMin =
new Vector3(-0.5f, -0.5f, -0.5f);
289 ushort faceIndexOffset = (ushort)coords.Count;
291 byte[] posBytes = subMeshData[
"Position"].AsBinary();
292 for (
int i = 0; i < posBytes.Length; i += 6)
294 ushort uX = Utils.BytesToUInt16(posBytes, i);
295 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
296 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
299 Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
300 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
301 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));
306 byte[] triangleBytes = subMeshData[
"TriangleList"].AsBinary();
307 for (
int i = 0; i < triangleBytes.Length; i += 6)
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);
325 private Mesh CreateMeshFromPrimMesher(
string primName,
PrimitiveBaseShape primShape,
float lod,
bool convex)
338 if (!useMeshiesPhysicsMesh)
341 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, out coords, out faces, convex))
346 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, lod, out coords, out faces))
352 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, out coords, out faces))
357 int numCoords = coords.Count;
358 int numFaces = faces.Count;
360 Mesh mesh =
new Mesh();
362 for (
int i = 0; i < numFaces; 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));
373 if(mesh.numberVertices() < 3 || mesh.numberTriangles() < 1)
375 m_log.ErrorFormat(
"[MESH]: invalid degenerated mesh for prim " + primName +
" ignored");
379 primShape.SculptData = Utils.EmptyBytes;
393 private bool GenerateCoordsAndFacesFromPrimMeshData(
394 string primName,
PrimitiveBaseShape primShape, out List<Coord> coords, out List<Face> faces,
bool convex)
398 bool usemesh =
false;
400 coords =
new List<Coord>();
401 faces =
new List<Face>();
411 using (MemoryStream data =
new MemoryStream(primShape.
SculptData))
415 OSD osd = OSDParser.DeserializeLLSDBinary(data);
420 m_log.Warn(
"[Mesh}: unable to cast mesh asset to OSDMap");
426 m_log.Error(
"[MESH]: Exception deserializing mesh asset header:" + e.ToString());
429 start = data.Position;
434 OSDMap physicsParms = null;
435 OSDMap map = (
OSDMap)meshOsd;
439 if (map.ContainsKey(
"physics_shape"))
440 physicsParms = (OSDMap)map[
"physics_shape"];
441 else if (map.ContainsKey(
"physics_mesh"))
442 physicsParms = (OSDMap)map[
"physics_mesh"];
444 if (physicsParms != null)
448 if(!usemesh && (map.ContainsKey(
"physics_convex")))
449 physicsParms = (
OSDMap)map[
"physics_convex"];
452 if (physicsParms == null)
454 m_log.Warn(
"[MESH]: unknown mesh type");
458 int physOffset = physicsParms[
"offset"].AsInteger() + (
int)start;
459 int physSize = physicsParms["size"].AsInteger();
461 if (physOffset < 0 || physSize == 0)
464 OSD decodedMeshOsd = new
OSD();
465 byte[] meshBytes = new byte[physSize];
466 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
470 using (MemoryStream inMs =
new MemoryStream(meshBytes))
472 using (MemoryStream outMs =
new MemoryStream())
474 using (DeflateStream decompressionStream =
new DeflateStream(inMs,
CompressionMode.Decompress))
476 byte[] readBuffer =
new byte[2048];
477 inMs.Read(readBuffer, 0, 2);
480 while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
481 outMs.Write(readBuffer, 0, readLen);
484 outMs.Seek(0, SeekOrigin.Begin);
486 byte[] decompressedBuf = outMs.GetBuffer();
488 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
495 m_log.Error(
"[MESH]: exception decoding physical mesh prim " + primName +
" : " + e.ToString());
501 OSDArray decodedMeshOsdArray = null;
508 decodedMeshOsdArray = (
OSDArray)decodedMeshOsd;
509 foreach (OSD subMeshOsd
in decodedMeshOsdArray)
511 if (subMeshOsd is OSDMap)
512 AddSubMesh(subMeshOsd as OSDMap, coords, faces);
518 OSDMap cmap = (
OSDMap)decodedMeshOsd;
524 List<float3> vs =
new List<float3>();
532 const float invMaxU16 = 1.0f / 65535f;
540 if (cmap.ContainsKey(
"Max"))
541 range = cmap[
"Max"].AsVector3();
543 range =
new Vector3(0.5f, 0.5f, 0.5f);
545 if (cmap.ContainsKey(
"Min"))
546 min = cmap[
"Min"].AsVector3();
548 min =
new Vector3(-0.5f, -0.5f, -0.5f);
553 if (!convex && cmap.ContainsKey(
"HullList") && cmap.ContainsKey(
"Positions"))
555 List<int> hsizes =
new List<int>();
557 data = cmap[
"HullList"].AsBinary();
558 for (i = 0; i < data.Length; i++)
567 data = cmap[
"Positions"].AsBinary();
571 if (totalpoints == data.Length / 6)
573 foreach (
int hullsize
in hsizes)
575 for (i = 0; i < hullsize; i++ )
578 t1 += data[ptr++] << 8;
580 t2 += data[ptr++] << 8;
582 t3 += data[ptr++] << 8;
584 f3 =
new float3((t1 * range.X + min.X),
585 (t2 * range.Y + min.Y),
586 (t3 * range.Z + min.Z));
598 foreach (
float3 point
in vs)
605 f =
new Face(vertsoffset, vertsoffset + 1, vertsoffset + 2);
611 f =
new Face(vertsoffset, vertsoffset + 2, vertsoffset + 3);
613 f =
new Face(vertsoffset, vertsoffset + 3, vertsoffset + 1);
615 f =
new Face(vertsoffset + 3, vertsoffset + 2, vertsoffset + 1);
618 vertsoffset += vs.Count;
623 if (!HullUtils.ComputeHull(vs, ref hullr, 0, 0.0f))
629 nverts = hullr.Vertices.Count;
630 nindexs = hullr.Indices.Count;
632 if (nindexs % 3 != 0)
638 for (i = 0; i < nverts; i++)
640 c.X = hullr.Vertices[i].x;
641 c.Y = hullr.Vertices[i].y;
642 c.Z = hullr.Vertices[i].z;
646 for (i = 0; i < nindexs; i += 3)
648 t1 = hullr.Indices[i];
651 t2 = hullr.Indices[i + 1];
654 t3 = hullr.Indices[i + 2];
657 f =
new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3);
660 vertsoffset += nverts;
664 if (coords.Count > 0 && faces.Count > 0)
670 if (cmap.ContainsKey(
"BoundingVerts"))
672 data = cmap[
"BoundingVerts"].AsBinary();
674 for (i = 0; i < data.Length; )
677 t1 += data[i++] << 8;
679 t2 += data[i++] << 8;
681 t3 += data[i++] << 8;
683 f3 =
new float3((t1 * range.X + min.X),
684 (t2 * range.Y + min.Y),
685 (t3 * range.Z + min.Z));
697 foreach (
float3 point
in vs)
704 f =
new Face(0, 1, 2);
709 f =
new Face(0, 2, 3);
711 f =
new Face(0, 3, 1);
713 f =
new Face( 3, 2, 1);
720 if (!HullUtils.ComputeHull(vs, ref hullr, 0, 0.0f))
723 nverts = hullr.Vertices.Count;
724 nindexs = hullr.Indices.Count;
726 if (nindexs % 3 != 0)
729 for (i = 0; i < nverts; i++)
731 c.X = hullr.Vertices[i].x;
732 c.Y = hullr.Vertices[i].y;
733 c.Z = hullr.Vertices[i].z;
736 for (i = 0; i < nindexs; i += 3)
738 t1 = hullr.Indices[i];
741 t2 = hullr.Indices[i + 1];
744 t3 = hullr.Indices[i + 2];
747 f =
new Face(t1, t2, t3);
751 if (coords.Count > 0 && faces.Count > 0)
772 private bool GenerateCoordsAndFacesFromPrimSculptData(
773 string primName,
PrimitiveBaseShape primShape,
float lod, out List<Coord> coords, out List<Face> faces)
775 coords =
new List<Coord>();
776 faces =
new List<Face>();
785 OpenMetaverse.Imaging.ManagedImage unusedData;
786 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
794 m_log.WarnFormat(
"[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
798 catch (DllNotFoundException)
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!");
803 catch (IndexOutOfRangeException)
805 m_log.Error(
"[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
810 m_log.Error(
"[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
817 switch (pbsSculptType)
819 case OpenMetaverse.SculptType.Cylinder:
820 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
822 case OpenMetaverse.SculptType.Plane:
823 sculptType = PrimMesher.SculptMesh.SculptType.plane;
825 case OpenMetaverse.SculptType.Torus:
826 sculptType = PrimMesher.SculptMesh.SculptType.torus;
828 case OpenMetaverse.SculptType.Sphere:
829 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
832 sculptType = PrimMesher.SculptMesh.SculptType.plane;
836 bool mirror = ((primShape.SculptType & 128) != 0);
837 bool invert = ((primShape.SculptType & 64) != 0);
845 coords = sculptMesh.coords;
846 faces = sculptMesh.faces;
860 private
bool GenerateCoordsAndFacesFromPrimShapeData(
864 coords =
new List<Coord>();
865 faces =
new List<Face>();
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;
874 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
875 float profileEnd = 1.0f - (
float)primShape.ProfileEnd * 2.0e-5f;
877 if (profileBegin < 0.0f)
880 if (profileEnd < 0.02f)
882 else if (profileEnd > 1.0f)
885 if (profileBegin >= profileEnd)
886 profileBegin = profileEnd - 0.02f;
888 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
889 if (profileHollow > 0.95f)
890 profileHollow = 0.95f;
894 byte profshape = (byte)(primShape.ProfileCurve & 0x07);
896 if (profshape == (byte)ProfileShape.EquilateralTriangle
898 || profshape == (byte)ProfileShape.RightTriangle)
900 else if (profshape == (byte)ProfileShape.Circle)
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;
911 else if (profshape == (byte)ProfileShape.HalfCircle)
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;
922 profileBegin = 0.5f * profileBegin + 0.5f;
923 profileEnd = 0.5f * profileEnd + 0.5f;
926 int hollowSides = sides;
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;
938 else if (primShape.HollowShape ==
HollowShape.Square)
940 else if (primShape.HollowShape ==
HollowShape.Triangle)
942 if (profshape == (byte)ProfileShape.HalfCircle)
948 primMesh =
new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
952 m_log.Error(
"[ERROR] " + primMesh.errorMessage);
954 primMesh.topShearX = pathShearX;
955 primMesh.topShearY = pathShearY;
956 primMesh.pathCutBegin = pathBegin;
957 primMesh.pathCutEnd = pathEnd;
959 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte)
Extrusion.Flexible)
961 primMesh.twistBegin = (primShape.PathTwistBegin * 18) / 10;
962 primMesh.twistEnd = (primShape.PathTwist * 18) / 10;
963 primMesh.taperX = pathScaleX;
964 primMesh.taperY = pathScaleY;
967 m_log.Debug(
"****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
971 primMesh.ExtrudeLinear();
975 ReportPrimError(
"Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
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;
991 if(profshape == (byte)ProfileShape.HalfCircle)
994 primMesh.holeSizeY = 0.01f;
996 primMesh.holeSizeY = 1.0f;
1000 m_log.Debug(
"****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
1004 primMesh.ExtrudeCircular();
1006 catch (Exception ex)
1008 ReportPrimError(
"Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
1015 coords = primMesh.coords;
1016 faces = primMesh.faces;
1032 key.uuid = primShape.SculptTexture;
1034 key.hashC = mdjb2(key.
hashC, primShape.
PCode);
1038 hash = mdjb2(hash, primShape.
PathCurve);
1041 hash = mdjb2(hash, primShape.
PathBegin);
1042 hash = mdjb2(hash, primShape.
PathEnd);
1049 hash = mdjb2(hash, (byte)primShape.
PathTwist);
1052 hash = mdjb2(hash, (byte)primShape.
PathTaperX);
1053 hash = mdjb2(hash, (byte)primShape.
PathTaperY);
1055 hash = mdjb2(hash, (byte)primShape.
PathSkew);
1059 hash = mdjb2(hash, primShape.
PCode);
1065 hash = mdjb2(hash, lod);
1067 if (size == m_MeshUnitSize)
1074 someBytes = size.GetBytes();
1075 for (
int i = 0; i < someBytes.Length; i++)
1076 hash = mdjb2(hash, someBytes[i]);
1086 if (primShape.
SculptType == (byte)SculptType.Mesh)
1095 private ulong mdjb2(ulong hash, byte c)
1097 return ((hash << 5) + hash) + (ulong)c;
1100 private ulong mdjb2(ulong hash, ushort c)
1102 hash = ((hash << 5) + hash) + (ulong)((byte)c);
1103 return ((hash << 5) + hash) + (ulong)(c >> 8);
1108 return CreateMesh(primName, primShape, size, lod,
false,
false,
false);
1113 return CreateMesh(primName, primShape, size, lod,
false,
false,
false);
1118 return CreateMesh(primName, primShape, size, lod,
false,
false,
false);
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;
1129 AMeshKey key = GetMeshUniqueKey(primShape, size, (byte)lod, convex);
1130 lock (m_uniqueMeshes)
1132 m_uniqueMeshes.TryGetValue(
key, out mesh);
1141 lock (m_uniqueReleasedMeshes)
1143 m_uniqueReleasedMeshes.TryGetValue(
key, out mesh);
1146 m_uniqueReleasedMeshes.Remove(
key);
1149 m_uniqueMeshes.Add(
key, mesh);
1160 private static Vector3 m_MeshUnitSize =
new Vector3(1.0f, 1.0f, 1.0f);
1165 m_log.DebugFormat(
"[MESH]: Creating mesh for {0}", primName);
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;
1176 AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex);
1178 lock (m_uniqueMeshes)
1180 m_uniqueMeshes.TryGetValue(
key, out mesh);
1189 lock (m_uniqueReleasedMeshes)
1191 m_uniqueReleasedMeshes.TryGetValue(
key, out mesh);
1194 m_uniqueReleasedMeshes.Remove(
key);
1197 m_uniqueMeshes.Add(
key, mesh);
1206 Mesh UnitMesh = null;
1207 AMeshKey unitKey = GetMeshUniqueKey(primShape, m_MeshUnitSize, (byte)lod, convex);
1209 lock (m_uniqueReleasedMeshes)
1211 m_uniqueReleasedMeshes.TryGetValue(unitKey, out UnitMesh);
1212 if (UnitMesh != null)
1214 UnitMesh.RefCount = 1;
1218 if (UnitMesh == null && primShape.
SculptEntry && doMeshFileCache)
1219 UnitMesh = GetFromFileCache(unitKey);
1221 if (UnitMesh == null)
1223 UnitMesh = CreateMeshFromPrimMesher(primName, primShape, lod, convex);
1225 if (UnitMesh == null)
1228 UnitMesh.DumpRaw(baseDir, unitKey.ToString(),
"Z");
1233 UnitMesh.PrepForOde();
1236 UnitMesh.TrimExcess();
1238 UnitMesh.Key = unitKey;
1239 UnitMesh.RefCount = 1;
1242 StoreToFileCache(unitKey, UnitMesh);
1244 lock (m_uniqueReleasedMeshes)
1248 m_uniqueReleasedMeshes.Add(unitKey, UnitMesh);
1254 mesh = UnitMesh.Scale(size);
1257 lock (m_uniqueMeshes)
1261 m_uniqueMeshes.Add(
key, mesh);
1276 lock (m_uniqueMeshes)
1278 int curRefCount = mesh.RefCount;
1281 if (curRefCount > 0)
1283 mesh.RefCount = curRefCount;
1288 m_uniqueMeshes.Remove(mesh.Key);
1289 lock (m_uniqueReleasedMeshes)
1293 m_uniqueReleasedMeshes.Add(mesh.Key, mesh);
1302 if (m_uniqueReleasedMeshes.Count == 0)
1305 List<Mesh> meshstodelete =
new List<Mesh>();
1308 lock (m_uniqueReleasedMeshes)
1310 foreach (
Mesh m
in m_uniqueReleasedMeshes.Values)
1312 refcntr = m.RefCount;
1315 m.RefCount = refcntr;
1317 meshstodelete.Add(m);
1320 foreach (
Mesh m
in meshstodelete)
1322 m_uniqueReleasedMeshes.Remove(m.Key);
1323 m.releaseBuildingMeshData();
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);
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);
1349 string filename = FullFileName(key);
1354 if (
File.Exists(filename))
1356 FileStream stream = null;
1359 stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
1360 BinaryFormatter bformatter =
new BinaryFormatter();
1362 mesh = Mesh.FromStream(stream,
key);
1369 "[MESH CACHE]: Failed to get file {0}. Exception {1} {2}",
1370 filename, e.Message, e.StackTrace);
1376 if (mesh == null || !ok)
1377 File.Delete(filename);
1379 File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
1386 private void StoreToFileCache(
AMeshKey key, Mesh mesh)
1388 Stream stream = null;
1392 string dir = String.Empty;
1393 string filename = String.Empty;
1395 FileNames(key, out dir, out filename);
1401 if (!Directory.Exists(dir))
1403 Directory.CreateDirectory(dir);
1406 stream = File.Open(filename, FileMode.Create);
1407 ok = mesh.ToStream(stream);
1409 catch (IOException e)
1412 "[MESH CACHE]: Failed to write file {0}. Exception {1} {2}.",
1413 filename, e.Message, e.StackTrace);
1420 if (
File.Exists(filename))
1423 File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
1425 File.Delete(filename);
1435 string controlfile = System.IO.Path.Combine(cachePath,
"cntr");
1441 if (
File.Exists(controlfile))
1446 DateTime OlderTime = File.GetLastAccessTimeUtc(controlfile) - CacheExpire;
1447 File.SetLastAccessTimeUtc(controlfile, DateTime.UtcNow);
1449 foreach (
string dir
in Directory.GetDirectories(cachePath))
1453 foreach (
string file
in Directory.GetFiles(dir))
1457 if (
File.GetLastAccessTimeUtc(file) < OlderTime)
1472 m_log.InfoFormat(
"[MESH CACHE]: {0} Files in {1} cache folders, no expires",
1475 m_log.InfoFormat(
"[MESH CACHE]: {0} Files in {1} cache folders, expired {2} files accessed before {3}",
1476 totalfiles,ndirs, ndeleted, OlderTime.ToString());
1480 m_log.Info(
"[MESH CACHE]: Expire delayed to next startup");
1481 FileStream fs = File.Create(controlfile,4096,FileOptions.WriteThrough);
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
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...
void ReleaseMesh(IMesh imesh)
OpenMetaverse.StructuredData.OSDMap OSDMap
string FullFileName(AMeshKey key)
void ExpireReleaseMeshs()
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
ProfileShape ProfileShape
OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType SculptType
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...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
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...
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
void FileNames(AMeshKey key, out string dir, out string fullFileName)