diff options
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/Meshmerizer.cs')
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 249 |
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); |