From 2b6487c8324fa858bf04b4284d4f31ac70274169 Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Thu, 12 Jun 2008 01:11:57 +0000 Subject: [PATCH] * Added Prim drawing to the mainmap tile generation.. you can see blocks representing the prim now on the mainmap. * It isn't perfect since the blocks are square, however it's pretty good. * Performance is also pretty good, however, if it takes too long for you, you can disable it in the OpenSim.ini * You can see how long it takes in milliseconds on the console when it finishes. --- OpenSim/Region/Environment/Scenes/Scene.cs | 144 ++++++++++++++++++++- bin/OpenSim.ini.example | 4 + 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 3c9f91bf5e..798c9adb76 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -998,9 +998,11 @@ namespace OpenSim.Region.Environment.Scenes // Cannot create a map for a nonexistant heightmap yet. if (Heightmap == null) return; - + if (terrain == null) { + int tc = System.Environment.TickCount; + m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); Bitmap mapbmp = new Bitmap(256, 256); double[,] hm = Heightmap.GetDoubles(); @@ -1129,6 +1131,146 @@ namespace OpenSim.Region.Environment.Scenes //tc = System.Environment.TickCount - tc; //m_log.Info("[MAPTILE]: Completed One row in " + tc + " ms"); } + m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms"); + + bool drawPrimVolume = true; + + + try + { + IConfig startupConfig = m_config.Configs["Startup"]; + drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", true); + } + catch (Exception) + { + m_log.Warn("Failed to load StarupConfg"); + } + + + if (drawPrimVolume) + { + tc = System.Environment.TickCount; + m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); + List objs = GetEntities(); + + lock (objs) + { + foreach (EntityBase obj in objs) + { + // Only draw the contents of SceneObjectGroup + if (obj is SceneObjectGroup) + { + SceneObjectGroup mapdot = (SceneObjectGroup)obj; + Color mapdotspot = Color.Gray; // Default color when prim color is white + // Loop over prim in group + foreach (SceneObjectPart part in mapdot.Children.Values) + { + // Draw if the object is at least 1 meter wide in any direction + if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) + { + LLColor texcolor = part.Shape.Textures.DefaultTexture.RGBA; + int colorr = 255 - (int)(texcolor.R * 255f); + int colorg = 255 - (int)(texcolor.G * 255f); + int colorb = 255 - (int)(texcolor.B * 255f); + + if (colorr == 255 && colorg == 255 && colorb == 255) + { } + else + { + try + { + // If the color gets goofy somehow, skip it *shakes fist at LLColor + mapdotspot = Color.FromArgb(colorr, colorg, colorb); + } + catch (ArgumentException) + { + } + } + + LLVector3 pos = part.GetWorldPosition(); + + // skip prim outside of retion + if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f) + continue; + + // skip prim in non-finite position + if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || Single.IsInfinity(pos.X) + || Single.IsInfinity(pos.Y)) + continue; + + // Figure out if object is under 256m above the height of the terrain + bool isBelow256AboveTerrain = false; + + try + { + isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f)); + } + catch (Exception) + { + } + + if (isBelow256AboveTerrain) + { + // Translate scale by rotation so scale is represented properly when object is rotated + Vector3 scale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); + LLQuaternion llrot = part.GetWorldRotation(); + Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); + scale = rot * scale; + + // negative scales don't work in this situation + scale.x = Math.Abs(scale.x); + scale.y = Math.Abs(scale.y); + scale.z = Math.Abs(scale.z); + + // This scaling isn't very accurate and doesn't take into account the face rotation :P + int mapdrawstartX = (int)(pos.X - scale.x); + int mapdrawstartY = (int)(pos.Y - scale.y); + int mapdrawendX = (int)(pos.X + scale.x); + int mapdrawendY = (int)(pos.Y + scale.y); + + // If object is beyond the edge of the map, don't draw it to avoid errors + if (mapdrawstartX < 0 || mapdrawstartX > 255 || mapdrawendX < 0 || mapdrawendX > 255 + || mapdrawstartY < 0 || mapdrawstartY > 255 || mapdrawendY < 0 + || mapdrawendY > 255) + continue; + + + int wy = 0; + + bool breakYN = false; // If we run into an error drawing, break out of the + // loop so we don't lag to death on error handling + for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) + { + for (wy = mapdrawstartY; wy < mapdrawendY; wy++) + { + //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); + try + { + // Remember, flip the y! + mapbmp.SetPixel(wx, (255 - wy), mapdotspot); + } + catch (ArgumentException) + { + breakYN = true; + } + + if (breakYN) + break; + } + + if (breakYN) + break; + } + } // Object is within 256m Z of terrain + } // object is at least a meter wide + } // loop over group children + } // entitybase is sceneobject group + } // foreach loop over entities + } // lock entities objs + + m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (System.Environment.TickCount - tc) + " ms"); + } // end if drawPrimOnMaptle + byte[] data; try { diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 0682a3e4b4..d61eef0d61 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -22,6 +22,10 @@ region_info_source = "filesystem" ; except that everything is also enclosed in a tag. ; regionload_webserver_url = "http://example.com/regions.xml"; +; Draw objects on maptile. This step might take a long time if you've got a huge amount of +; objects, so you can turn it off here if you'd like. +DrawPrimOnMapTile = true + ; ## ; ## STORAGE ; ##