diff options
-rw-r--r-- | OpenSim/Region/Environment/Modules/World/WorldMap/MapImageModule.cs | 412 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/Scene.cs | 166 |
2 files changed, 478 insertions, 100 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/WorldMap/MapImageModule.cs b/OpenSim/Region/Environment/Modules/World/WorldMap/MapImageModule.cs index 68c8046..a331d37 100644 --- a/OpenSim/Region/Environment/Modules/World/WorldMap/MapImageModule.cs +++ b/OpenSim/Region/Environment/Modules/World/WorldMap/MapImageModule.cs | |||
@@ -26,29 +26,58 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
29 | using System.Drawing; | 30 | using System.Drawing; |
31 | using System.Reflection; | ||
32 | using Axiom.Math; | ||
30 | using Nini.Config; | 33 | using Nini.Config; |
34 | using log4net; | ||
31 | using OpenJPEGNet; | 35 | using OpenJPEGNet; |
32 | using OpenSim.Region.Environment.Interfaces; | 36 | using OpenSim.Region.Environment.Interfaces; |
33 | using OpenSim.Region.Environment.Scenes; | 37 | using OpenSim.Region.Environment.Scenes; |
38 | using libsecondlife; | ||
34 | 39 | ||
35 | namespace OpenSim.Region.Environment.Modules.World.WorldMap | 40 | namespace OpenSim.Region.Environment.Modules.World.WorldMap |
36 | { | 41 | { |
37 | internal class MapImageModule : IMapImageGenerator, IRegionModule | 42 | public class MapImageModule : IMapImageGenerator, IRegionModule |
38 | { | 43 | { |
44 | private static readonly ILog m_log = | ||
45 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
39 | private Scene m_scene; | 47 | private Scene m_scene; |
48 | private IConfigSource m_config; | ||
40 | 49 | ||
41 | #region IMapImageGenerator Members | 50 | #region IMapImageGenerator Members |
42 | 51 | ||
43 | public byte[] WriteJpeg2000Image(string gradientmap) | 52 | public byte[] WriteJpeg2000Image(string gradientmap) |
44 | { | 53 | { |
45 | byte[] imageData = null; | 54 | byte[] imageData = null; |
55 | Bitmap mapbmp = new Bitmap(256, 256); | ||
56 | |||
57 | //Bitmap bmp = TerrainToBitmap(gradientmap); | ||
58 | mapbmp = TerrainToBitmap2(m_scene,mapbmp); | ||
59 | |||
60 | bool drawPrimVolume = true; | ||
61 | |||
62 | try | ||
63 | { | ||
64 | IConfig startupConfig = m_config.Configs["Startup"]; | ||
65 | drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", true); | ||
66 | } | ||
67 | catch (Exception) | ||
68 | { | ||
69 | m_log.Warn("Failed to load StartupConfig"); | ||
70 | } | ||
71 | |||
72 | if (drawPrimVolume) | ||
73 | { | ||
74 | DrawObjectVolume(m_scene, mapbmp); | ||
75 | } | ||
46 | 76 | ||
47 | Bitmap bmp = TerrainToBitmap(gradientmap); | ||
48 | 77 | ||
49 | try | 78 | try |
50 | { | 79 | { |
51 | imageData = OpenJPEG.EncodeFromImage(bmp, true); | 80 | imageData = OpenJPEG.EncodeFromImage(mapbmp, true); |
52 | } | 81 | } |
53 | catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke | 82 | catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke |
54 | { | 83 | { |
@@ -65,6 +94,7 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap | |||
65 | public void Initialise(Scene scene, IConfigSource source) | 94 | public void Initialise(Scene scene, IConfigSource source) |
66 | { | 95 | { |
67 | m_scene = scene; | 96 | m_scene = scene; |
97 | m_config = source; | ||
68 | m_scene.RegisterModuleInterface<IMapImageGenerator>(this); | 98 | m_scene.RegisterModuleInterface<IMapImageGenerator>(this); |
69 | } | 99 | } |
70 | 100 | ||
@@ -128,6 +158,381 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap | |||
128 | } | 158 | } |
129 | } | 159 | } |
130 | 160 | ||
161 | private Bitmap TerrainToBitmap2(Scene whichScene, Bitmap mapbmp) | ||
162 | { | ||
163 | int tc = System.Environment.TickCount; | ||
164 | m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); | ||
165 | |||
166 | double[,] hm = whichScene.Heightmap.GetDoubles(); | ||
167 | bool ShadowDebugContinue = true; | ||
168 | //Color prim = Color.FromArgb(120, 120, 120); | ||
169 | //LLVector3 RayEnd = new LLVector3(0, 0, 0); | ||
170 | //LLVector3 RayStart = new LLVector3(0, 0, 0); | ||
171 | //LLVector3 direction = new LLVector3(0, 0, -1); | ||
172 | //Vector3 AXOrigin = new Vector3(); | ||
173 | //Vector3 AXdirection = new Vector3(); | ||
174 | //Ray testRay = new Ray(); | ||
175 | //EntityIntersection rt = new EntityIntersection(); | ||
176 | bool terraincorruptedwarningsaid = false; | ||
177 | |||
178 | float low = 255; | ||
179 | float high = 0; | ||
180 | for (int x = 0; x < 256; x++) | ||
181 | { | ||
182 | for (int y = 0; y < 256; y++) | ||
183 | { | ||
184 | float hmval = (float)hm[x, y]; | ||
185 | if (hmval < low) | ||
186 | low = hmval; | ||
187 | if (hmval > high) | ||
188 | high = hmval; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | float mid = (high + low) * 0.5f; | ||
193 | |||
194 | // temporary initializer | ||
195 | float hfvalue = (float)whichScene.RegionInfo.RegionSettings.WaterHeight; | ||
196 | float hfvaluecompare = hfvalue; | ||
197 | float hfdiff = hfvalue; | ||
198 | int hfdiffi = 0; | ||
199 | |||
200 | |||
201 | for (int x = 0; x < 256; x++) | ||
202 | { | ||
203 | //int tc = System.Environment.TickCount; | ||
204 | for (int y = 0; y < 256; y++) | ||
205 | { | ||
206 | //RayEnd = new LLVector3(x, y, 0); | ||
207 | //RayStart = new LLVector3(x, y, 255); | ||
208 | |||
209 | //direction = LLVector3.Norm(RayEnd - RayStart); | ||
210 | //AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); | ||
211 | //AXdirection = new Vector3(direction.X, direction.Y, direction.Z); | ||
212 | |||
213 | //testRay = new Ray(AXOrigin, AXdirection); | ||
214 | //rt = m_innerScene.GetClosestIntersectingPrim(testRay); | ||
215 | |||
216 | //if (rt.HitTF) | ||
217 | //{ | ||
218 | //mapbmp.SetPixel(x, y, prim); | ||
219 | //} | ||
220 | //else | ||
221 | //{ | ||
222 | //float tmpval = (float)hm[x, y]; | ||
223 | float heightvalue = (float)hm[x, y]; | ||
224 | |||
225 | |||
226 | if (heightvalue > (float)whichScene.RegionInfo.RegionSettings.WaterHeight) | ||
227 | { | ||
228 | |||
229 | // scale height value | ||
230 | heightvalue = low + mid * (heightvalue - low) / mid; | ||
231 | |||
232 | if (heightvalue > 255) | ||
233 | heightvalue = 255; | ||
234 | |||
235 | if (heightvalue < 0) | ||
236 | heightvalue = 0; | ||
237 | |||
238 | if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) | ||
239 | heightvalue = 0; | ||
240 | try | ||
241 | { | ||
242 | Color green = Color.FromArgb((int)heightvalue, 100, (int)heightvalue); | ||
243 | |||
244 | // Y flip the cordinates | ||
245 | mapbmp.SetPixel(x, (256 - y) - 1, green); | ||
246 | |||
247 | //X | ||
248 | // . | ||
249 | // | ||
250 | // Shade the terrain for shadows | ||
251 | if ((x - 1 > 0) && (y - 1 > 0)) | ||
252 | { | ||
253 | hfvalue = (float)hm[x, y]; | ||
254 | hfvaluecompare = (float)hm[x - 1, y - 1]; | ||
255 | |||
256 | if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue)) | ||
257 | hfvalue = 0; | ||
258 | |||
259 | if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) | ||
260 | hfvaluecompare = 0; | ||
261 | |||
262 | hfdiff = hfvaluecompare - hfvalue; | ||
263 | |||
264 | if (hfdiff > 0.3f) | ||
265 | { | ||
266 | |||
267 | } | ||
268 | else if (hfdiff < -0.3f) | ||
269 | { | ||
270 | // We have to desaturate and blacken the land at the same time | ||
271 | // we use floats, colors use bytes, so shrink are space down to | ||
272 | // 0-255 | ||
273 | |||
274 | |||
275 | try | ||
276 | { | ||
277 | hfdiffi = Math.Abs((int)((hfdiff * 4) + (hfdiff * 0.5))) + 1; | ||
278 | if (hfdiff % 1 != 0) | ||
279 | { | ||
280 | hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1); | ||
281 | } | ||
282 | } | ||
283 | catch (System.OverflowException) | ||
284 | { | ||
285 | m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString()); | ||
286 | ShadowDebugContinue = false; | ||
287 | } | ||
288 | |||
289 | if (ShadowDebugContinue) | ||
290 | { | ||
291 | if ((256 - y) - 1 > 0) | ||
292 | { | ||
293 | Color Shade = mapbmp.GetPixel(x - 1, (256 - y) - 1); | ||
294 | |||
295 | int r = Shade.R; | ||
296 | |||
297 | int g = Shade.G; | ||
298 | int b = Shade.B; | ||
299 | Shade = Color.FromArgb((r - hfdiffi > 0) ? r - hfdiffi : 0, (g - hfdiffi > 0) ? g - hfdiffi : 0, (b - hfdiffi > 0) ? b - hfdiffi : 0); | ||
300 | //Console.WriteLine("d:" + hfdiff.ToString() + ", i:" + hfdiffi + ", pos: " + x + "," + y + " - R:" + Shade.R.ToString() + ", G:" + Shade.G.ToString() + ", B:" + Shade.G.ToString()); | ||
301 | mapbmp.SetPixel(x - 1, (256 - y) - 1, Shade); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | |||
306 | } | ||
307 | |||
308 | } | ||
309 | |||
310 | |||
311 | |||
312 | |||
313 | } | ||
314 | catch (System.ArgumentException) | ||
315 | { | ||
316 | if (!terraincorruptedwarningsaid) | ||
317 | { | ||
318 | m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", whichScene.RegionInfo.RegionName); | ||
319 | terraincorruptedwarningsaid = true; | ||
320 | } | ||
321 | Color black = Color.Black; | ||
322 | mapbmp.SetPixel(x, (256 - y) - 1, black); | ||
323 | } | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | // Y flip the cordinates | ||
328 | heightvalue = (float)whichScene.RegionInfo.RegionSettings.WaterHeight - heightvalue; | ||
329 | if (heightvalue > 19) | ||
330 | heightvalue = 19; | ||
331 | if (heightvalue < 0) | ||
332 | heightvalue = 0; | ||
333 | |||
334 | heightvalue = 100 - (heightvalue * 100) / 19; | ||
335 | |||
336 | if (heightvalue > 255) | ||
337 | heightvalue = 255; | ||
338 | |||
339 | if (heightvalue < 0) | ||
340 | heightvalue = 0; | ||
341 | |||
342 | if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) | ||
343 | heightvalue = 0; | ||
344 | |||
345 | try | ||
346 | { | ||
347 | Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255); | ||
348 | mapbmp.SetPixel(x, (256 - y) - 1, water); | ||
349 | } | ||
350 | catch (System.ArgumentException) | ||
351 | { | ||
352 | if (!terraincorruptedwarningsaid) | ||
353 | { | ||
354 | m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", whichScene.RegionInfo.RegionName); | ||
355 | terraincorruptedwarningsaid = true; | ||
356 | } | ||
357 | Color black = Color.Black; | ||
358 | mapbmp.SetPixel(x, (256 - y) - 1, black); | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | //} | ||
363 | |||
364 | //tc = System.Environment.TickCount - tc; | ||
365 | //m_log.Info("[MAPTILE]: Completed One row in " + tc + " ms"); | ||
366 | } | ||
367 | m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms"); | ||
368 | |||
369 | return mapbmp; | ||
370 | } | ||
371 | |||
372 | |||
373 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) | ||
374 | { | ||
375 | int tc = 0; | ||
376 | double[,] hm = whichScene.Heightmap.GetDoubles(); | ||
377 | tc = System.Environment.TickCount; | ||
378 | m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); | ||
379 | List<EntityBase> objs = whichScene.GetEntities(); | ||
380 | |||
381 | lock (objs) | ||
382 | { | ||
383 | foreach (EntityBase obj in objs) | ||
384 | { | ||
385 | // Only draw the contents of SceneObjectGroup | ||
386 | if (obj is SceneObjectGroup) | ||
387 | { | ||
388 | SceneObjectGroup mapdot = (SceneObjectGroup)obj; | ||
389 | Color mapdotspot = Color.Gray; // Default color when prim color is white | ||
390 | // Loop over prim in group | ||
391 | foreach (SceneObjectPart part in mapdot.Children.Values) | ||
392 | { | ||
393 | if (part == null) | ||
394 | continue; | ||
395 | |||
396 | |||
397 | // Draw if the object is at least 1 meter wide in any direction | ||
398 | if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) | ||
399 | { | ||
400 | // Try to get the RGBA of the default texture entry.. | ||
401 | // | ||
402 | try | ||
403 | { | ||
404 | if (part == null) | ||
405 | continue; | ||
406 | |||
407 | if (part.Shape == null) | ||
408 | continue; | ||
409 | |||
410 | if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree) | ||
411 | continue; // eliminates trees from this since we don't really have a good tree representation | ||
412 | // if you want tree blocks on the map comment the above line and uncomment the below line | ||
413 | //mapdotspot = Color.PaleGreen; | ||
414 | |||
415 | if (part.Shape.Textures == null) | ||
416 | continue; | ||
417 | |||
418 | if (part.Shape.Textures.DefaultTexture == null) | ||
419 | continue; | ||
420 | |||
421 | LLColor texcolor = part.Shape.Textures.DefaultTexture.RGBA; | ||
422 | |||
423 | // Not sure why some of these are null, oh well. | ||
424 | |||
425 | int colorr = 255 - (int)(texcolor.R * 255f); | ||
426 | int colorg = 255 - (int)(texcolor.G * 255f); | ||
427 | int colorb = 255 - (int)(texcolor.B * 255f); | ||
428 | |||
429 | if (!(colorr == 255 && colorg == 255 && colorb == 255)) | ||
430 | { | ||
431 | //Try to set the map spot color | ||
432 | try | ||
433 | { | ||
434 | // If the color gets goofy somehow, skip it *shakes fist at LLColor | ||
435 | mapdotspot = Color.FromArgb(colorr, colorg, colorb); | ||
436 | } | ||
437 | catch (ArgumentException) | ||
438 | { | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | catch (IndexOutOfRangeException) | ||
443 | { | ||
444 | // Windows Array | ||
445 | } | ||
446 | catch (ArgumentOutOfRangeException) | ||
447 | { | ||
448 | // Mono Array | ||
449 | } | ||
450 | |||
451 | LLVector3 pos = part.GetWorldPosition(); | ||
452 | |||
453 | // skip prim outside of retion | ||
454 | if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f) | ||
455 | continue; | ||
456 | |||
457 | // skip prim in non-finite position | ||
458 | if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || Single.IsInfinity(pos.X) | ||
459 | || Single.IsInfinity(pos.Y)) | ||
460 | continue; | ||
461 | |||
462 | // Figure out if object is under 256m above the height of the terrain | ||
463 | bool isBelow256AboveTerrain = false; | ||
464 | |||
465 | try | ||
466 | { | ||
467 | isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f)); | ||
468 | } | ||
469 | catch (Exception) | ||
470 | { | ||
471 | } | ||
472 | |||
473 | if (isBelow256AboveTerrain) | ||
474 | { | ||
475 | // Translate scale by rotation so scale is represented properly when object is rotated | ||
476 | Vector3 scale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); | ||
477 | LLQuaternion llrot = part.GetWorldRotation(); | ||
478 | Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); | ||
479 | scale = rot * scale; | ||
480 | |||
481 | // negative scales don't work in this situation | ||
482 | scale.x = Math.Abs(scale.x); | ||
483 | scale.y = Math.Abs(scale.y); | ||
484 | scale.z = Math.Abs(scale.z); | ||
485 | |||
486 | // This scaling isn't very accurate and doesn't take into account the face rotation :P | ||
487 | int mapdrawstartX = (int)(pos.X - scale.x); | ||
488 | int mapdrawstartY = (int)(pos.Y - scale.y); | ||
489 | int mapdrawendX = (int)(pos.X + scale.x); | ||
490 | int mapdrawendY = (int)(pos.Y + scale.y); | ||
491 | |||
492 | // If object is beyond the edge of the map, don't draw it to avoid errors | ||
493 | if (mapdrawstartX < 0 || mapdrawstartX > 255 || mapdrawendX < 0 || mapdrawendX > 255 | ||
494 | || mapdrawstartY < 0 || mapdrawstartY > 255 || mapdrawendY < 0 | ||
495 | || mapdrawendY > 255) | ||
496 | continue; | ||
497 | |||
498 | int wy = 0; | ||
499 | |||
500 | bool breakYN = false; // If we run into an error drawing, break out of the | ||
501 | // loop so we don't lag to death on error handling | ||
502 | for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) | ||
503 | { | ||
504 | for (wy = mapdrawstartY; wy < mapdrawendY; wy++) | ||
505 | { | ||
506 | //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); | ||
507 | try | ||
508 | { | ||
509 | // Remember, flip the y! | ||
510 | mapbmp.SetPixel(wx, (255 - wy), mapdotspot); | ||
511 | } | ||
512 | catch (ArgumentException) | ||
513 | { | ||
514 | breakYN = true; | ||
515 | } | ||
516 | |||
517 | if (breakYN) | ||
518 | break; | ||
519 | } | ||
520 | |||
521 | if (breakYN) | ||
522 | break; | ||
523 | } | ||
524 | } // Object is within 256m Z of terrain | ||
525 | } // object is at least a meter wide | ||
526 | } // loop over group children | ||
527 | } // entitybase is sceneobject group | ||
528 | } // foreach loop over entities | ||
529 | } // lock entities objs | ||
530 | |||
531 | m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (System.Environment.TickCount - tc) + " ms"); | ||
532 | return mapbmp; | ||
533 | } | ||
534 | |||
535 | # region Depreciated Maptile Generation. Adam may update this | ||
131 | private Bitmap TerrainToBitmap(string gradientmap) | 536 | private Bitmap TerrainToBitmap(string gradientmap) |
132 | { | 537 | { |
133 | Bitmap gradientmapLd = new Bitmap(gradientmap); | 538 | Bitmap gradientmapLd = new Bitmap(gradientmap); |
@@ -163,5 +568,6 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap | |||
163 | return bmp; | 568 | return bmp; |
164 | } | 569 | } |
165 | } | 570 | } |
571 | #endregion | ||
166 | } | 572 | } |
167 | } \ No newline at end of file | 573 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index e060f3d..e8a8a78 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -1023,6 +1023,8 @@ namespace OpenSim.Region.Environment.Scenes | |||
1023 | 1023 | ||
1024 | if (terrain == null) | 1024 | if (terrain == null) |
1025 | { | 1025 | { |
1026 | #region Fallback default maptile generation | ||
1027 | |||
1026 | int tc = System.Environment.TickCount; | 1028 | int tc = System.Environment.TickCount; |
1027 | m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); | 1029 | m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); |
1028 | Bitmap mapbmp = new Bitmap(256, 256); | 1030 | Bitmap mapbmp = new Bitmap(256, 256); |
@@ -1053,13 +1055,13 @@ namespace OpenSim.Region.Environment.Scenes | |||
1053 | } | 1055 | } |
1054 | 1056 | ||
1055 | float mid = (high + low) * 0.5f; | 1057 | float mid = (high + low) * 0.5f; |
1056 | 1058 | ||
1057 | // temporary initializer | 1059 | // temporary initializer |
1058 | float hfvalue = (float)m_regInfo.RegionSettings.WaterHeight; | 1060 | float hfvalue = (float)m_regInfo.RegionSettings.WaterHeight; |
1059 | float hfvaluecompare = hfvalue; | 1061 | float hfvaluecompare = hfvalue; |
1060 | float hfdiff = hfvalue; | 1062 | float hfdiff = hfvalue; |
1061 | int hfdiffi = 0; | 1063 | int hfdiffi = 0; |
1062 | 1064 | ||
1063 | 1065 | ||
1064 | for (int x = 0; x < 256; x++) | 1066 | for (int x = 0; x < 256; x++) |
1065 | { | 1067 | { |
@@ -1088,7 +1090,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
1088 | 1090 | ||
1089 | if (heightvalue > (float)m_regInfo.RegionSettings.WaterHeight) | 1091 | if (heightvalue > (float)m_regInfo.RegionSettings.WaterHeight) |
1090 | { | 1092 | { |
1091 | 1093 | ||
1092 | // scale height value | 1094 | // scale height value |
1093 | heightvalue = low + mid * (heightvalue - low) / mid; | 1095 | heightvalue = low + mid * (heightvalue - low) / mid; |
1094 | 1096 | ||
@@ -1115,7 +1117,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
1115 | { | 1117 | { |
1116 | hfvalue = (float)hm[x, y]; | 1118 | hfvalue = (float)hm[x, y]; |
1117 | hfvaluecompare = (float)hm[x - 1, y - 1]; | 1119 | hfvaluecompare = (float)hm[x - 1, y - 1]; |
1118 | 1120 | ||
1119 | if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue)) | 1121 | if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue)) |
1120 | hfvalue = 0; | 1122 | hfvalue = 0; |
1121 | 1123 | ||
@@ -1133,7 +1135,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
1133 | // We have to desaturate and blacken the land at the same time | 1135 | // We have to desaturate and blacken the land at the same time |
1134 | // we use floats, colors use bytes, so shrink are space down to | 1136 | // we use floats, colors use bytes, so shrink are space down to |
1135 | // 0-255 | 1137 | // 0-255 |
1136 | 1138 | ||
1137 | 1139 | ||
1138 | try | 1140 | try |
1139 | { | 1141 | { |
@@ -1148,7 +1150,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
1148 | m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString()); | 1150 | m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString()); |
1149 | ShadowDebugContinue = false; | 1151 | ShadowDebugContinue = false; |
1150 | } | 1152 | } |
1151 | 1153 | ||
1152 | if (ShadowDebugContinue) | 1154 | if (ShadowDebugContinue) |
1153 | { | 1155 | { |
1154 | if ((256 - y) - 1 > 0) | 1156 | if ((256 - y) - 1 > 0) |
@@ -1164,13 +1166,13 @@ namespace OpenSim.Region.Environment.Scenes | |||
1164 | mapbmp.SetPixel(x - 1, (256 - y) - 1, Shade); | 1166 | mapbmp.SetPixel(x - 1, (256 - y) - 1, Shade); |
1165 | } | 1167 | } |
1166 | } | 1168 | } |
1167 | 1169 | ||
1168 | 1170 | ||
1169 | } | 1171 | } |
1170 | 1172 | ||
1171 | } | 1173 | } |
1172 | 1174 | ||
1173 | 1175 | ||
1174 | 1176 | ||
1175 | 1177 | ||
1176 | } | 1178 | } |
@@ -1178,7 +1180,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
1178 | { | 1180 | { |
1179 | if (!terraincorruptedwarningsaid) | 1181 | if (!terraincorruptedwarningsaid) |
1180 | { | 1182 | { |
1181 | m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level",RegionInfo.RegionName); | 1183 | m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", RegionInfo.RegionName); |
1182 | terraincorruptedwarningsaid = true; | 1184 | terraincorruptedwarningsaid = true; |
1183 | } | 1185 | } |
1184 | Color black = Color.Black; | 1186 | Color black = Color.Black; |
@@ -1262,7 +1264,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
1262 | if (part == null) | 1264 | if (part == null) |
1263 | continue; | 1265 | continue; |
1264 | 1266 | ||
1265 | 1267 | ||
1266 | // Draw if the object is at least 1 meter wide in any direction | 1268 | // Draw if the object is at least 1 meter wide in any direction |
1267 | if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) | 1269 | if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) |
1268 | { | 1270 | { |
@@ -1278,8 +1280,8 @@ namespace OpenSim.Region.Environment.Scenes | |||
1278 | 1280 | ||
1279 | if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree) | 1281 | if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree) |
1280 | continue; // eliminates trees from this since we don't really have a good tree representation | 1282 | continue; // eliminates trees from this since we don't really have a good tree representation |
1281 | // if you want tree blocks on the map comment the above line and uncomment the below line | 1283 | // if you want tree blocks on the map comment the above line and uncomment the below line |
1282 | //mapdotspot = Color.PaleGreen; | 1284 | //mapdotspot = Color.PaleGreen; |
1283 | 1285 | ||
1284 | if (part.Shape.Textures == null) | 1286 | if (part.Shape.Textures == null) |
1285 | continue; | 1287 | continue; |
@@ -1410,106 +1412,76 @@ namespace OpenSim.Region.Environment.Scenes | |||
1410 | return; | 1412 | return; |
1411 | } | 1413 | } |
1412 | 1414 | ||
1413 | LLUUID lastMapRegionUUID = m_regInfo.lastMapUUID; | 1415 | LazySaveGeneratedMaptile(data,temporary); |
1414 | 1416 | ||
1415 | int lastMapRefresh = 0; | 1417 | #endregion |
1416 | int twoDays = 172800; | 1418 | } |
1417 | int RefreshSeconds = twoDays; | 1419 | else |
1418 | 1420 | { | |
1419 | try | 1421 | // Use the module to generate the maptile. |
1420 | { | 1422 | byte[] data = terrain.WriteJpeg2000Image("defaultstripe.png"); |
1421 | lastMapRefresh = Convert.ToInt32(m_regInfo.lastMapRefresh); | 1423 | if (data != null) |
1422 | } | ||
1423 | catch (ArgumentException) | ||
1424 | { | ||
1425 | } | ||
1426 | catch (FormatException) | ||
1427 | { | ||
1428 | } | ||
1429 | catch (OverflowException) | ||
1430 | { | 1424 | { |
1425 | LazySaveGeneratedMaptile(data,temporary); | ||
1431 | } | 1426 | } |
1427 | } | ||
1428 | } | ||
1429 | public void LazySaveGeneratedMaptile(byte[] data, bool temporary) | ||
1430 | { | ||
1431 | // Overwrites the local Asset cache with new maptile data | ||
1432 | // Assets are single write, this causes the asset server to ignore this update, | ||
1433 | // but the local asset cache does not | ||
1432 | 1434 | ||
1433 | LLUUID TerrainImageLLUUID = LLUUID.Random(); | 1435 | // this is on purpose! The net result of this is the region always has the most up to date |
1436 | // map tile while protecting the (grid) asset database from bloat caused by a new asset each | ||
1437 | // time a mapimage is generated! | ||
1438 | |||
1439 | LLUUID lastMapRegionUUID = m_regInfo.lastMapUUID; | ||
1434 | 1440 | ||
1435 | if (lastMapRegionUUID == LLUUID.Zero || (lastMapRefresh + RefreshSeconds) < Util.UnixTimeSinceEpoch()) | 1441 | int lastMapRefresh = 0; |
1436 | { | 1442 | int twoDays = 172800; |
1437 | m_regInfo.SaveLastMapUUID(TerrainImageLLUUID); | 1443 | int RefreshSeconds = twoDays; |
1438 | 1444 | ||
1439 | m_log.Warn("[MAPTILE]: STORING MAPTILE IMAGE"); | 1445 | try |
1440 | //Extra protection.. probably not needed. | 1446 | { |
1441 | } | 1447 | lastMapRefresh = Convert.ToInt32(m_regInfo.lastMapRefresh); |
1442 | else | 1448 | } |
1443 | { | 1449 | catch (ArgumentException) |
1444 | TerrainImageLLUUID = lastMapRegionUUID; | 1450 | { |
1445 | m_log.Warn("[MAPTILE]: REUSING OLD MAPTILE IMAGE ID"); | 1451 | } |
1446 | } | 1452 | catch (FormatException) |
1453 | { | ||
1454 | } | ||
1455 | catch (OverflowException) | ||
1456 | { | ||
1457 | } | ||
1447 | 1458 | ||
1448 | m_regInfo.RegionSettings.TerrainImageID = TerrainImageLLUUID; | 1459 | LLUUID TerrainImageLLUUID = LLUUID.Random(); |
1449 | 1460 | ||
1450 | AssetBase asset = new AssetBase(); | 1461 | if (lastMapRegionUUID == LLUUID.Zero || (lastMapRefresh + RefreshSeconds) < Util.UnixTimeSinceEpoch()) |
1451 | asset.FullID = m_regInfo.RegionSettings.TerrainImageID; | 1462 | { |
1452 | asset.Data = data; | 1463 | m_regInfo.SaveLastMapUUID(TerrainImageLLUUID); |
1453 | asset.Name = "terrainImage_" + m_regInfo.RegionID.ToString() + "_" + lastMapRefresh.ToString(); | ||
1454 | asset.Description = RegionInfo.RegionName; | ||
1455 | 1464 | ||
1456 | asset.Type = 0; | 1465 | m_log.Warn("[MAPTILE]: STORING MAPTILE IMAGE"); |
1457 | asset.Temporary = temporary; | ||
1458 | AssetCache.AddAsset(asset); | ||
1459 | } | 1466 | } |
1460 | else | 1467 | else |
1461 | { | 1468 | { |
1462 | byte[] data = terrain.WriteJpeg2000Image("defaultstripe.png"); | 1469 | TerrainImageLLUUID = lastMapRegionUUID; |
1463 | if (data != null) | 1470 | m_log.Warn("[MAPTILE]: REUSING OLD MAPTILE IMAGE ID"); |
1464 | { | 1471 | } |
1465 | LLUUID lastMapRegionUUID = m_regInfo.lastMapUUID; | ||
1466 | |||
1467 | int lastMapRefresh = 0; | ||
1468 | int twoDays = 172800; | ||
1469 | int RefreshSeconds = twoDays; | ||
1470 | |||
1471 | try | ||
1472 | { | ||
1473 | lastMapRefresh = Convert.ToInt32(m_regInfo.lastMapRefresh); | ||
1474 | } | ||
1475 | catch (ArgumentException) | ||
1476 | { | ||
1477 | } | ||
1478 | catch (FormatException) | ||
1479 | { | ||
1480 | } | ||
1481 | catch (OverflowException) | ||
1482 | { | ||
1483 | } | ||
1484 | |||
1485 | LLUUID TerrainImageLLUUID = LLUUID.Random(); | ||
1486 | |||
1487 | if (lastMapRegionUUID == LLUUID.Zero || (lastMapRefresh + RefreshSeconds) < Util.UnixTimeSinceEpoch()) | ||
1488 | { | ||
1489 | m_regInfo.SaveLastMapUUID(TerrainImageLLUUID); | ||
1490 | 1472 | ||
1491 | //m_log.Warn(terrainImageID); | 1473 | m_regInfo.RegionSettings.TerrainImageID = TerrainImageLLUUID; |
1492 | //Extra protection.. probably not needed. | ||
1493 | } | ||
1494 | else | ||
1495 | { | ||
1496 | TerrainImageLLUUID = lastMapRegionUUID; | ||
1497 | } | ||
1498 | 1474 | ||
1499 | m_regInfo.RegionSettings.TerrainImageID = TerrainImageLLUUID; | 1475 | AssetBase asset = new AssetBase(); |
1476 | asset.FullID = m_regInfo.RegionSettings.TerrainImageID; | ||
1477 | asset.Data = data; | ||
1478 | asset.Name = "terrainImage_" + m_regInfo.RegionID.ToString() + "_" + lastMapRefresh.ToString(); | ||
1479 | asset.Description = RegionInfo.RegionName; | ||
1500 | 1480 | ||
1501 | AssetBase asset = new AssetBase(); | 1481 | asset.Type = 0; |
1502 | asset.FullID = m_regInfo.RegionSettings.TerrainImageID; | 1482 | asset.Temporary = temporary; |
1503 | asset.Data = data; | 1483 | AssetCache.AddAsset(asset); |
1504 | asset.Name = "terrainImage_" + m_regInfo.RegionID.ToString() + "_" + lastMapRefresh.ToString(); | ||
1505 | asset.Description = RegionInfo.RegionName; | ||
1506 | asset.Type = 0; | ||
1507 | asset.Temporary = temporary; | ||
1508 | AssetCache.AddAsset(asset); | ||
1509 | } | ||
1510 | } | ||
1511 | } | 1484 | } |
1512 | |||
1513 | #endregion | 1485 | #endregion |
1514 | 1486 | ||
1515 | #region Load Land | 1487 | #region Load Land |