1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- //#define SPAM
- using System;
- using System.Collections.Generic;
- using OpenSim.Framework;
- using OpenSim.Region.Framework.Scenes;
- using OpenSim.Region.Framework.Interfaces;
- using OpenSim.Region.PhysicsModules.SharedBase;
- using OpenSim.Region.PhysicsModules.ConvexDecompositionDotNet;
- using OpenMetaverse;
- using OpenMetaverse.StructuredData;
- using System.Drawing;
- using System.Threading;
- using System.IO.Compression;
- using PrimMesher;
- using log4net;
- using Nini.Config;
- using System.Reflection;
- using System.IO;
- using Mono.Addins;
- namespace OpenSim.Region.PhysicsModule.ubODEMeshing
- {
- [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ubODEMeshmerizer")]
- public class ubMeshmerizer : IMesher, INonSharedRegionModule
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- // Setting baseDir to a path will enable the dumping of raw files
- // raw files can be imported by blender so a visual inspection of the results can be done
- const float floatPI = MathF.PI;
- private readonly static string cacheControlFilename = "cntr";
- private bool m_Enabled = false;
- public static object diskLock = new();
- public bool doMeshFileCache = true;
- public bool doCacheExpire = true;
- public string cachePath = "MeshCache";
- public TimeSpan CacheExpire;
- //private const string baseDir = "rawFiles";
- private const string baseDir = null; //"rawFiles";
- private bool useMeshiesPhysicsMesh = true;
- private bool doConvexPrims = true;
- private bool doConvexSculpts = true;
- private readonly Dictionary<AMeshKey, Mesh> m_uniqueMeshes = new();
- private readonly Dictionary<AMeshKey, Mesh> m_uniqueReleasedMeshes = new ();
- #region INonSharedRegionModule
- public string Name
- {
- get { return "ubODEMeshmerizer"; }
- }
- public Type ReplaceableInterface
- {
- get { return null; }
- }
- public void Initialise(IConfigSource config)
- {
- IConfig start_config = config.Configs["Startup"];
- string mesher = start_config.GetString("meshing", string.Empty);
- if (mesher == Name)
- {
- float fcache = 48.0f;
- // float fcache = 0.02f;
- IConfig mesh_config = config.Configs["Mesh"];
- if (mesh_config != null)
- {
- useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
- doConvexPrims = mesh_config.GetBoolean("ConvexPrims",doConvexPrims);
- doConvexSculpts = mesh_config.GetBoolean("ConvexSculpts",doConvexPrims);
- doMeshFileCache = mesh_config.GetBoolean("MeshFileCache", doMeshFileCache);
- cachePath = mesh_config.GetString("MeshFileCachePath", cachePath);
- fcache = mesh_config.GetFloat("MeshFileCacheExpireHours", fcache);
- doCacheExpire = mesh_config.GetBoolean("MeshFileCacheDoExpire", doCacheExpire);
- m_Enabled = true;
- }
- CacheExpire = TimeSpan.FromHours(fcache);
- if(String.IsNullOrEmpty(cachePath))
- doMeshFileCache = false;
- if(doMeshFileCache)
- {
- if(!checkCache())
- {
- doMeshFileCache = false;
- doCacheExpire = false;
- }
- }
- else
- doCacheExpire = false;
- }
- }
- public void Close()
- {
- }
- public void AddRegion(Scene scene)
- {
- if (!m_Enabled)
- return;
- scene.RegisterModuleInterface<IMesher>(this);
- }
- public void RemoveRegion(Scene scene)
- {
- if (!m_Enabled)
- return;
- scene.UnregisterModuleInterface<IMesher>(this);
- }
- public void RegionLoaded(Scene scene)
- {
- if (!m_Enabled)
- return;
- }
- #endregion
- private void ReportPrimError(string message, string primName, PrimMesh primMesh)
- {
- m_log.Error(message);
- m_log.Error("\nPrim Name: " + primName);
- m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
- }
- /// <summary>
- /// Add a submesh to an existing list of coords and faces.
- /// </summary>
- /// <param name="subMeshData"></param>
- /// <param name="size">Size of entire object</param>
- /// <param name="coords"></param>
- /// <param name="faces"></param>
- private unsafe void AddSubMesh(OSDMap subMeshData, List<Coord> coords, List<Face> faces)
- {
- // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
- // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
- // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
- // geometry for this submesh.
- if (subMeshData.ContainsKey("NoGeometry"))
- return;
- byte[] posBytes = subMeshData["Position"].AsBinary();
- if (posBytes == null || posBytes.Length == 0)
- return;
- byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
- if (triangleBytes == null || triangleBytes.Length == 0)
- return;
- const float invMaxU16 = 1.0f / 65535f;
- Vector3 posRange;
- Vector3 posMin;
- if(subMeshData.TryGetValue("PositionDomain", out OSD tmp))
- {
- posRange = ((OSDMap)tmp)["Max"].AsVector3();
- posMin = ((OSDMap)tmp)["Min"].AsVector3();
- posRange -= posMin;
- posRange *= invMaxU16;
- }
- else
- {
- posRange = new Vector3(invMaxU16, invMaxU16, invMaxU16);
- posMin = new Vector3(-0.5f, -0.5f, -0.5f);
- }
- int faceIndexOffset = coords.Count;
- fixed (byte* ptrstart = posBytes)
- {
- byte* end = ptrstart + posBytes.Length;
- byte* ptr = ptrstart;
- while (ptr < end)
- {
- ushort uX = Utils.BytesToUInt16(ptr);
- ptr += 2;
- ushort uY = Utils.BytesToUInt16(ptr);
- ptr += 2;
- ushort uZ = Utils.BytesToUInt16(ptr);
- ptr += 2;
- coords.Add(new Coord(
- uX * posRange.X + posMin.X,
- uY * posRange.Y + posMin.Y,
- uZ * posRange.Z + posMin.Z)
- );
- }
- }
- fixed (byte* ptrstart = triangleBytes)
- {
- byte* end = ptrstart + triangleBytes.Length;
- byte* ptr = ptrstart;
- while (ptr < end)
- {
- int v1 = Utils.BytesToUInt16(ptr) + faceIndexOffset;
- ptr += 2;
- int v2 = Utils.BytesToUInt16(ptr) + faceIndexOffset;
- ptr += 2;
- int v3 = Utils.BytesToUInt16(ptr) + faceIndexOffset;
- ptr += 2;
- Face f = new (v1, v2, v3);
- faces.Add(f);
- }
- }
- }
- /// <summary>
- /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
- /// </summary>
- /// <param name="primName"></param>
- /// <param name="primShape"></param>
- /// <param name="size"></param>
- /// <param name="lod"></param>
- /// <returns></returns>
- private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, float lod, bool convex)
- {
- // m_log.DebugFormat(
- // "[MESH]: Creating physics proxy for {0}, shape {1}",
- // primName, (OpenMetaverse.SculptType)primShape.SculptType);
- List<Coord> coords;
- List<Face> faces;
- bool needsConvexProcessing = convex;
- if (primShape.SculptEntry)
- {
- if (((SculptType)primShape.SculptType) == SculptType.Mesh)
- {
- if (!useMeshiesPhysicsMesh)
- return null;
- try
- {
- if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, out coords, out faces, convex))
- return null;
- needsConvexProcessing = false;
- }
- catch
- {
- m_log.ErrorFormat("[MESH]: fail to process mesh asset for prim {0}", primName);
- return null;
- }
- }
- else
- {
- try
- {
- if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, lod, out coords, out faces))
- return null;
- needsConvexProcessing &= doConvexSculpts;
- }
- catch
- {
- m_log.ErrorFormat("[MESH]: fail to process sculpt map for prim {0}", primName);
- return null;
- }
- }
- }
- else
- {
- try
- {
- if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, convex, out coords, out faces))
- return null;
- needsConvexProcessing &= doConvexPrims;
- }
- catch
- {
- m_log.ErrorFormat("[MESH]: fail to process shape parameters for prim {0}", primName);
- return null;
- }
- }
- int numCoords = coords.Count;
- int numFaces = faces.Count;
- if(numCoords < 3 || (!needsConvexProcessing && numFaces < 1))
- {
- m_log.ErrorFormat("[ubODEMesh]: invalid degenerated mesh for prim {0} ignored", primName);
- return null;
- }
- if(needsConvexProcessing)
- {
- if(CreateBoundingHull(coords, out List<Coord> convexcoords, out List<Face> convexfaces) && convexcoords != null && convexfaces != null)
- {
- coords.Clear();
- coords = convexcoords;
-
- faces.Clear();
- faces = convexfaces;
- numFaces = faces.Count;
- }
- else
- m_log.ErrorFormat("[ubMESH]: failed to create convex for {0} using normal mesh", primName);
- }
- Mesh mesh = new(true);
- // Add the corresponding triangles to the mesh
- for (int i = 0; i < numFaces; i++)
- {
- Face f = faces[i];
- mesh.Add(new Triangle(coords[f.v1].X, coords[f.v1].Y, coords[f.v1].Z,
- coords[f.v2].X, coords[f.v2].Y, coords[f.v2].Z,
- coords[f.v3].X, coords[f.v3].Y, coords[f.v3].Z));
- }
- coords.Clear();
- faces.Clear();
- if(mesh.numberVertices() < 3 || mesh.numberTriangles() < 1)
- {
- m_log.ErrorFormat("[ubODEMesh]: invalid degenerated mesh for prim {0} ignored", primName);
- return null;
- }
- primShape.SculptData = Utils.EmptyBytes;
- return mesh;
- }
- /// <summary>
- /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
- /// </summary>
- /// <param name="primName"></param>
- /// <param name="primShape"></param>
- /// <param name="size"></param>
- /// <param name="coords">Coords are added to this list by the method.</param>
- /// <param name="faces">Faces are added to this list by the method.</param>
- /// <returns>true if coords and faces were successfully generated, false if not</returns>
- private unsafe bool GenerateCoordsAndFacesFromPrimMeshData(
- string primName, PrimitiveBaseShape primShape, out List<Coord> coords, out List<Face> faces, bool convex)
- {
- // m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
- // for ubOde we have a diferent mesh use priority
- // priority is to use full mesh then decomposition
- // SL does the oposite
- bool usemesh = false;
- coords = new List<Coord>();
- faces = new List<Face>();
- if (primShape.SculptData == null || primShape.SculptData.Length <= 0)
- {
- // m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName);
- return false;
- }
- OSD osd;
- long start = 0;
- using (MemoryStream data = new(primShape.SculptData))
- {
- try
- {
- osd = OSDParser.DeserializeLLSDBinary(data);
- }
- catch (Exception e)
- {
- m_log.Error($"[MESH]: Error deserializing mesh asset header: {e.Message} in Prim '{primName}' asset {primShape.SculptTexture}");
- return false;
- }
- start = data.Position;
- }
- if (osd is not OSDMap map)
- {
- m_log.Warn($"[Mesh]: unable to cast mesh asset to OSDMap prim: {primName} asset {primShape.SculptTexture}");
- return false;
- }
- OSDMap physicsParms = null;
- if (!convex)
- {
- if (map.TryGetValue("physics_shape", out OSD pso))
- physicsParms = (OSDMap)pso; // old asset format
- else if (map.TryGetValue("physics_mesh", out OSD pm))
- physicsParms = (OSDMap)pm; // new asset format
- if (physicsParms != null)
- usemesh = true;
- }
- if(!usemesh && map.TryGetValue("physics_convex",out OSD pc))
- physicsParms = (OSDMap)pc;
- if (physicsParms == null)
- {
- //m_log.WarnFormat("[MESH]: unknown mesh type for prim {0}",primName);
- return false;
- }
- int physOffset = physicsParms["offset"].AsInteger() + (int)start;
- int physSize = physicsParms["size"].AsInteger();
- if (physOffset < 0 || physSize == 0)
- return false; // no mesh data in asset
- OSD decodedMeshOsd = new();
- try
- {
- using (MemoryStream outMs = new(4 * physSize))
- {
- using (MemoryStream inMs = new(primShape.SculptData, physOffset, physSize))
- {
- using (DeflateStream decompressionStream = new(inMs, CompressionMode.Decompress))
- {
- byte[] readBuffer = new byte[8192];
- inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header
- int readLen = 0;
- while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
- outMs.Write(readBuffer, 0, readLen);
- }
- }
- outMs.Seek(0, SeekOrigin.Begin);
- decodedMeshOsd = OSDParser.DeserializeLLSDBinary(outMs);
- }
- }
- catch (Exception e)
- {
- m_log.Error("[MESH]: exception decoding physical mesh prim " + primName +" : " + e.ToString());
- return false;
- }
- if (usemesh)
- {
- // physics_shape is an array of OSDMaps, one for each submesh
- if (decodedMeshOsd is OSDArray decodedMeshOsdArray)
- {
- //Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
- foreach (OSD subMeshOsd in decodedMeshOsdArray)
- {
- if (subMeshOsd is OSDMap subm)
- AddSubMesh(subm, coords, faces);
- }
- }
- return true;
- }
- else if(decodedMeshOsd is OSDMap cmap)
- {
- byte[] data;
- List<float3> vs = new();
- PHullResult hullr = new();
- float3 f3;
- Vector3 range;
- Vector3 min;
- const float invMaxU16 = 1.0f / 65535f;
- int t1;
- int t2;
- int t3;
- int i;
- int nverts;
- int nindexs;
- if (cmap.ContainsKey("Max"))
- range = cmap["Max"].AsVector3();
- else
- range = new Vector3(0.5f, 0.5f, 0.5f);
- if (cmap.ContainsKey("Min"))
- min = cmap["Min"].AsVector3();
- else
- min = new Vector3(-0.5f, -0.5f, -0.5f);
- range -= min;
- range *= invMaxU16;
- if(!convex)
- {
- // if mesh data not present and not convex then we need convex decomposition data
- if (cmap.ContainsKey("HullList") && cmap.ContainsKey("Positions"))
- {
- List<int> hsizes = new();
- int totalpoints = 0;
- data = cmap["HullList"].AsBinary();
- for (i = 0; i < data.Length; i++)
- {
- t1 = data[i];
- if (t1 == 0)
- t1 = 256;
- totalpoints += t1;
- hsizes.Add(t1);
- }
- data = cmap["Positions"].AsBinary();
- fixed(byte* ptrstart = data)
- {
- byte* ptr = ptrstart;
- int vertsoffset = 0;
- if (totalpoints == data.Length / 6) // 2 bytes per coord, 3 coords per point
- {
- foreach (int hullsize in hsizes)
- {
- if (hullsize < 4)
- {
- if (hullsize < 3)
- {
- ptr += 6 * hullsize;
- continue;
- }
- for (i = 0; i < hullsize; i++)
- {
- t1 = Utils.BytesToUInt16(ptr); ptr += 2;
- t2 = Utils.BytesToUInt16(ptr); ptr += 2;
- t3 = Utils.BytesToUInt16(ptr); ptr += 2;
- coords.Add(new Coord(
- t1 * range.X + min.X,
- t2 * range.Y + min.Y,
- t3 * range.Z + min.Z)
- );
-
- }
- faces.Add(new Face(vertsoffset, vertsoffset + 1, vertsoffset + 2));
- vertsoffset += hullsize;
- continue;
- }
- for (i = 0; i < hullsize; i++)
- {
- t1 = Utils.BytesToUInt16(ptr); ptr += 2;
- t2 = Utils.BytesToUInt16(ptr); ptr += 2;
- t3 = Utils.BytesToUInt16(ptr); ptr += 2;
- f3 = new float3(t1 * range.X + min.X,
- t2 * range.Y + min.Y,
- t3 * range.Z + min.Z);
- vs.Add(f3);
- }
- if (!HullUtils.ComputeHull(vs, out List<int> indices))
- {
- vs.Clear();
- continue;
- }
- nverts = vs.Count;
- nindexs = indices.Count;
- if (nindexs % 3 != 0)
- {
- vs.Clear();
- continue;
- }
- for (i = 0; i < vs.Count; i++)
- coords.Add(new Coord(vs[i].x, vs[i].y, vs[i].z));
- for (i = 0; i < indices.Count; i += 3)
- {
- t1 = indices[i];
- if (t1 > nverts)
- break;
- t2 = indices[i + 1];
- if (t2 > nverts)
- break;
- t3 = indices[i + 2];
- if (t3 > nverts)
- break;
- faces.Add(new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3));
- }
- vertsoffset += nverts;
- vs.Clear();
- }
- }
- }
- if (coords.Count > 0 && faces.Count > 0)
- return true;
- }
- else
- {
- // if neither mesh or decomposition present, warn and use convex
- //m_log.WarnFormat("[MESH]: Data for PRIM shape type ( mesh or decomposition) not found for prim {0}",primName);
- }
- }
- vs.Clear();
- if (cmap.TryGetValue("BoundingVerts", out OSD odata))
- {
- data = odata.AsBinary();
- if (data.Length < 3 * 6)
- {
- vs.Clear();
- return false;
- }
- fixed (byte* ptrstart = data)
- {
- byte* end = ptrstart + data.Length;
- byte* ptr = ptrstart;
- while(ptr < end)
- {
- t1 = Utils.BytesToUInt16(ptr); ptr += 2;
- t2 = Utils.BytesToUInt16(ptr); ptr += 2;
- t3 = Utils.BytesToUInt16(ptr); ptr += 2;
- f3 = new float3((t1 * range.X + min.X),
- (t2 * range.Y + min.Y),
- (t3 * range.Z + min.Z));
- vs.Add(f3);
- }
- }
- nverts = vs.Count;
- if (nverts < 4)
- {
- for (i = 0; i < vs.Count; i++)
- coords.Add(new Coord(vs[i].x, vs[i].y, vs[i].z));
- faces.Add(new Face(0, 1, 2));
- vs.Clear();
- return true;
- }
- if (!HullUtils.ComputeHull(vs, out List<int> indices))
- return false;
- nindexs = indices.Count;
- if (nindexs % 3 != 0)
- return false;
- for (i = 0; i < vs.Count; i++)
- coords.Add(new Coord(vs[i].x, vs[i].y, vs[i].z));
- for (i = 0; i < indices.Count; i += 3)
- {
- t1 = indices[i];
- if (t1 > nverts)
- break;
- t2 = indices[i + 1];
- if (t2 > nverts)
- break;
- t3 = indices[i + 2];
- if (t3 > nverts)
- break;
- faces.Add(new Face(t1, t2, t3));
- }
- vs.Clear();
- if (coords.Count > 0 && faces.Count > 0)
- return true;
- }
- }
- return false;
- }
- /// <summary>
- /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
- /// </summary>
- /// <param name="primName"></param>
- /// <param name="primShape"></param>
- /// <param name="size"></param>
- /// <param name="lod"></param>
- /// <param name="coords">Coords are added to this list by the method.</param>
- /// <param name="faces">Faces are added to this list by the method.</param>
- /// <returns>true if coords and faces were successfully generated, false if not</returns>
- private static bool GenerateCoordsAndFacesFromPrimSculptData(
- string primName, PrimitiveBaseShape primShape, float lod, out List<Coord> coords, out List<Face> faces)
- {
- coords = new List<Coord>();
- faces = new List<Face>();
- PrimMesher.SculptMesh sculptMesh;
- Image idata;
- if (primShape.SculptData == null || primShape.SculptData.Length == 0)
- return false;
- try
- {
- OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out OpenMetaverse.Imaging.ManagedImage unusedData, out idata);
- unusedData = null;
- if (idata == null)
- {
- // In some cases it seems that the decode can return a null bitmap without throwing
- // an exception
- m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
- return false;
- }
- }
- catch (DllNotFoundException e)
- {
- m_log.Error($"[PHYSICS]: OpenJpeg problem: {e.Message}");
- return false;
- }
- catch (IndexOutOfRangeException)
- {
- m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
- return false;
- }
- catch (Exception ex)
- {
- m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
- return false;
- }
- // remove mirror and invert bits
- OpenMetaverse.SculptType pbsSculptType = ((OpenMetaverse.SculptType)(primShape.SculptType & 0x3f));
- var sculptType = pbsSculptType switch
- {
- OpenMetaverse.SculptType.Cylinder => PrimMesher.SculptMesh.SculptType.cylinder,
- OpenMetaverse.SculptType.Plane => PrimMesher.SculptMesh.SculptType.plane,
- OpenMetaverse.SculptType.Torus => PrimMesher.SculptMesh.SculptType.torus,
- OpenMetaverse.SculptType.Sphere => PrimMesher.SculptMesh.SculptType.sphere,
- _ => PrimMesher.SculptMesh.SculptType.plane,
- };
- bool mirror = ((primShape.SculptType & 128) != 0);
- bool invert = ((primShape.SculptType & 64) != 0);
- sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, mirror, invert);
- idata.Dispose();
- // sculptMesh.DumpRaw(baseDir, primName, "primMesh");
- coords = sculptMesh.coords;
- faces = sculptMesh.faces;
- return true;
- }
- /// <summary>
- /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim.
- /// </summary>
- /// <param name="primName"></param>
- /// <param name="primShape"></param>
- /// <param name="size"></param>
- /// <param name="coords">Coords are added to this list by the method.</param>
- /// <param name="faces">Faces are added to this list by the method.</param>
- /// <returns>true if coords and faces were successfully generated, false if not</returns>
- private bool GenerateCoordsAndFacesFromPrimShapeData(
- string primName, PrimitiveBaseShape primShape, float lod, bool convex,
- out List<Coord> coords, out List<Face> faces)
- {
- PrimMesh primMesh;
- coords = new List<Coord>();
- faces = new List<Face>();
- float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
- float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
- float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
- float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
- float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
- float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
- float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
- float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
- if (profileBegin < 0.0f)
- profileBegin = 0.0f;
- if (profileEnd < 0.02f)
- profileEnd = 0.02f;
- else if (profileEnd > 1.0f)
- profileEnd = 1.0f;
- if (profileBegin >= profileEnd)
- profileBegin = profileEnd - 0.02f;
- float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
- if(convex)
- profileHollow = 0.0f;
- else if (profileHollow > 0.95f)
- profileHollow = 0.95f;
- int sides = 4;
- LevelOfDetail iLOD = (LevelOfDetail)lod;
- byte profshape = (byte)(primShape.ProfileCurve & 0x07);
- if (profshape == (byte)ProfileShape.EquilateralTriangle
- || profshape == (byte)ProfileShape.IsometricTriangle
- || profshape == (byte)ProfileShape.RightTriangle)
- sides = 3;
- else if (profshape == (byte)ProfileShape.Circle)
- {
- sides = iLOD switch
- {
- LevelOfDetail.High => 24,
- LevelOfDetail.Medium => 12,
- LevelOfDetail.Low => 6,
- LevelOfDetail.VeryLow => 3,
- _ => 24,
- };
- }
- else if (profshape == (byte)ProfileShape.HalfCircle)
- { // half circle, prim is a sphere
- sides = iLOD switch
- {
- LevelOfDetail.High => 24,
- LevelOfDetail.Medium => 12,
- LevelOfDetail.Low => 6,
- LevelOfDetail.VeryLow => 3,
- _ => 24,
- };
- profileBegin = 0.5f * profileBegin + 0.5f;
- profileEnd = 0.5f * profileEnd + 0.5f;
- }
- int hollowSides = sides;
- if (primShape.HollowShape == HollowShape.Circle)
- {
- hollowSides = iLOD switch
- {
- LevelOfDetail.High => 24,
- LevelOfDetail.Medium => 12,
- LevelOfDetail.Low => 6,
- LevelOfDetail.VeryLow => 3,
- _ => 24,
- };
- }
- else if (primShape.HollowShape == HollowShape.Square)
- hollowSides = 4;
- else if (primShape.HollowShape == HollowShape.Triangle)
- {
- if (profshape == (byte)ProfileShape.HalfCircle)
- hollowSides = 6;
- else
- hollowSides = 3;
- }
- primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
- if (primMesh.errorMessage != null)
- if (primMesh.errorMessage.Length > 0)
- m_log.Error("[ERROR] " + primMesh.errorMessage);
- primMesh.topShearX = pathShearX;
- primMesh.topShearY = pathShearY;
- primMesh.pathCutBegin = pathBegin;
- primMesh.pathCutEnd = pathEnd;
-
- if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
- {
- primMesh.twistBegin = (float)(primShape.PathTwistBegin * (floatPI * 0.01f));
- primMesh.twistEnd = (float)(primShape.PathTwist * (floatPI * 0.01f));
- primMesh.taperX = pathScaleX;
- primMesh.taperY = pathScaleY;
- #if SPAM
- m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
- #endif
- try
- {
- primMesh.Extrude(PathType.Linear);
- }
- catch (Exception ex)
- {
- ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
- return false;
- }
- }
- else
- {
- primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
- primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
- primMesh.radius = 0.01f * primShape.PathRadiusOffset;
- primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
- primMesh.skew = 0.01f * primShape.PathSkew;
- primMesh.twistBegin = (float)(primShape.PathTwistBegin * (floatPI * 0.02f));
- primMesh.twistEnd = (float)(primShape.PathTwistBegin * (floatPI * 0.02f));
- primMesh.taperX = primShape.PathTaperX * 0.01f;
- primMesh.taperY = primShape.PathTaperY * 0.01f;
- if(profshape == (byte)ProfileShape.HalfCircle)
- {
- if(primMesh.holeSizeY < 0.01f)
- primMesh.holeSizeY = 0.01f;
- else if(primMesh.holeSizeY > 1.0f)
- primMesh.holeSizeY = 1.0f;
- }
- #if SPAM
- m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
- #endif
- try
- {
- primMesh.Extrude(PathType.Circular);
- }
- catch (Exception ex)
- {
- ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
- return false;
- }
- }
- // primMesh.DumpRaw(baseDir, primName, "primMesh");
- coords = primMesh.coords;
- faces = primMesh.faces;
- return true;
- }
- public static AMeshKey GetMeshUniqueKey(PrimitiveBaseShape primShape, Vector3 size, byte lod, bool convex)
- {
- AMeshKey key = new();
- Byte[] someBytes;
- key.hashB = 5181;
- key.hashC = 5181;
- ulong hash = 5381;
- if (primShape.SculptEntry)
- {
- key.uuid = primShape.SculptTexture;
- key.hashC = mdjb2(key.hashC, primShape.SculptType);
- key.hashC = mdjb2(key.hashC, primShape.PCode);
- }
- else
- {
- hash = mdjb2(hash, primShape.PathCurve);
- hash = mdjb2(hash, (byte)primShape.HollowShape);
- hash = mdjb2(hash, (byte)primShape.ProfileShape);
- hash = mdjb2(hash, primShape.PathBegin);
- hash = mdjb2(hash, primShape.PathEnd);
- hash = mdjb2(hash, primShape.PathScaleX);
- hash = mdjb2(hash, primShape.PathScaleY);
- hash = mdjb2(hash, primShape.PathShearX);
- key.hashA = hash;
- hash = key.hashB;
- hash = mdjb2(hash, primShape.PathShearY);
- hash = mdjb2(hash, (byte)primShape.PathTwist);
- hash = mdjb2(hash, (byte)primShape.PathTwistBegin);
- hash = mdjb2(hash, (byte)primShape.PathRadiusOffset);
- hash = mdjb2(hash, (byte)primShape.PathTaperX);
- hash = mdjb2(hash, (byte)primShape.PathTaperY);
- hash = mdjb2(hash, primShape.PathRevolutions);
- hash = mdjb2(hash, (byte)primShape.PathSkew);
- hash = mdjb2(hash, primShape.ProfileBegin);
- hash = mdjb2(hash, primShape.ProfileEnd);
- hash = mdjb2(hash, primShape.ProfileHollow);
- hash = mdjb2(hash, primShape.PCode);
- key.hashB = hash;
- }
- hash = key.hashC;
- hash = mdjb2(hash, lod);
- if (size == m_MeshUnitSize)
- {
- hash <<= 8;
- hash |= 8;
- }
- else
- {
- someBytes = size.GetBytes();
- for (int i = 0; i < someBytes.Length; i++)
- hash = mdjb2(hash, someBytes[i]);
- hash <<= 8;
- }
- if (convex)
- hash |= 4;
- if (primShape.SculptEntry)
- {
- hash |= 1;
- if (primShape.SculptType == (byte)SculptType.Mesh)
- hash |= 2;
- }
- key.hashC = hash;
- return key;
- }
- private static ulong mdjb2(ulong hash, byte c)
- {
- //return ((hash << 5) + hash) + (ulong)c;
- return 33 * hash + c;
- }
- private static ulong mdjb2(ulong hash, ushort c)
- {
- //hash = ((hash << 5) + hash) + (ulong)((byte)c);
- //return ((hash << 5) + hash) + (ulong)(c >> 8);
- return 33 * hash + c;
- }
- public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
- {
- return CreateMesh(primName, primShape, size, lod, false,false,false);
- }
- public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
- {
- return CreateMesh(primName, primShape, size, lod, false,false,false);
- }
- public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
- {
- return CreateMesh(primName, primShape, size, lod, false, false, false);
- }
- public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
- {
- Mesh mesh = null;
- if (size.X < 0.01f) size.X = 0.01f;
- if (size.Y < 0.01f) size.Y = 0.01f;
- if (size.Z < 0.01f) size.Z = 0.01f;
- AMeshKey key = GetMeshUniqueKey(primShape, size, (byte)lod, convex);
- lock (m_uniqueMeshes)
- {
- m_uniqueMeshes.TryGetValue(key, out mesh);
- if (mesh != null)
- {
- mesh.RefCount++;
- return mesh;
- }
- // try to find a identical mesh on meshs recently released
- lock (m_uniqueReleasedMeshes)
- {
- m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
- if (mesh != null)
- {
- m_uniqueReleasedMeshes.Remove(key);
- try
- {
- m_uniqueMeshes.Add(key, mesh);
- }
- catch { }
- mesh.RefCount = 1;
- return mesh;
- }
- }
- }
- return null;
- }
- private static Vector3 m_MeshUnitSize = new(1.0f, 1.0f, 1.0f);
- public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde)
- {
- #if SPAM
- m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
- #endif
- Mesh mesh = null;
- if (size.X < 0.01f) size.X = 0.01f;
- if (size.Y < 0.01f) size.Y = 0.01f;
- if (size.Z < 0.01f) size.Z = 0.01f;
- // try to find a identical mesh on meshs in use
- AMeshKey key = GetMeshUniqueKey(primShape,size,(byte)lod, convex);
- lock (m_uniqueMeshes)
- {
- m_uniqueMeshes.TryGetValue(key, out mesh);
- if (mesh != null)
- {
- mesh.RefCount++;
- return mesh;
- }
- // try to find a identical mesh on meshs recently released
- lock (m_uniqueReleasedMeshes)
- {
- m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
- if (mesh != null)
- {
- m_uniqueReleasedMeshes.Remove(key);
- try
- {
- m_uniqueMeshes.Add(key, mesh);
- }
- catch { }
- mesh.RefCount = 1;
- return mesh;
- }
- }
- }
- Mesh UnitMesh = null;
- AMeshKey unitKey = GetMeshUniqueKey(primShape, m_MeshUnitSize, (byte)lod, convex);
- lock (m_uniqueReleasedMeshes)
- {
- m_uniqueReleasedMeshes.TryGetValue(unitKey, out UnitMesh);
- if (UnitMesh != null)
- {
- UnitMesh.RefCount = 1;
- }
- }
- if (UnitMesh == null && primShape.SculptEntry && doMeshFileCache)
- UnitMesh = GetFromFileCache(unitKey);
- if (UnitMesh == null)
- {
- UnitMesh = CreateMeshFromPrimMesher(primName, primShape, lod, convex);
- if (UnitMesh == null)
- return null;
- UnitMesh.DumpRaw(baseDir, unitKey.ToString(), "Z");
- if (forOde)
- {
- // force pinned mem allocation
- UnitMesh.PrepForOde();
- }
- else
- UnitMesh.TrimExcess();
- UnitMesh.Key = unitKey;
- UnitMesh.RefCount = 1;
- if (doMeshFileCache && primShape.SculptEntry)
- StoreToFileCache(unitKey, UnitMesh);
- lock (m_uniqueReleasedMeshes)
- {
- try
- {
- m_uniqueReleasedMeshes.Add(unitKey, UnitMesh);
- }
- catch { }
- }
- }
- mesh = UnitMesh.Scale(size);
- mesh.Key = key;
- mesh.RefCount = 1;
- lock (m_uniqueMeshes)
- {
- try
- {
- m_uniqueMeshes.Add(key, mesh);
- }
- catch { }
- }
- return mesh;
- }
- public void ReleaseMesh(IMesh imesh)
- {
- if (imesh == null)
- return;
- Mesh mesh = (Mesh)imesh;
- lock (m_uniqueMeshes)
- {
- int curRefCount = mesh.RefCount;
- curRefCount--;
- if (curRefCount > 0)
- {
- mesh.RefCount = curRefCount;
- return;
- }
- mesh.RefCount = 0;
- m_uniqueMeshes.Remove(mesh.Key);
- lock (m_uniqueReleasedMeshes)
- {
- try
- {
- m_uniqueReleasedMeshes.Add(mesh.Key, mesh);
- }
- catch { }
- }
- }
- }
- public void ExpireReleaseMeshs()
- {
- if (m_uniqueReleasedMeshes.Count == 0)
- return;
- List<Mesh> meshstodelete = new();
- int refcntr;
- lock (m_uniqueReleasedMeshes)
- {
- foreach (Mesh m in m_uniqueReleasedMeshes.Values)
- {
- refcntr = m.RefCount;
- refcntr--;
- if (refcntr > -6)
- m.RefCount = refcntr;
- else
- meshstodelete.Add(m);
- }
- foreach (Mesh m in meshstodelete)
- {
- m_uniqueReleasedMeshes.Remove(m.Key);
- m.releaseBuildingMeshData();
- m.releasePinned();
- }
- }
- }
- public void FileNames(AMeshKey key, out string dir, out string fullFileName)
- {
- string id = key.ToString();
- string init = id[..1];
- dir = System.IO.Path.Combine(cachePath, init);
- fullFileName = System.IO.Path.Combine(dir, id);
- }
- public string FullFileName(AMeshKey key)
- {
- string id = key.ToString();
- string init = id[..1];
- id = System.IO.Path.Combine(init, id);
- id = System.IO.Path.Combine(cachePath, id);
- return id;
- }
- private Mesh GetFromFileCache(AMeshKey key)
- {
- Mesh mesh = null;
- string filename = FullFileName(key);
- bool ok = true;
- lock (diskLock)
- {
- if (File.Exists(filename))
- {
- try
- {
- using(FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- // BinaryFormatter bformatter = new BinaryFormatter();
- mesh = Mesh.FromStream(stream,key);
- }
- }
- catch (Exception e)
- {
- ok = false;
- m_log.ErrorFormat(
- "[MESH CACHE]: Failed to get file {0}. Exception {1} {2}",
- filename, e.Message, e.StackTrace);
- }
- try
- {
- if (mesh == null || !ok)
- File.Delete(filename);
- else
- File.SetLastAccessTimeUtc(filename, DateTime.UtcNow);
- }
- catch
- {
- }
- }
- }
- return mesh;
- }
- private void StoreToFileCache(AMeshKey key, Mesh mesh)
- {
- bool ok = false;
- // Make sure the target cache directory exists
- FileNames(key, out string dir, out string filename);
- lock (diskLock)
- {
- Stream stream = null;
- try
- {
- if (!Directory.Exists(dir))
- {
- Directory.CreateDirectory(dir);
- }
- stream = File.Open(filename, FileMode.Create);
- ok = mesh.ToStream(stream);
- }
- catch (IOException e)
- {
- m_log.ErrorFormat(
- "[MESH CACHE]: Failed to write file {0}. Exception {1} {2}.",
- filename, e.Message, e.StackTrace);
- ok = false;
- }
- finally
- {
- if(stream != null)
- stream.Dispose();
- }
- if (!ok && File.Exists(filename))
- {
- try
- {
- File.Delete(filename);
- }
- catch (IOException)
- {
- m_log.ErrorFormat(
- "[MESH CACHE]: Failed to delete file {0}",filename);
- }
- }
- }
- }
- private static DateTime lastExpireTime = DateTime.MinValue;
- public void ExpireFileCache()
- {
- if (!doCacheExpire)
- return;
- lock (diskLock)
- {
- try
- {
- DateTime now = DateTime.UtcNow;
- if(now.Subtract(lastExpireTime).TotalMinutes < 10.0)
- return;
- lastExpireTime = now;
- string controlfile = System.IO.Path.Combine(cachePath, cacheControlFilename);
- if (File.Exists(controlfile))
- {
- int ndeleted = 0;
- int totalfiles = 0;
- int ndirs = 0;
- DateTime OlderTime = File.GetLastAccessTimeUtc(controlfile) - CacheExpire;
- File.SetLastAccessTimeUtc(controlfile, now);
- foreach (string dir in Directory.GetDirectories(cachePath))
- {
- try
- {
- foreach (string file in Directory.GetFiles(dir))
- {
- try
- {
- if (File.GetLastAccessTimeUtc(file) < OlderTime)
- {
- File.Delete(file);
- ndeleted++;
- }
- }
- catch { }
- totalfiles++;
- }
- }
- catch { }
- ndirs++;
- }
- if (ndeleted == 0)
- m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, no expires",
- totalfiles,ndirs);
- else
- m_log.InfoFormat("[MESH CACHE]: {0} Files in {1} cache folders, expired {2} files accessed before {3}",
- totalfiles,ndirs, ndeleted, OlderTime.ToString());
- }
- else
- {
- m_log.Info("[MESH CACHE]: Expire delayed to next startup");
- FileStream fs = File.Create(controlfile,4096,FileOptions.WriteThrough);
- fs.Close();
- }
- }
- catch { }
- }
- }
- public bool checkCache()
- {
- string controlfile = System.IO.Path.Combine(cachePath, cacheControlFilename);
- lock (diskLock)
- {
- try
- {
- if (!Directory.Exists(cachePath))
- {
- Directory.CreateDirectory(cachePath);
- Thread.Sleep(100);
- FileStream fs = File.Create(controlfile, 4096, FileOptions.WriteThrough);
- fs.Close();
- return true;
- }
- }
- catch
- {
- doMeshFileCache = false;
- doCacheExpire = false;
- return false;
- }
- finally {}
- if (File.Exists(controlfile))
- return true;
- try
- {
- Directory.Delete(cachePath, true);
- while(Directory.Exists(cachePath))
- Thread.Sleep(100);
- }
- catch(Exception e)
- {
- m_log.Error("[MESH CACHE]: failed to delete old version of the cache: " + e.Message);
- doMeshFileCache = false;
- doCacheExpire = false;
- return false;
- }
- finally {}
- try
- {
- Directory.CreateDirectory(cachePath);
- while(!Directory.Exists(cachePath))
- Thread.Sleep(100);
- }
- catch(Exception e)
- {
- m_log.Error("[MESH CACHE]: failed to create new cache folder: " + e.Message);
- doMeshFileCache = false;
- doCacheExpire = false;
- return false;
- }
- finally {}
- try
- {
- FileStream fs = File.Create(controlfile, 4096, FileOptions.WriteThrough);
- fs.Close();
- }
- catch(Exception e)
- {
- m_log.Error("[MESH CACHE]: failed to create new control file: " + e.Message);
- doMeshFileCache = false;
- doCacheExpire = false;
- return false;
- }
- finally {}
-
- return true;
- }
- }
- public static bool CreateBoundingHull(List<Coord> inputVertices, out List<Coord> convexcoords, out List<Face> newfaces)
- {
- convexcoords = null;
- newfaces = null;
- HullDesc desc = new();
- HullResult result = new();
- int nInputVerts = inputVertices.Count;
- int i;
- List<float3> vs = new(nInputVerts);
- float3 f3;
- //useless copy
- for(i = 0 ; i < nInputVerts; i++)
- {
- f3 = new float3(inputVertices[i].X, inputVertices[i].Y, inputVertices[i].Z);
- vs.Add(f3);
- }
- desc.Vertices = vs;
- desc.Flags = HullFlag.QF_TRIANGLES;
- desc.MaxVertices = 256;
- try
- {
- HullError ret = HullUtils.CreateConvexHull(desc, ref result);
- if (ret != HullError.QE_OK)
- return false;
- int nverts = result.OutputVertices.Count;
- int nindx = result.Indices.Count;
- if(nverts < 3 || nindx< 3)
- return false;
- if(nindx % 3 != 0)
- return false;
- convexcoords = new List<Coord>(nverts);
- Coord c;
- vs = result.OutputVertices;
- for(i = 0 ; i < nverts; i++)
- {
- c = new Coord(vs[i].x, vs[i].y, vs[i].z);
- convexcoords.Add(c);
- }
- newfaces = new List<Face>(nindx / 3);
- List<int> indxs = result.Indices;
- int k, l, m;
- Face f;
- for(i = 0 ; i < nindx;)
- {
- k = indxs[i++];
- l = indxs[i++];
- m = indxs[i++];
- if(k > nInputVerts)
- continue;
- if(l > nInputVerts)
- continue;
- if(m > nInputVerts)
- continue;
- f = new Face(k,l,m);
- newfaces.Add(f);
- }
- }
- catch
- {
- return false;
- }
- return true;
- }
- }
- }
|