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