aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/Meshmerizer.cs')
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs249
1 files changed, 224 insertions, 25 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index d181b78..16d65eb 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -64,6 +64,7 @@ namespace OpenSim.Region.Physics.Meshing
64 public class Meshmerizer : IMesher 64 public class Meshmerizer : IMesher
65 { 65 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private static string LogHeader = "[MESH]";
67 68
68 // Setting baseDir to a path will enable the dumping of raw files 69 // Setting baseDir to a path will enable the dumping of raw files
69 // raw files can be imported by blender so a visual inspection of the results can be done 70 // raw files can be imported by blender so a visual inspection of the results can be done
@@ -72,6 +73,8 @@ namespace OpenSim.Region.Physics.Meshing
72#else 73#else
73 private const string baseDir = null; //"rawFiles"; 74 private const string baseDir = null; //"rawFiles";
74#endif 75#endif
76 // If 'true', lots of DEBUG logging of asset parsing details
77 private bool debugDetail = false;
75 78
76 private bool cacheSculptMaps = true; 79 private bool cacheSculptMaps = true;
77 private string decodedSculptMapPath = null; 80 private string decodedSculptMapPath = null;
@@ -79,6 +82,9 @@ namespace OpenSim.Region.Physics.Meshing
79 82
80 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh 83 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
81 84
85 private List<List<Vector3>> mConvexHulls = null;
86 private List<Vector3> mBoundingHull = null;
87
82 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); 88 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
83 89
84 public Meshmerizer(IConfigSource config) 90 public Meshmerizer(IConfigSource config)
@@ -88,8 +94,11 @@ namespace OpenSim.Region.Physics.Meshing
88 94
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); 95 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); 96 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
91 if(mesh_config != null) 97 if (mesh_config != null)
98 {
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); 99 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
100 debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail);
101 }
93 102
94 try 103 try
95 { 104 {
@@ -319,6 +328,9 @@ namespace OpenSim.Region.Physics.Meshing
319 faces = new List<Face>(); 328 faces = new List<Face>();
320 OSD meshOsd = null; 329 OSD meshOsd = null;
321 330
331 mConvexHulls = null;
332 mBoundingHull = null;
333
322 if (primShape.SculptData.Length <= 0) 334 if (primShape.SculptData.Length <= 0)
323 { 335 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this 336 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
@@ -355,9 +367,139 @@ namespace OpenSim.Region.Physics.Meshing
355 OSDMap physicsParms = null; 367 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd; 368 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape")) 369 if (map.ContainsKey("physics_shape"))
370 {
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format 371 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
372 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
373 }
359 else if (map.ContainsKey("physics_mesh")) 374 else if (map.ContainsKey("physics_mesh"))
375 {
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 376 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
377 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
378 }
379 else if (map.ContainsKey("medium_lod"))
380 {
381 physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
382 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
383 }
384 else if (map.ContainsKey("high_lod"))
385 {
386 physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
387 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
388 }
389
390 if (map.ContainsKey("physics_convex"))
391 { // pull this out also in case physics engine can use it
392 OSD convexBlockOsd = null;
393 try
394 {
395 OSDMap convexBlock = (OSDMap)map["physics_convex"];
396 {
397 int convexOffset = convexBlock["offset"].AsInteger() + (int)start;
398 int convexSize = convexBlock["size"].AsInteger();
399
400 byte[] convexBytes = new byte[convexSize];
401
402 System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize);
403
404 try
405 {
406 convexBlockOsd = DecompressOsd(convexBytes);
407 }
408 catch (Exception e)
409 {
410 m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e);
411 //return false;
412 }
413 }
414
415 if (convexBlockOsd != null && convexBlockOsd is OSDMap)
416 {
417 convexBlock = convexBlockOsd as OSDMap;
418
419 if (debugDetail)
420 {
421 string keys = LogHeader + " keys found in convexBlock: ";
422 foreach (KeyValuePair<string, OSD> kvp in convexBlock)
423 keys += "'" + kvp.Key + "' ";
424 m_log.Debug(keys);
425 }
426
427 Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f);
428 if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3();
429 Vector3 max = new Vector3(0.5f, 0.5f, 0.5f);
430 if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3();
431
432 List<Vector3> boundingHull = null;
433
434 if (convexBlock.ContainsKey("BoundingVerts"))
435 {
436 byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary();
437 boundingHull = new List<Vector3>();
438 for (int i = 0; i < boundingVertsBytes.Length; )
439 {
440 ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
441 ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
442 ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
443
444 Vector3 pos = new Vector3(
445 Utils.UInt16ToFloat(uX, min.X, max.X),
446 Utils.UInt16ToFloat(uY, min.Y, max.Y),
447 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
448 );
449
450 boundingHull.Add(pos);
451 }
452
453 mBoundingHull = boundingHull;
454 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count);
455 }
456
457 if (convexBlock.ContainsKey("HullList"))
458 {
459 byte[] hullList = convexBlock["HullList"].AsBinary();
460
461 byte[] posBytes = convexBlock["Positions"].AsBinary();
462
463 List<List<Vector3>> hulls = new List<List<Vector3>>();
464 int posNdx = 0;
465
466 foreach (byte cnt in hullList)
467 {
468 int count = cnt == 0 ? 256 : cnt;
469 List<Vector3> hull = new List<Vector3>();
470
471 for (int i = 0; i < count; i++)
472 {
473 ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
474 ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
475 ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
476
477 Vector3 pos = new Vector3(
478 Utils.UInt16ToFloat(uX, min.X, max.X),
479 Utils.UInt16ToFloat(uY, min.Y, max.Y),
480 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
481 );
482
483 hull.Add(pos);
484 }
485
486 hulls.Add(hull);
487 }
488
489 mConvexHulls = hulls;
490 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
491 }
492 else
493 {
494 if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
495 }
496 }
497 }
498 catch (Exception e)
499 {
500 m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
501 }
502 }
361 503
362 if (physicsParms == null) 504 if (physicsParms == null)
363 { 505 {
@@ -374,34 +516,14 @@ namespace OpenSim.Region.Physics.Meshing
374 OSD decodedMeshOsd = new OSD(); 516 OSD decodedMeshOsd = new OSD();
375 byte[] meshBytes = new byte[physSize]; 517 byte[] meshBytes = new byte[physSize];
376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); 518 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
377// byte[] decompressed = new byte[physSize * 5]; 519 // byte[] decompressed = new byte[physSize * 5];
378 try 520 try
379 { 521 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes)) 522 decodedMeshOsd = DecompressOsd(meshBytes);
381 {
382 using (MemoryStream outMs = new MemoryStream())
383 {
384 using (ZOutputStream zOut = new ZOutputStream(outMs))
385 {
386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
389 {
390 zOut.Write(readBuffer, 0, readLen);
391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
398 }
399 }
400 }
401 } 523 }
402 catch (Exception e) 524 catch (Exception e)
403 { 525 {
404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); 526 m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
405 return false; 527 return false;
406 } 528 }
407 529
@@ -410,7 +532,7 @@ namespace OpenSim.Region.Physics.Meshing
410 // physics_shape is an array of OSDMaps, one for each submesh 532 // physics_shape is an array of OSDMaps, one for each submesh
411 if (decodedMeshOsd is OSDArray) 533 if (decodedMeshOsd is OSDArray)
412 { 534 {
413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); 535 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
414 536
415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 537 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
416 foreach (OSD subMeshOsd in decodedMeshOsdArray) 538 foreach (OSD subMeshOsd in decodedMeshOsdArray)
@@ -418,12 +540,50 @@ namespace OpenSim.Region.Physics.Meshing
418 if (subMeshOsd is OSDMap) 540 if (subMeshOsd is OSDMap)
419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); 541 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
420 } 542 }
543 if (debugDetail)
544 m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
545 LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
421 } 546 }
422 } 547 }
423 548
424 return true; 549 return true;
425 } 550 }
426 551
552
553 /// <summary>
554 /// decompresses a gzipped OSD object
555 /// </summary>
556 /// <param name="decodedOsd"></param> the OSD object
557 /// <param name="meshBytes"></param>
558 /// <returns></returns>
559 private static OSD DecompressOsd(byte[] meshBytes)
560 {
561 OSD decodedOsd = null;
562
563 using (MemoryStream inMs = new MemoryStream(meshBytes))
564 {
565 using (MemoryStream outMs = new MemoryStream())
566 {
567 using (ZOutputStream zOut = new ZOutputStream(outMs))
568 {
569 byte[] readBuffer = new byte[2048];
570 int readLen = 0;
571 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
572 {
573 zOut.Write(readBuffer, 0, readLen);
574 }
575 zOut.Flush();
576 outMs.Seek(0, SeekOrigin.Begin);
577
578 byte[] decompressedBuf = outMs.GetBuffer();
579
580 decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
581 }
582 }
583 }
584 return decodedOsd;
585 }
586
427 /// <summary> 587 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. 588 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary> 589 /// </summary>
@@ -700,6 +860,45 @@ namespace OpenSim.Region.Physics.Meshing
700 return true; 860 return true;
701 } 861 }
702 862
863 /// <summary>
864 /// temporary prototype code - please do not use until the interface has been finalized!
865 /// </summary>
866 /// <param name="size">value to scale the hull points by</param>
867 /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns>
868 public List<Vector3> GetBoundingHull(Vector3 size)
869 {
870 if (mBoundingHull == null)
871 return null;
872
873 List<Vector3> verts = new List<Vector3>();
874 foreach (var vert in mBoundingHull)
875 verts.Add(vert * size);
876
877 return verts;
878 }
879
880 /// <summary>
881 /// temporary prototype code - please do not use until the interface has been finalized!
882 /// </summary>
883 /// <param name="size">value to scale the hull points by</param>
884 /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns>
885 public List<List<Vector3>> GetConvexHulls(Vector3 size)
886 {
887 if (mConvexHulls == null)
888 return null;
889
890 List<List<Vector3>> hulls = new List<List<Vector3>>();
891 foreach (var hull in mConvexHulls)
892 {
893 List<Vector3> verts = new List<Vector3>();
894 foreach (var vert in hull)
895 verts.Add(vert * size);
896 hulls.Add(verts);
897 }
898
899 return hulls;
900 }
901
703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 902 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
704 { 903 {
705 return CreateMesh(primName, primShape, size, lod, false, true); 904 return CreateMesh(primName, primShape, size, lod, false, true);