Meshmerizer.cs 60 KB

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