29 using System.Collections.Generic;
31 using System.Drawing.Imaging;
33 using System.Reflection;
38 using Rednettle.Warp3D;
41 using OpenSim.Framework;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Region.Framework.Scenes;
44 using OpenSim.Region.PhysicsModules.SharedBase;
45 using OpenSim.Services.Interfaces;
48 using OpenMetaverse.Assets;
49 using OpenMetaverse.Imaging;
50 using OpenMetaverse.Rendering;
51 using OpenMetaverse.StructuredData;
55 namespace OpenSim.
Region.CoreModules.
World.Warp3DMap
57 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"Warp3DImageModule")]
60 private static readonly
UUID TEXTURE_METADATA_MAGIC =
new UUID(
"802dc0e0-f080-4931-8b57-d1be8611c4f3");
61 private static readonly Color4 WATER_COLOR =
new Color4(29, 72, 96, 216);
63 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
65 #pragma warning disable 414
66 private static string LogHeader =
"[WARP 3D IMAGE MODULE]";
67 #pragma warning restore 414
69 private Scene m_scene;
70 private IRendering m_primMesher;
71 private Dictionary<UUID, Color4> m_colors =
new Dictionary<UUID, Color4>();
73 private IConfigSource m_config;
74 private bool m_drawPrimVolume =
true;
75 private bool m_textureTerrain =
true;
76 private bool m_texturePrims =
true;
77 private float m_texturePrimSize = 48f;
78 private bool m_renderMeshes =
false;
79 private bool m_useAntiAliasing =
false;
81 private bool m_Enabled =
false;
83 private Bitmap lastImage = null;
84 private DateTime lastImageTime = DateTime.MinValue;
86 #region Region Module interface
92 string[] configSections =
new string[] {
"Map",
"Startup" };
94 if (Util.GetConfigVarFromSections<
string>(
95 m_config,
"MapImageModule", configSections,
"MapImageModule") !=
"Warp3DImageModule")
101 = Util.GetConfigVarFromSections<
bool>(m_config,
"DrawPrimOnMapTile", configSections, m_drawPrimVolume);
103 = Util.GetConfigVarFromSections<
bool>(m_config,
"TextureOnMapTile", configSections, m_textureTerrain);
105 = Util.GetConfigVarFromSections<
bool>(m_config,
"TexturePrims", configSections, m_texturePrims);
107 = Util.GetConfigVarFromSections<
float>(m_config,
"TexturePrimSize", configSections, m_texturePrimSize);
109 = Util.GetConfigVarFromSections<
bool>(m_config,
"RenderMeshes", configSections, m_renderMeshes);
111 = Util.GetConfigVarFromSections<
bool>(m_config,
"UseAntiAliasing", configSections, m_useAntiAliasing);
122 List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
123 if (renderers.Count > 0)
124 m_log.Info(
"[MAPTILE]: Loaded prim mesher " + renderers[0]);
126 m_log.Info(
"[MAPTILE]: No prim mesher loaded, prim rendering will be disabled");
145 get {
return "Warp3DImageModule"; }
148 public Type ReplaceableInterface
155 #region IMapImageGenerator Members
166 List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
167 if (renderers.Count > 0)
169 m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
172 Vector3 camPos =
new Vector3(
173 m_scene.RegionInfo.RegionSizeX / 2 - 0.5f,
174 m_scene.RegionInfo.RegionSizeY / 2 - 0.5f,
178 (
int)m_scene.RegionInfo.RegionSizeX, (
int)m_scene.RegionInfo.RegionSizeY,
179 (
float)m_scene.RegionInfo.RegionSizeX, (
float)m_scene.RegionInfo.RegionSizeY);
181 Bitmap tile = CreateMapTile(viewport,
false);
191 public Bitmap
CreateViewImage(Vector3 camPos, Vector3 camDir,
float fov,
int width,
int height,
bool useTextures)
194 return CreateMapTile(viewport, useTextures);
201 int width = viewport.Width;
202 int height = viewport.Height;
204 if (m_useAntiAliasing)
212 renderer.CreateScene(width, height);
213 renderer.Scene.autoCalcNormals =
false;
217 warp_Vector pos = ConvertVector(viewport.
Position);
219 warp_Vector lookat = warp_Vector.add(ConvertVector(viewport.
Position), ConvertVector(viewport.
LookDirection));
221 renderer.Scene.defaultCamera.setPos(pos);
222 renderer.Scene.defaultCamera.lookAt(lookat);
226 renderer.Scene.defaultCamera.isOrthographic =
true;
227 renderer.Scene.defaultCamera.orthoViewWidth = viewport.OrthoWindowWidth;
228 renderer.Scene.defaultCamera.orthoViewHeight = viewport.OrthoWindowHeight;
232 float fov = viewport.FieldOfView;
234 renderer.Scene.defaultCamera.setFov(fov);
239 renderer.Scene.addLight(
"Light1",
new warp_Light(
new warp_Vector(1.0f, 0.5f, 1f), 0xffffff, 0, 320, 40));
240 renderer.Scene.addLight(
"Light2",
new warp_Light(
new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40));
242 CreateWater(renderer);
243 CreateTerrain(renderer, m_textureTerrain);
244 if (m_drawPrimVolume)
245 CreateAllPrims(renderer, useTextures);
248 Bitmap bitmap = renderer.Scene.getImage();
250 if (m_useAntiAliasing)
252 using (Bitmap origBitmap = bitmap)
253 bitmap = ImageUtils.ResizeImage(origBitmap, viewport.
Width, viewport.
Height);
260 foreach (var o
in renderer.Scene.objectData.Values)
262 warp_Object obj = (warp_Object)o;
263 obj.vertexData = null;
264 obj.triangleData = null;
267 renderer.Scene.removeAllObjects();
273 m_log.Debug(
"[WARP 3D IMAGE MODULE]: GC.Collect()");
282 using (Bitmap mapbmp = CreateMapTile())
283 return OpenJPEG.EncodeFromImage(mapbmp,
true);
288 m_log.Error(
"[WARP 3D IMAGE MODULE]: Failed generating terrain map: ", e);
296 #region Rendering Methods
301 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
303 renderer.AddPlane(
"Water", m_scene.RegionInfo.RegionSizeX * 0.5f);
304 renderer.Scene.sceneobject(
"Water").setPos(m_scene.RegionInfo.RegionSizeX / 2 - 0.5f,
306 m_scene.RegionInfo.RegionSizeY / 2 - 0.5f);
308 warp_Material waterColorMaterial =
new warp_Material(ConvertColor(WATER_COLOR));
309 waterColorMaterial.setReflectivity(0);
310 waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f));
311 renderer.Scene.addMaterial(
"WaterColor", waterColorMaterial);
312 renderer.SetObjectMaterial(
"Water",
"WaterColor");
318 private void CreateTerrain(
WarpRenderer renderer,
bool textureTerrain)
323 float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f;
325 warp_Object obj =
new warp_Object(256 * 256, 255 * 255 * 2);
328 for (
float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
330 for (
float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
332 warp_Vector pos = ConvertVector(x, y, (
float)terrain[(
int)x, (
int)y]);
333 obj.addVertex(
new warp_Vertex(pos,
334 x / (
float)m_scene.RegionInfo.RegionSizeX,
335 (((
float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY));
342 for (
float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
344 for (
float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
346 float newX = x / diff;
347 float newY = y / diff;
348 if (newX < 255 && newY < 255)
350 int v = (int)newY * 256 + (
int)newX;
353 Vector3 v1 =
new Vector3(newX, newY, (
float)terrain[(
int)x, (
int)y]);
354 Vector3 v2 =
new Vector3(newX + 1, newY, (
float)terrain[(
int)(x + 1), (
int)y]);
355 Vector3 v3 =
new Vector3(newX, newY + 1, (
float)terrain[(
int)x, ((
int)(y + 1))]);
356 warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3));
357 norm = norm.reverse();
358 obj.vertex(v).n = norm;
374 renderer.Scene.addObject(
"Terrain", obj);
377 float[] startHeights =
new float[4];
378 float[] heightRanges =
new float[4];
382 textureIDs[0] = regionInfo.TerrainTexture1;
383 textureIDs[1] = regionInfo.TerrainTexture2;
384 textureIDs[2] = regionInfo.TerrainTexture3;
385 textureIDs[3] = regionInfo.TerrainTexture4;
388 startHeights[1] = (
float)regionInfo.Elevation1NW;
389 startHeights[2] = (float)regionInfo.Elevation1SE;
390 startHeights[3] = (
float)regionInfo.Elevation1NE;
392 heightRanges[0] = (float)regionInfo.Elevation2SW;
393 heightRanges[1] = (
float)regionInfo.Elevation2NW;
394 heightRanges[2] = (float)regionInfo.Elevation2SE;
395 heightRanges[3] = (
float)regionInfo.Elevation2NE;
397 uint globalX, globalY;
398 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
400 warp_Texture texture;
403 = TerrainSplat.Splat(
404 terrain, textureIDs, startHeights, heightRanges,
405 new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain))
407 texture =
new warp_Texture(image);
410 warp_Material material =
new warp_Material(texture);
411 material.setReflectivity(50);
412 renderer.Scene.addMaterial(
"TerrainColor", material);
413 renderer.Scene.material(
"TerrainColor").setReflectivity(0);
414 renderer.SetObjectMaterial(
"Terrain",
"TerrainColor");
417 private void CreateAllPrims(
WarpRenderer renderer,
bool useTextures)
419 if (m_primMesher == null)
426 CreatePrim(renderer, child, useTextures);
434 const float MIN_SIZE = 2f;
438 if (prim.
Scale.LengthSquared() < MIN_SIZE * MIN_SIZE)
441 FacetedMesh renderMesh = null;
442 Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);
446 if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture !=
UUID.Zero)
449 byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
450 if (sculptAsset != null)
455 AssetMesh meshAsset =
new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
456 FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
462 if (imgDecoder != null)
464 Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
467 renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt,
478 if (renderMesh == null)
480 renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
483 if (renderMesh == null)
489 warp_Matrix m = warp_Matrix.quaternionMatrix(primRot);
498 warp_Vector primScale = ConvertVector(prim.
Scale);
500 string primID = prim.UUID.ToString();
504 for (
int i = 0; i < renderMesh.Faces.Count; i++)
506 Face face = renderMesh.Faces[i];
507 string meshName = primID +
"-Face-" + i.ToString();
510 if (renderer.Scene.objectData.ContainsKey(meshName))
515 warp_Object faceObj =
new warp_Object(face.Vertices.Count, face.Indices.Count / 3);
517 for (
int j = 0; j < face.Vertices.Count; j++)
519 Vertex v = face.Vertices[j];
521 warp_Vector pos = ConvertVector(v.Position);
522 warp_Vector norm = ConvertVector(v.Normal);
525 norm = norm.reverse();
526 warp_Vertex vert =
new warp_Vertex(pos, norm, v.TexCoord.
X, v.TexCoord.
Y);
528 faceObj.addVertex(vert);
531 for (
int j = 0; j < face.Indices.Count; j += 3)
536 face.Indices[j + 2]);
539 Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
540 Color4 faceColor = GetFaceColor(teFace);
541 string materialName = String.Empty;
542 if (m_texturePrims && prim.
Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize)
543 materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID);
545 materialName = GetOrCreateMaterial(renderer, faceColor);
547 faceObj.transform(m);
548 faceObj.setPos(primPos);
549 faceObj.scaleSelf(primScale.x, primScale.y, primScale.z);
551 renderer.Scene.addObject(meshName, faceObj);
553 renderer.SetObjectMaterial(meshName, materialName);
557 private Color4 GetFaceColor(
Primitive.TextureEntryFace face)
561 if (face.TextureID ==
UUID.Zero)
564 if (!m_colors.TryGetValue(face.TextureID, out color))
566 bool fetched =
false;
569 UUID metadataID = UUID.Combine(face.TextureID, TEXTURE_METADATA_MAGIC);
570 AssetBase metadata = m_scene.AssetService.GetCached(metadataID.ToString());
571 if (metadata != null)
574 try { map = OSDParser.Deserialize(metadata.Data) as
OSDMap; }
catch { }
578 color = map[
"X-JPEG2000-RGBA"].AsColor4();
587 AssetBase textureAsset = m_scene.AssetService.Get(face.TextureID.ToString());
588 if (textureAsset != null)
591 color = GetAverageColor(textureAsset.FullID, textureAsset.Data, out width, out height);
593 OSDMap data =
new OSDMap { {
"X-JPEG2000-RGBA", OSD.FromColor4(color) } };
596 Data = System.Text.Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(data)),
597 Description =
"Metadata for JPEG2000 texture " + face.TextureID.ToString(),
604 Type = (sbyte)AssetType.Unknown
606 m_scene.AssetService.Store(metadata);
610 color =
new Color4(0.5f, 0.5f, 0.5f, 1.0f);
614 m_colors[face.TextureID] = color;
617 return color * face.RGBA;
620 private string GetOrCreateMaterial(
WarpRenderer renderer, Color4 color)
622 string name = color.ToString();
624 warp_Material material = renderer.Scene.material(name);
625 if (material != null)
628 renderer.AddMaterial(name, ConvertColor(color));
630 renderer.Scene.material(name).setTransparency((byte)((1f - color.A) * 255f));
636 string materialName =
"Color-" + faceColor.ToString() +
"-Texture-" + textureID.ToString();
638 if (renderer.Scene.material(materialName) == null)
640 renderer.AddMaterial(materialName, ConvertColor(faceColor));
641 if (faceColor.A < 1f)
643 renderer.Scene.material(materialName).setTransparency((byte) ((1f - faceColor.A)*255f));
645 warp_Texture texture = GetTexture(textureID);
647 renderer.Scene.material(materialName).setTexture(texture);
653 private warp_Texture GetTexture(UUID
id)
655 warp_Texture ret = null;
657 byte[] asset = m_scene.AssetService.GetData(id.ToString());
666 ret =
new warp_Texture(img);
670 m_log.Warn(string.Format(
"[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id), e);
677 #endregion Rendering Methods
679 #region Static Helpers
681 private static warp_Vector ConvertVector(
float x,
float y,
float z)
683 return new warp_Vector(x, z, y);
686 private static warp_Vector ConvertVector(Vector3
vector)
688 return new warp_Vector(vector.X, vector.Z, vector.Y);
691 private static warp_Quaternion ConvertQuaternion(Quaternion quat)
693 return new warp_Quaternion(quat.X, quat.Z, quat.Y, -quat.W);
696 private static int ConvertColor(Color4 color)
698 int c = warp_Color.getColor((byte)(color.R * 255f), (byte)(color.G * 255f), (byte)(color.B * 255f));
700 c |= (byte)(color.A * 255f) << 24;
705 private static Vector3 SurfaceNormal(Vector3 c1, Vector3 c2, Vector3 c3)
707 Vector3 edge1 =
new Vector3(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
708 Vector3 edge2 =
new Vector3(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
710 Vector3 normal = Vector3.Cross(edge1, edge2);
716 public static Color4
GetAverageColor(UUID textureID, byte[] j2kData, out
int width, out
int height)
723 using (MemoryStream stream =
new MemoryStream(j2kData))
729 using (Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream))
731 width = bitmap.Width;
732 height = bitmap.Height;
734 BitmapData bitmapData = bitmap.LockBits(
new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
735 pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
742 for (
int y = 0; y < height; y++)
744 byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
746 for (
int x = 0; x < width; x++)
748 b += row[x * pixelBytes + 0];
749 g += row[x * pixelBytes + 1];
750 r += row[x * pixelBytes + 2];
751 a += row[x * pixelBytes + 3];
757 for (
int y = 0; y < height; y++)
759 byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
761 for (
int x = 0; x < width; x++)
763 b += row[x * pixelBytes + 0];
764 g += row[x * pixelBytes + 1];
765 r += row[x * pixelBytes + 2];
773 const decimal OO_255 = 1m / 255m;
774 decimal totalPixels = (decimal)(width * height);
776 decimal rm = ((decimal)r / totalPixels) * OO_255;
777 decimal gm = ((decimal)g / totalPixels) * OO_255;
778 decimal bm = ((decimal)b / totalPixels) * OO_255;
779 decimal am = ((decimal)a / totalPixels) * OO_255;
784 return new Color4((
float)rm, (
float)gm, (
float)bm, (
float)am);
789 "[WARP 3D IMAGE MODULE]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}",
790 textureID, j2kData.Length, ex.Message);
794 return new Color4(0.5f, 0.5f, 0.5f, 1.0f);
799 #endregion Static Helpers
802 public static class ImageUtils
814 public static float Bilinear(
float v00,
float v01,
float v10,
float v11,
float xPercent,
float yPercent)
816 return Utils.Lerp(Utils.Lerp(v00, v01, xPercent),
Utils.Lerp(v10, v11, xPercent), yPercent);
826 public static Bitmap ResizeImage(Image image,
int width,
int height)
828 Bitmap result =
new Bitmap(width, height);
830 using (Graphics graphics = Graphics.FromImage(result))
832 graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
833 graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
834 graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
835 graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
837 graphics.DrawImage(image, 0, 0, result.Width, result.Height);
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
static Color4 GetAverageColor(UUID textureID, byte[] j2kData, out int width, out int height)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
OpenSim.Server.Handlers.Simulation.Utils Utils
byte[] WriteJpeg2000Image()
Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures)
OpenMetaverse.StructuredData.OSDMap OSDMap
OpenSim.Framework.RegionSettings RegionSettings
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Asset class. All Assets are reference by this class or a class derived from this class ...
Image DecodeToImage(byte[] j2kData)
Provides a synchronous decode direct to an image object
Vector3 Scale
Change the scale of this part.
Bitmap CreateMapTile(Viewport viewport, bool useTextures)
OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType SculptType
global::Warp3D.Warp3D WarpRenderer
override string ToString()
string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID)
uint ParentID
The parent ID of this part.
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3 vector
Vector3 GetWorldPosition()
Method for a prim to get it's world position from the group.
Quaternion RotationOffset