aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/MapImageService
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Services/MapImageService/MapImageService.cs129
-rw-r--r--OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs10
2 files changed, 83 insertions, 56 deletions
diff --git a/OpenSim/Services/MapImageService/MapImageService.cs b/OpenSim/Services/MapImageService/MapImageService.cs
index 6b4a91a..e9db41d 100644
--- a/OpenSim/Services/MapImageService/MapImageService.cs
+++ b/OpenSim/Services/MapImageService/MapImageService.cs
@@ -23,8 +23,8 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * 26 *
27 * The design of this map service is based on SimianGrid's PHP-based 27 * The design of this map service is based on SimianGrid's PHP-based
28 * map service. See this URL for the original PHP version: 28 * map service. See this URL for the original PHP version:
29 * https://github.com/openmetaversefoundation/simiangrid/ 29 * https://github.com/openmetaversefoundation/simiangrid/
30 */ 30 */
@@ -63,12 +63,14 @@ namespace OpenSim.Services.MapImageService
63 private const int HALF_WIDTH = 128; 63 private const int HALF_WIDTH = 128;
64 private const int JPEG_QUALITY = 80; 64 private const int JPEG_QUALITY = 80;
65 65
66 private static string m_TilesStoragePath = "maptiles"; 66 private static string m_TilesStoragePath = Path.Combine(Util.cacheDir(), "/maptiles");
67 67
68 private static object m_Sync = new object(); 68 private static object m_Sync = new object();
69 private static bool m_Initialized = false; 69 private static bool m_Initialized = false;
70 private static string m_WaterTileFile = string.Empty; 70 private static string m_WaterTileFile = string.Empty;
71 private static Color m_Watercolor = Color.FromArgb(29, 71, 95); 71 private static Color m_Watercolor = Color.FromArgb(29, 71, 95);
72 private static Bitmap m_WaterBitmap = null;
73 private static byte[] m_WaterBytes = null;
72 74
73 public MapImageService(IConfigSource config) 75 public MapImageService(IConfigSource config)
74 { 76 {
@@ -80,7 +82,7 @@ namespace OpenSim.Services.MapImageService
80 IConfig serviceConfig = config.Configs["MapImageService"]; 82 IConfig serviceConfig = config.Configs["MapImageService"];
81 if (serviceConfig != null) 83 if (serviceConfig != null)
82 { 84 {
83 m_TilesStoragePath = "../caches/" + serviceConfig.GetString("TilesStoragePath", m_TilesStoragePath); 85 m_TilesStoragePath = serviceConfig.GetString("TilesStoragePath", m_TilesStoragePath);
84 if (!Directory.Exists(m_TilesStoragePath)) 86 if (!Directory.Exists(m_TilesStoragePath))
85 Directory.CreateDirectory(m_TilesStoragePath); 87 Directory.CreateDirectory(m_TilesStoragePath);
86 88
@@ -91,6 +93,18 @@ namespace OpenSim.Services.MapImageService
91 Bitmap waterTile = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH); 93 Bitmap waterTile = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH);
92 FillImage(waterTile, m_Watercolor); 94 FillImage(waterTile, m_Watercolor);
93 waterTile.Save(m_WaterTileFile, ImageFormat.Jpeg); 95 waterTile.Save(m_WaterTileFile, ImageFormat.Jpeg);
96 m_WaterBitmap = waterTile;
97 }
98
99 if (File.Exists(m_WaterTileFile))
100 {
101 m_WaterBitmap = new Bitmap(m_WaterTileFile);
102 using (MemoryStream ms = new MemoryStream())
103 {
104 m_WaterBitmap.Save(ms,ImageFormat.Jpeg);
105 ms.Seek(0, SeekOrigin.Begin);
106 m_WaterBytes = ms.ToArray();
107 }
94 } 108 }
95 } 109 }
96 } 110 }
@@ -98,10 +112,10 @@ namespace OpenSim.Services.MapImageService
98 112
99 #region IMapImageService 113 #region IMapImageService
100 114
101 public bool AddMapTile(int x, int y, byte[] imageData, out string reason) 115 public bool AddMapTile(int x, int y, byte[] imageData, UUID scopeID, out string reason)
102 { 116 {
103 reason = string.Empty; 117 reason = string.Empty;
104 string fileName = GetFileName(1, x, y); 118 string fileName = GetFileName(1, x, y, scopeID);
105 119
106 lock (m_Sync) 120 lock (m_Sync)
107 { 121 {
@@ -118,13 +132,13 @@ namespace OpenSim.Services.MapImageService
118 } 132 }
119 } 133 }
120 134
121 return UpdateMultiResolutionFilesAsync(x, y, out reason); 135 return UpdateMultiResolutionFiles(x, y, scopeID, out reason);
122 } 136 }
123 137
124 public bool RemoveMapTile(int x, int y, out string reason) 138 public bool RemoveMapTile(int x, int y, UUID scopeID, out string reason)
125 { 139 {
126 reason = String.Empty; 140 reason = String.Empty;
127 string fileName = GetFileName(1, x, y); 141 string fileName = GetFileName(1, x, y, scopeID);
128 142
129 lock (m_Sync) 143 lock (m_Sync)
130 { 144 {
@@ -134,15 +148,16 @@ namespace OpenSim.Services.MapImageService
134 } 148 }
135 catch (Exception e) 149 catch (Exception e)
136 { 150 {
151
137 m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save delete file {0}: {1}", fileName, e); 152 m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save delete file {0}: {1}", fileName, e);
138 reason = e.Message; 153 reason = e.Message;
139 return false; 154 return false;
140 } 155 }
141 } 156 }
142 157 return UpdateMultiResolutionFiles(x, y, scopeID, out reason);
143 return UpdateMultiResolutionFilesAsync(x, y, out reason);
144 } 158 }
145 159
160
146 // When large varregions start up, they can send piles of new map tiles. This causes 161 // When large varregions start up, they can send piles of new map tiles. This causes
147 // this multi-resolution routine to be called a zillion times an causes much CPU 162 // this multi-resolution routine to be called a zillion times an causes much CPU
148 // time to be spent creating multi-resolution tiles that will be replaced when 163 // time to be spent creating multi-resolution tiles that will be replaced when
@@ -151,23 +166,27 @@ namespace OpenSim.Services.MapImageService
151 { 166 {
152 public int xx; 167 public int xx;
153 public int yy; 168 public int yy;
154 public mapToMultiRez(int pX, int pY) 169 public UUID scopeID;
170 public mapToMultiRez(int pX, int pY, UUID pscopeID)
155 { 171 {
156 xx = pX; 172 xx = pX;
157 yy = pY; 173 yy = pY;
174 scopeID = pscopeID;
158 } 175 }
159 }; 176 };
160 private Queue<mapToMultiRez> multiRezToBuild = new Queue<mapToMultiRez>(); 177 private Queue<mapToMultiRez> multiRezToBuild = new Queue<mapToMultiRez>();
161 private bool UpdateMultiResolutionFilesAsync(int x, int y, out string reason) 178
179 private bool UpdateMultiResolutionFiles(int x, int y, UUID scopeID, out string reason)
162 { 180 {
163 reason = String.Empty; 181 reason = String.Empty;
182
164 lock (multiRezToBuild) 183 lock (multiRezToBuild)
165 { 184 {
166 // m_log.DebugFormat("{0} UpdateMultiResolutionFilesAsync: scheduling update for <{1},{2}>", LogHeader, x, y); 185 // m_log.DebugFormat("{0} UpdateMultiResolutionFilesAsync: scheduling update for <{1},{2}>", LogHeader, x, y);
167 multiRezToBuild.Enqueue(new mapToMultiRez(x, y)); 186 multiRezToBuild.Enqueue(new mapToMultiRez(x, y, scopeID));
168 if (multiRezToBuild.Count == 1) 187 if (multiRezToBuild.Count == 1)
169 Util.FireAndForget( 188 Util.FireAndForget(
170 DoUpdateMultiResolutionFilesAsync, null, "MapImageService.DoUpdateMultiResolutionFilesAsync"); 189 DoUpdateMultiResolutionFilesAsync);
171 } 190 }
172 191
173 return true; 192 return true;
@@ -175,10 +194,8 @@ namespace OpenSim.Services.MapImageService
175 194
176 private void DoUpdateMultiResolutionFilesAsync(object o) 195 private void DoUpdateMultiResolutionFilesAsync(object o)
177 { 196 {
178 // This sleep causes the FireAndForget thread to be different than the invocation thread. 197 // let acumulate large region tiles
179 // It also allows other tiles to be uploaded so the multi-rez images are more likely 198 Thread.Sleep(60 * 1000); // large regions take time to upload tiles
180 // to be correct.
181 Thread.Sleep(1 * 1000);
182 199
183 while (multiRezToBuild.Count > 0) 200 while (multiRezToBuild.Count > 0)
184 { 201 {
@@ -192,20 +209,23 @@ namespace OpenSim.Services.MapImageService
192 { 209 {
193 int x = toMultiRez.xx; 210 int x = toMultiRez.xx;
194 int y = toMultiRez.yy; 211 int y = toMultiRez.yy;
212 UUID scopeID = toMultiRez.scopeID;
195 // m_log.DebugFormat("{0} DoUpdateMultiResolutionFilesAsync: doing build for <{1},{2}>", LogHeader, x, y); 213 // m_log.DebugFormat("{0} DoUpdateMultiResolutionFilesAsync: doing build for <{1},{2}>", LogHeader, x, y);
196 214
215 int width = 1;
216
197 // Stitch seven more aggregate tiles together 217 // Stitch seven more aggregate tiles together
198 for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++) 218 for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++)
199 { 219 {
200 // Calculate the width (in full resolution tiles) and bottom-left 220 // Calculate the width (in full resolution tiles) and bottom-left
201 // corner of the current zoom level 221 // corner of the current zoom level
202 int width = (int)Math.Pow(2, (double)(zoomLevel - 1)); 222 width *= 2;
203 int x1 = x - (x % width); 223 int x1 = x - (x % width);
204 int y1 = y - (y % width); 224 int y1 = y - (y % width);
205 225
206 lock (m_Sync) // must lock the reading and writing of the maptile files 226 lock (m_Sync) // must lock the reading and writing of the maptile files
207 { 227 {
208 if (!CreateTile(zoomLevel, x1, y1)) 228 if (!CreateTile(zoomLevel, x1, y1, scopeID))
209 { 229 {
210 m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel); 230 m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel);
211 return; 231 return;
@@ -214,25 +234,25 @@ namespace OpenSim.Services.MapImageService
214 } 234 }
215 } 235 }
216 } 236 }
217
218 return; 237 return;
219 } 238 }
220 239
221 public byte[] GetMapTile(string fileName, out string format) 240 public byte[] GetMapTile(string fileName, UUID scopeID, out string format)
222 { 241 {
223// m_log.DebugFormat("[MAP IMAGE SERVICE]: Getting map tile {0}", fileName); 242// m_log.DebugFormat("[MAP IMAGE SERVICE]: Getting map tile {0}", fileName);
224 243
225 format = ".jpg"; 244 format = ".jpg";
226 string fullName = Path.Combine(m_TilesStoragePath, fileName); 245 string fullName = Path.Combine(m_TilesStoragePath, scopeID.ToString());
246 fullName = Path.Combine(fullName, fileName);
227 if (File.Exists(fullName)) 247 if (File.Exists(fullName))
228 { 248 {
229 format = Path.GetExtension(fileName).ToLower(); 249 format = Path.GetExtension(fileName).ToLower();
230 //m_log.DebugFormat("[MAP IMAGE SERVICE]: Found file {0}, extension {1}", fileName, format); 250 //m_log.DebugFormat("[MAP IMAGE SERVICE]: Found file {0}, extension {1}", fileName, format);
231 return File.ReadAllBytes(fullName); 251 return File.ReadAllBytes(fullName);
232 } 252 }
233 else if (File.Exists(m_WaterTileFile)) 253 else if (m_WaterBytes != null)
234 { 254 {
235 return File.ReadAllBytes(m_WaterTileFile); 255 return (byte[])m_WaterBytes.Clone();
236 } 256 }
237 else 257 else
238 { 258 {
@@ -244,10 +264,12 @@ namespace OpenSim.Services.MapImageService
244 #endregion 264 #endregion
245 265
246 266
247 private string GetFileName(uint zoomLevel, int x, int y) 267 private string GetFileName(uint zoomLevel, int x, int y, UUID scopeID)
248 { 268 {
249 string extension = "jpg"; 269 string extension = "jpg";
250 return Path.Combine(m_TilesStoragePath, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension)); 270 string path = Path.Combine(m_TilesStoragePath, scopeID.ToString());
271 Directory.CreateDirectory(path);
272 return Path.Combine(path, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension));
251 } 273 }
252 274
253 private Bitmap GetInputTileImage(string fileName) 275 private Bitmap GetInputTileImage(string fileName)
@@ -269,14 +291,14 @@ namespace OpenSim.Services.MapImageService
269 { 291 {
270 try 292 try
271 { 293 {
272 if (File.Exists(fileName)) 294 if (File.Exists(fileName))
273 return new Bitmap(fileName); 295 return new Bitmap(fileName);
274 296
275 else 297 else
276 { 298 {
277 // Create a new output tile with a transparent background 299 // Create a new output tile with a transparent background
278 Bitmap bm = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH, PixelFormat.Format24bppRgb); 300 Bitmap bm = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH, PixelFormat.Format24bppRgb);
279 bm.MakeTransparent(); 301 //bm.MakeTransparent(); // 24bpp does not have transparency, this would make it 32bpp
280 return bm; 302 return bm;
281 } 303 }
282 } 304 }
@@ -288,7 +310,7 @@ namespace OpenSim.Services.MapImageService
288 return null; 310 return null;
289 } 311 }
290 312
291 private bool CreateTile(uint zoomLevel, int x, int y) 313 private bool CreateTile(uint zoomLevel, int x, int y, UUID scopeID)
292 { 314 {
293// m_log.DebugFormat("[MAP IMAGE SERVICE]: Create tile for {0} {1}, zoom {2}", x, y, zoomLevel); 315// m_log.DebugFormat("[MAP IMAGE SERVICE]: Create tile for {0} {1}, zoom {2}", x, y, zoomLevel);
294 int prevWidth = (int)Math.Pow(2, (double)zoomLevel - 2); 316 int prevWidth = (int)Math.Pow(2, (double)zoomLevel - 2);
@@ -303,55 +325,60 @@ namespace OpenSim.Services.MapImageService
303 int yOut = y - (y % thisWidth); 325 int yOut = y - (y % thisWidth);
304 326
305 // Try to open the four input tiles from the previous zoom level 327 // Try to open the four input tiles from the previous zoom level
306 Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn)); 328 Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn, scopeID));
307 Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn)); 329 Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn, scopeID));
308 Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth)); 330 Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth, scopeID));
309 Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth)); 331 Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth, scopeID));
310 332
311 // Open the output tile (current zoom level) 333 // Open the output tile (current zoom level)
312 string outputFile = GetFileName(zoomLevel, xOut, yOut); 334 string outputFile = GetFileName(zoomLevel, xOut, yOut, scopeID);
313 Bitmap output = GetOutputTileImage(outputFile); 335
314 if (output == null) 336 int ntiles = 0;
315 return false; 337 Bitmap output = (Bitmap)m_WaterBitmap.Clone();
316 FillImage(output, m_Watercolor);
317 338
318 if (inputBL != null) 339 if (inputBL != null)
319 { 340 {
320 ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0); 341 ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0);
321 inputBL.Dispose(); 342 inputBL.Dispose();
343 ntiles++;
322 } 344 }
323 if (inputBR != null) 345 if (inputBR != null)
324 { 346 {
325 ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0); 347 ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0);
326 inputBR.Dispose(); 348 inputBR.Dispose();
349 ntiles++;
327 } 350 }
328 if (inputTL != null) 351 if (inputTL != null)
329 { 352 {
330 ImageCopyResampled(output, inputTL, 0, 0, 0, 0); 353 ImageCopyResampled(output, inputTL, 0, 0, 0, 0);
331 inputTL.Dispose(); 354 inputTL.Dispose();
355 ntiles++;
332 } 356 }
333 if (inputTR != null) 357 if (inputTR != null)
334 { 358 {
335 ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0); 359 ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0);
336 inputTR.Dispose(); 360 inputTR.Dispose();
361 ntiles++;
337 } 362 }
338 363
339 // Write the modified output 364 // Write the modified output
340 try 365 if (ntiles == 0)
366 File.Delete(outputFile);
367
368 else
341 { 369 {
342 using (Bitmap final = new Bitmap(output)) 370
371 try
343 { 372 {
344 output.Dispose(); 373 output.Save(outputFile, ImageFormat.Jpeg);
345 final.Save(outputFile, ImageFormat.Jpeg);
346 } 374 }
347 } 375 catch (Exception e)
348 catch (Exception e) 376 {
349 { 377 m_log.WarnFormat("[MAP IMAGE SERVICE]: Oops on saving {0} {1}", outputFile, e);
350 m_log.WarnFormat("[MAP IMAGE SERVICE]: Oops on saving {0} {1}", outputFile, e); 378 }
351 } 379 } // Save also as png?
352
353 // Save also as png?
354 380
381 output.Dispose();
355 return true; 382 return true;
356 } 383 }
357 384
diff --git a/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs b/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs
index e779238..8f4b9b9 100644
--- a/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs
@@ -2,7 +2,7 @@
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4 4
5// General Information about an assembly is controlled through the following 5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly. 7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Services.MapImageService")] 8[assembly: AssemblyTitle("OpenSim.Services.MapImageService")]
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices;
14[assembly: AssemblyTrademark("")] 14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")] 15[assembly: AssemblyCulture("")]
16 16
17// Setting ComVisible to false makes the types in this assembly not visible 17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from 18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type. 19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)] 20[assembly: ComVisible(false)]
21 21
@@ -25,9 +25,9 @@ using System.Runtime.InteropServices;
25// Version information for an assembly consists of the following four values: 25// Version information for an assembly consists of the following four values:
26// 26//
27// Major Version 27// Major Version
28// Minor Version 28// Minor Version
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.8.3.*")] 32[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
33 33