aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs (renamed from OpenSim/Region/Physics/Meshing/Meshmerizer.cs)389
1 files changed, 319 insertions, 70 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs
index 8145d61..4d25bf3 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs
@@ -28,8 +28,12 @@
28 28
29using System; 29using System;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection;
32using System.IO;
31using OpenSim.Framework; 33using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager; 34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.PhysicsModules.SharedBase;
33using OpenMetaverse; 37using OpenMetaverse;
34using OpenMetaverse.StructuredData; 38using OpenMetaverse.StructuredData;
35using System.Drawing; 39using System.Drawing;
@@ -38,32 +42,15 @@ using System.IO.Compression;
38using PrimMesher; 42using PrimMesher;
39using log4net; 43using log4net;
40using Nini.Config; 44using Nini.Config;
41using System.Reflection; 45using Mono.Addins;
42using System.IO;
43using ComponentAce.Compression.Libs.zlib;
44 46
45namespace OpenSim.Region.Physics.Meshing 47namespace OpenSim.Region.PhysicsModules.Meshing
46{ 48{
47 public class MeshmerizerPlugin : IMeshingPlugin 49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "Meshmerizer")]
48 { 50 public class Meshmerizer : IMesher, INonSharedRegionModule
49 public MeshmerizerPlugin()
50 {
51 }
52
53 public string GetName()
54 {
55 return "Meshmerizer";
56 }
57
58 public IMesher GetMesher(IConfigSource config)
59 {
60 return new Meshmerizer(config);
61 }
62 }
63
64 public class Meshmerizer : IMesher
65 { 51 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 private static string LogHeader = "[MESH]";
67 54
68 // Setting baseDir to a path will enable the dumping of raw files 55 // 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 56 // raw files can be imported by blender so a visual inspection of the results can be done
@@ -72,6 +59,10 @@ namespace OpenSim.Region.Physics.Meshing
72#else 59#else
73 private const string baseDir = null; //"rawFiles"; 60 private const string baseDir = null; //"rawFiles";
74#endif 61#endif
62 private bool m_Enabled = false;
63
64 // If 'true', lots of DEBUG logging of asset parsing details
65 private bool debugDetail = false;
75 66
76 private bool cacheSculptMaps = true; 67 private bool cacheSculptMaps = true;
77 private string decodedSculptMapPath = null; 68 private string decodedSculptMapPath = null;
@@ -79,29 +70,85 @@ namespace OpenSim.Region.Physics.Meshing
79 70
80 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh 71 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
81 72
82 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); 73 private List<List<Vector3>> mConvexHulls = null;
74 private List<Vector3> mBoundingHull = null;
75
76 // Mesh cache. Static so it can be shared across instances of this class
77 private static Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
83 78
84 public Meshmerizer(IConfigSource config) 79 #region INonSharedRegionModule
80 public string Name
85 { 81 {
86 IConfig start_config = config.Configs["Startup"]; 82 get { return "Meshmerizer"; }
87 IConfig mesh_config = config.Configs["Mesh"]; 83 }
88 84
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); 85 public Type ReplaceableInterface
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); 86 {
91 if(mesh_config != null) 87 get { return null; }
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); 88 }
93 89
94 try 90 public void Initialise(IConfigSource source)
95 { 91 {
96 if (!Directory.Exists(decodedSculptMapPath)) 92 IConfig config = source.Configs["Startup"];
97 Directory.CreateDirectory(decodedSculptMapPath); 93 if (config != null)
98 }
99 catch (Exception e)
100 { 94 {
101 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message); 95 string mesher = config.GetString("meshing", string.Empty);
96 if (mesher == Name)
97 {
98 m_Enabled = true;
99
100 IConfig mesh_config = source.Configs["Mesh"];
101
102 decodedSculptMapPath = config.GetString("DecodedSculptMapPath", "j2kDecodeCache");
103 cacheSculptMaps = config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
104 if (mesh_config != null)
105 {
106 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
107 debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail);
108 }
109
110 try
111 {
112 if (!Directory.Exists(decodedSculptMapPath))
113 Directory.CreateDirectory(decodedSculptMapPath);
114 }
115 catch (Exception e)
116 {
117 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
118 }
119
120 }
102 } 121 }
103 } 122 }
104 123
124 public void Close()
125 {
126 }
127
128 public void AddRegion(Scene scene)
129 {
130 if (!m_Enabled)
131 return;
132
133 scene.RegisterModuleInterface<IMesher>(this);
134 }
135
136 public void RemoveRegion(Scene scene)
137 {
138 if (!m_Enabled)
139 return;
140
141 scene.UnregisterModuleInterface<IMesher>(this);
142 }
143
144 public void RegionLoaded(Scene scene)
145 {
146 if (!m_Enabled)
147 return;
148 }
149 #endregion
150
151
105 /// <summary> 152 /// <summary>
106 /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may 153 /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may
107 /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail 154 /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail
@@ -319,6 +366,9 @@ namespace OpenSim.Region.Physics.Meshing
319 faces = new List<Face>(); 366 faces = new List<Face>();
320 OSD meshOsd = null; 367 OSD meshOsd = null;
321 368
369 mConvexHulls = null;
370 mBoundingHull = null;
371
322 if (primShape.SculptData.Length <= 0) 372 if (primShape.SculptData.Length <= 0)
323 { 373 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this 374 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
@@ -355,9 +405,139 @@ namespace OpenSim.Region.Physics.Meshing
355 OSDMap physicsParms = null; 405 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd; 406 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape")) 407 if (map.ContainsKey("physics_shape"))
408 {
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format 409 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
410 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
411 }
359 else if (map.ContainsKey("physics_mesh")) 412 else if (map.ContainsKey("physics_mesh"))
413 {
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 414 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
415 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
416 }
417 else if (map.ContainsKey("medium_lod"))
418 {
419 physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
420 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
421 }
422 else if (map.ContainsKey("high_lod"))
423 {
424 physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
425 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
426 }
427
428 if (map.ContainsKey("physics_convex"))
429 { // pull this out also in case physics engine can use it
430 OSD convexBlockOsd = null;
431 try
432 {
433 OSDMap convexBlock = (OSDMap)map["physics_convex"];
434 {
435 int convexOffset = convexBlock["offset"].AsInteger() + (int)start;
436 int convexSize = convexBlock["size"].AsInteger();
437
438 byte[] convexBytes = new byte[convexSize];
439
440 System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize);
441
442 try
443 {
444 convexBlockOsd = DecompressOsd(convexBytes);
445 }
446 catch (Exception e)
447 {
448 m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e);
449 //return false;
450 }
451 }
452
453 if (convexBlockOsd != null && convexBlockOsd is OSDMap)
454 {
455 convexBlock = convexBlockOsd as OSDMap;
456
457 if (debugDetail)
458 {
459 string keys = LogHeader + " keys found in convexBlock: ";
460 foreach (KeyValuePair<string, OSD> kvp in convexBlock)
461 keys += "'" + kvp.Key + "' ";
462 m_log.Debug(keys);
463 }
464
465 Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f);
466 if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3();
467 Vector3 max = new Vector3(0.5f, 0.5f, 0.5f);
468 if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3();
469
470 List<Vector3> boundingHull = null;
471
472 if (convexBlock.ContainsKey("BoundingVerts"))
473 {
474 byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary();
475 boundingHull = new List<Vector3>();
476 for (int i = 0; i < boundingVertsBytes.Length; )
477 {
478 ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
479 ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
480 ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
481
482 Vector3 pos = new Vector3(
483 Utils.UInt16ToFloat(uX, min.X, max.X),
484 Utils.UInt16ToFloat(uY, min.Y, max.Y),
485 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
486 );
487
488 boundingHull.Add(pos);
489 }
490
491 mBoundingHull = boundingHull;
492 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count);
493 }
494
495 if (convexBlock.ContainsKey("HullList"))
496 {
497 byte[] hullList = convexBlock["HullList"].AsBinary();
498
499 byte[] posBytes = convexBlock["Positions"].AsBinary();
500
501 List<List<Vector3>> hulls = new List<List<Vector3>>();
502 int posNdx = 0;
503
504 foreach (byte cnt in hullList)
505 {
506 int count = cnt == 0 ? 256 : cnt;
507 List<Vector3> hull = new List<Vector3>();
508
509 for (int i = 0; i < count; i++)
510 {
511 ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
512 ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
513 ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
514
515 Vector3 pos = new Vector3(
516 Utils.UInt16ToFloat(uX, min.X, max.X),
517 Utils.UInt16ToFloat(uY, min.Y, max.Y),
518 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
519 );
520
521 hull.Add(pos);
522 }
523
524 hulls.Add(hull);
525 }
526
527 mConvexHulls = hulls;
528 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
529 }
530 else
531 {
532 if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
533 }
534 }
535 }
536 catch (Exception e)
537 {
538 m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
539 }
540 }
361 541
362 if (physicsParms == null) 542 if (physicsParms == null)
363 { 543 {
@@ -374,34 +554,14 @@ namespace OpenSim.Region.Physics.Meshing
374 OSD decodedMeshOsd = new OSD(); 554 OSD decodedMeshOsd = new OSD();
375 byte[] meshBytes = new byte[physSize]; 555 byte[] meshBytes = new byte[physSize];
376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); 556 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
377// byte[] decompressed = new byte[physSize * 5]; 557 // byte[] decompressed = new byte[physSize * 5];
378 try 558 try
379 { 559 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes)) 560 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 } 561 }
402 catch (Exception e) 562 catch (Exception e)
403 { 563 {
404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); 564 m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
405 return false; 565 return false;
406 } 566 }
407 567
@@ -410,7 +570,7 @@ namespace OpenSim.Region.Physics.Meshing
410 // physics_shape is an array of OSDMaps, one for each submesh 570 // physics_shape is an array of OSDMaps, one for each submesh
411 if (decodedMeshOsd is OSDArray) 571 if (decodedMeshOsd is OSDArray)
412 { 572 {
413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); 573 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
414 574
415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 575 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
416 foreach (OSD subMeshOsd in decodedMeshOsdArray) 576 foreach (OSD subMeshOsd in decodedMeshOsdArray)
@@ -418,6 +578,9 @@ namespace OpenSim.Region.Physics.Meshing
418 if (subMeshOsd is OSDMap) 578 if (subMeshOsd is OSDMap)
419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); 579 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
420 } 580 }
581 if (debugDetail)
582 m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
583 LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
421 } 584 }
422 } 585 }
423 586
@@ -425,6 +588,42 @@ namespace OpenSim.Region.Physics.Meshing
425 } 588 }
426 589
427 /// <summary> 590 /// <summary>
591 /// decompresses a gzipped OSD object
592 /// </summary>
593 /// <param name="decodedOsd"></param> the OSD object
594 /// <param name="meshBytes"></param>
595 /// <returns></returns>
596 private static OSD DecompressOsd(byte[] meshBytes)
597 {
598 OSD decodedOsd = null;
599
600 using (MemoryStream inMs = new MemoryStream(meshBytes))
601 {
602 using (MemoryStream outMs = new MemoryStream())
603 {
604 using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress))
605 {
606 byte[] readBuffer = new byte[2048];
607 inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header
608 int readLen = 0;
609
610 while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
611 outMs.Write(readBuffer, 0, readLen);
612
613 outMs.Flush();
614
615 outMs.Seek(0, SeekOrigin.Begin);
616
617 byte[] decompressedBuf = outMs.GetBuffer();
618
619 decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
620 }
621 }
622 }
623 return decodedOsd;
624 }
625
626 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. 627 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary> 628 /// </summary>
430 /// <param name="primName"></param> 629 /// <param name="primName"></param>
@@ -469,10 +668,11 @@ namespace OpenSim.Region.Physics.Meshing
469 668
470 try 669 try
471 { 670 {
472 OpenMetaverse.Imaging.ManagedImage unusedData; 671 OpenMetaverse.Imaging.ManagedImage managedImage;
473 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); 672
673 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage);
474 674
475 if (idata == null) 675 if (managedImage == null)
476 { 676 {
477 // In some cases it seems that the decode can return a null bitmap without throwing 677 // In some cases it seems that the decode can return a null bitmap without throwing
478 // an exception 678 // an exception
@@ -481,9 +681,12 @@ namespace OpenSim.Region.Physics.Meshing
481 return false; 681 return false;
482 } 682 }
483 683
484 unusedData = null; 684 if ((managedImage.Channels & OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha) != 0)
685 managedImage.ConvertChannels(managedImage.Channels & ~OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha);
485 686
486 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); 687 Bitmap imgData = OpenMetaverse.Imaging.LoadTGAClass.LoadTGA(new MemoryStream(managedImage.ExportTGA()));
688 idata = (Image)imgData;
689 managedImage = null;
487 690
488 if (cacheSculptMaps) 691 if (cacheSculptMaps)
489 { 692 {
@@ -700,6 +903,45 @@ namespace OpenSim.Region.Physics.Meshing
700 return true; 903 return true;
701 } 904 }
702 905
906 /// <summary>
907 /// temporary prototype code - please do not use until the interface has been finalized!
908 /// </summary>
909 /// <param name="size">value to scale the hull points by</param>
910 /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns>
911 public List<Vector3> GetBoundingHull(Vector3 size)
912 {
913 if (mBoundingHull == null)
914 return null;
915
916 List<Vector3> verts = new List<Vector3>();
917 foreach (var vert in mBoundingHull)
918 verts.Add(vert * size);
919
920 return verts;
921 }
922
923 /// <summary>
924 /// temporary prototype code - please do not use until the interface has been finalized!
925 /// </summary>
926 /// <param name="size">value to scale the hull points by</param>
927 /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns>
928 public List<List<Vector3>> GetConvexHulls(Vector3 size)
929 {
930 if (mConvexHulls == null)
931 return null;
932
933 List<List<Vector3>> hulls = new List<List<Vector3>>();
934 foreach (var hull in mConvexHulls)
935 {
936 List<Vector3> verts = new List<Vector3>();
937 foreach (var vert in hull)
938 verts.Add(vert * size);
939 hulls.Add(verts);
940 }
941
942 return hulls;
943 }
944
703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 945 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
704 { 946 {
705 return CreateMesh(primName, primShape, size, lod, false, true); 947 return CreateMesh(primName, primShape, size, lod, false, true);
@@ -724,8 +966,11 @@ namespace OpenSim.Region.Physics.Meshing
724 if (shouldCache) 966 if (shouldCache)
725 { 967 {
726 key = primShape.GetMeshKey(size, lod); 968 key = primShape.GetMeshKey(size, lod);
727 if (m_uniqueMeshes.TryGetValue(key, out mesh)) 969 lock (m_uniqueMeshes)
728 return mesh; 970 {
971 if (m_uniqueMeshes.TryGetValue(key, out mesh))
972 return mesh;
973 }
729 } 974 }
730 975
731 if (size.X < 0.01f) size.X = 0.01f; 976 if (size.X < 0.01f) size.X = 0.01f;
@@ -751,11 +996,15 @@ namespace OpenSim.Region.Physics.Meshing
751 996
752 if (shouldCache) 997 if (shouldCache)
753 { 998 {
754 m_uniqueMeshes.Add(key, mesh); 999 lock (m_uniqueMeshes)
1000 {
1001 m_uniqueMeshes.Add(key, mesh);
1002 }
755 } 1003 }
756 } 1004 }
757 1005
758 return mesh; 1006 return mesh;
759 } 1007 }
1008
760 } 1009 }
761} 1010}