diff options
Diffstat (limited to 'OpenSim/Services/MapImageService')
-rw-r--r-- | OpenSim/Services/MapImageService/MapImageService.cs | 155 |
1 files changed, 125 insertions, 30 deletions
diff --git a/OpenSim/Services/MapImageService/MapImageService.cs b/OpenSim/Services/MapImageService/MapImageService.cs index a816411..fcace3a 100644 --- a/OpenSim/Services/MapImageService/MapImageService.cs +++ b/OpenSim/Services/MapImageService/MapImageService.cs | |||
@@ -69,6 +69,8 @@ namespace OpenSim.Services.MapImageService | |||
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 | { |
@@ -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 | { |
@@ -117,6 +131,7 @@ namespace OpenSim.Services.MapImageService | |||
117 | return false; | 131 | return false; |
118 | } | 132 | } |
119 | } | 133 | } |
134 | <<<<<<< HEAD | ||
120 | 135 | ||
121 | return UpdateMultiResolutionFilesAsync(x, y, out reason); | 136 | return UpdateMultiResolutionFilesAsync(x, y, out reason); |
122 | } | 137 | } |
@@ -125,24 +140,49 @@ namespace OpenSim.Services.MapImageService | |||
125 | { | 140 | { |
126 | reason = String.Empty; | 141 | reason = String.Empty; |
127 | string fileName = GetFileName(1, x, y); | 142 | string fileName = GetFileName(1, x, y); |
143 | ======= | ||
144 | |||
145 | return UpdateMultiResolutionFiles(x, y, scopeID, out reason); | ||
146 | } | ||
147 | |||
148 | public bool RemoveMapTile(int x, int y, UUID scopeID, out string reason) | ||
149 | { | ||
150 | reason = String.Empty; | ||
151 | string fileName = GetFileName(1, x, y, scopeID); | ||
152 | >>>>>>> avn/ubitvar | ||
128 | 153 | ||
129 | lock (m_Sync) | 154 | lock (m_Sync) |
130 | { | 155 | { |
131 | try | 156 | try |
157 | <<<<<<< HEAD | ||
132 | { | 158 | { |
133 | File.Delete(fileName); | 159 | File.Delete(fileName); |
134 | } | 160 | } |
135 | catch (Exception e) | 161 | catch (Exception e) |
136 | { | 162 | { |
163 | ======= | ||
164 | { | ||
165 | File.Delete(fileName); | ||
166 | } | ||
167 | catch (Exception e) | ||
168 | { | ||
169 | >>>>>>> avn/ubitvar | ||
137 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save delete file {0}: {1}", fileName, e); | 170 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save delete file {0}: {1}", fileName, e); |
138 | reason = e.Message; | 171 | reason = e.Message; |
139 | return false; | 172 | return false; |
140 | } | 173 | } |
141 | } | 174 | } |
175 | <<<<<<< HEAD | ||
142 | 176 | ||
143 | return UpdateMultiResolutionFilesAsync(x, y, out reason); | 177 | return UpdateMultiResolutionFilesAsync(x, y, out reason); |
144 | } | 178 | } |
145 | 179 | ||
180 | ======= | ||
181 | |||
182 | return UpdateMultiResolutionFiles(x, y, scopeID, out reason); | ||
183 | } | ||
184 | |||
185 | >>>>>>> avn/ubitvar | ||
146 | // When large varregions start up, they can send piles of new map tiles. This causes | 186 | // 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 | 187 | // 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 | 188 | // time to be spent creating multi-resolution tiles that will be replaced when |
@@ -151,6 +191,7 @@ namespace OpenSim.Services.MapImageService | |||
151 | { | 191 | { |
152 | public int xx; | 192 | public int xx; |
153 | public int yy; | 193 | public int yy; |
194 | <<<<<<< HEAD | ||
154 | public mapToMultiRez(int pX, int pY) | 195 | public mapToMultiRez(int pX, int pY) |
155 | { | 196 | { |
156 | xx = pX; | 197 | xx = pX; |
@@ -168,6 +209,29 @@ namespace OpenSim.Services.MapImageService | |||
168 | if (multiRezToBuild.Count == 1) | 209 | if (multiRezToBuild.Count == 1) |
169 | Util.FireAndForget( | 210 | Util.FireAndForget( |
170 | DoUpdateMultiResolutionFilesAsync, null, "MapImageService.DoUpdateMultiResolutionFilesAsync"); | 211 | DoUpdateMultiResolutionFilesAsync, null, "MapImageService.DoUpdateMultiResolutionFilesAsync"); |
212 | ======= | ||
213 | public UUID scopeID; | ||
214 | public mapToMultiRez(int pX, int pY, UUID pscopeID) | ||
215 | { | ||
216 | xx = pX; | ||
217 | yy = pY; | ||
218 | scopeID = pscopeID; | ||
219 | } | ||
220 | }; | ||
221 | private Queue<mapToMultiRez> multiRezToBuild = new Queue<mapToMultiRez>(); | ||
222 | |||
223 | private bool UpdateMultiResolutionFiles(int x, int y, UUID scopeID, out string reason) | ||
224 | { | ||
225 | reason = String.Empty; | ||
226 | |||
227 | lock (multiRezToBuild) | ||
228 | { | ||
229 | // m_log.DebugFormat("{0} UpdateMultiResolutionFilesAsync: scheduling update for <{1},{2}>", LogHeader, x, y); | ||
230 | multiRezToBuild.Enqueue(new mapToMultiRez(x, y, scopeID)); | ||
231 | if (multiRezToBuild.Count == 1) | ||
232 | Util.FireAndForget( | ||
233 | DoUpdateMultiResolutionFilesAsync); | ||
234 | >>>>>>> avn/ubitvar | ||
171 | } | 235 | } |
172 | 236 | ||
173 | return true; | 237 | return true; |
@@ -175,10 +239,15 @@ namespace OpenSim.Services.MapImageService | |||
175 | 239 | ||
176 | private void DoUpdateMultiResolutionFilesAsync(object o) | 240 | private void DoUpdateMultiResolutionFilesAsync(object o) |
177 | { | 241 | { |
242 | <<<<<<< HEAD | ||
178 | // This sleep causes the FireAndForget thread to be different than the invocation thread. | 243 | // This sleep causes the FireAndForget thread to be different than the invocation thread. |
179 | // It also allows other tiles to be uploaded so the multi-rez images are more likely | 244 | // It also allows other tiles to be uploaded so the multi-rez images are more likely |
180 | // to be correct. | 245 | // to be correct. |
181 | Thread.Sleep(1 * 1000); | 246 | Thread.Sleep(1 * 1000); |
247 | ======= | ||
248 | // let acumulate large region tiles | ||
249 | Thread.Sleep(60 * 1000); // large regions take time to upload tiles | ||
250 | >>>>>>> avn/ubitvar | ||
182 | 251 | ||
183 | while (multiRezToBuild.Count > 0) | 252 | while (multiRezToBuild.Count > 0) |
184 | { | 253 | { |
@@ -192,20 +261,35 @@ namespace OpenSim.Services.MapImageService | |||
192 | { | 261 | { |
193 | int x = toMultiRez.xx; | 262 | int x = toMultiRez.xx; |
194 | int y = toMultiRez.yy; | 263 | int y = toMultiRez.yy; |
264 | <<<<<<< HEAD | ||
265 | // m_log.DebugFormat("{0} DoUpdateMultiResolutionFilesAsync: doing build for <{1},{2}>", LogHeader, x, y); | ||
266 | |||
267 | ======= | ||
268 | UUID scopeID = toMultiRez.scopeID; | ||
195 | // m_log.DebugFormat("{0} DoUpdateMultiResolutionFilesAsync: doing build for <{1},{2}>", LogHeader, x, y); | 269 | // m_log.DebugFormat("{0} DoUpdateMultiResolutionFilesAsync: doing build for <{1},{2}>", LogHeader, x, y); |
196 | 270 | ||
271 | int width = 1; | ||
272 | >>>>>>> avn/ubitvar | ||
197 | // Stitch seven more aggregate tiles together | 273 | // Stitch seven more aggregate tiles together |
198 | for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++) | 274 | for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++) |
199 | { | 275 | { |
200 | // Calculate the width (in full resolution tiles) and bottom-left | 276 | // Calculate the width (in full resolution tiles) and bottom-left |
201 | // corner of the current zoom level | 277 | // corner of the current zoom level |
278 | <<<<<<< HEAD | ||
202 | int width = (int)Math.Pow(2, (double)(zoomLevel - 1)); | 279 | int width = (int)Math.Pow(2, (double)(zoomLevel - 1)); |
280 | ======= | ||
281 | width *= 2; | ||
282 | >>>>>>> avn/ubitvar | ||
203 | int x1 = x - (x % width); | 283 | int x1 = x - (x % width); |
204 | int y1 = y - (y % width); | 284 | int y1 = y - (y % width); |
205 | 285 | ||
206 | lock (m_Sync) // must lock the reading and writing of the maptile files | 286 | lock (m_Sync) // must lock the reading and writing of the maptile files |
207 | { | 287 | { |
288 | <<<<<<< HEAD | ||
208 | if (!CreateTile(zoomLevel, x1, y1)) | 289 | if (!CreateTile(zoomLevel, x1, y1)) |
290 | ======= | ||
291 | if (!CreateTile(zoomLevel, x1, y1, scopeID)) | ||
292 | >>>>>>> avn/ubitvar | ||
209 | { | 293 | { |
210 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel); | 294 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel); |
211 | return; | 295 | return; |
@@ -214,25 +298,29 @@ namespace OpenSim.Services.MapImageService | |||
214 | } | 298 | } |
215 | } | 299 | } |
216 | } | 300 | } |
301 | <<<<<<< HEAD | ||
217 | 302 | ||
303 | ======= | ||
304 | >>>>>>> avn/ubitvar | ||
218 | return; | 305 | return; |
219 | } | 306 | } |
220 | 307 | ||
221 | public byte[] GetMapTile(string fileName, out string format) | 308 | public byte[] GetMapTile(string fileName, UUID scopeID, out string format) |
222 | { | 309 | { |
223 | // m_log.DebugFormat("[MAP IMAGE SERVICE]: Getting map tile {0}", fileName); | 310 | // m_log.DebugFormat("[MAP IMAGE SERVICE]: Getting map tile {0}", fileName); |
224 | 311 | ||
225 | format = ".jpg"; | 312 | format = ".jpg"; |
226 | string fullName = Path.Combine(m_TilesStoragePath, fileName); | 313 | string fullName = Path.Combine(m_TilesStoragePath, scopeID.ToString()); |
314 | fullName = Path.Combine(fullName, fileName); | ||
227 | if (File.Exists(fullName)) | 315 | if (File.Exists(fullName)) |
228 | { | 316 | { |
229 | format = Path.GetExtension(fileName).ToLower(); | 317 | format = Path.GetExtension(fileName).ToLower(); |
230 | //m_log.DebugFormat("[MAP IMAGE SERVICE]: Found file {0}, extension {1}", fileName, format); | 318 | //m_log.DebugFormat("[MAP IMAGE SERVICE]: Found file {0}, extension {1}", fileName, format); |
231 | return File.ReadAllBytes(fullName); | 319 | return File.ReadAllBytes(fullName); |
232 | } | 320 | } |
233 | else if (File.Exists(m_WaterTileFile)) | 321 | else if (m_WaterBytes != null) |
234 | { | 322 | { |
235 | return File.ReadAllBytes(m_WaterTileFile); | 323 | return (byte[])m_WaterBytes.Clone(); |
236 | } | 324 | } |
237 | else | 325 | else |
238 | { | 326 | { |
@@ -244,10 +332,12 @@ namespace OpenSim.Services.MapImageService | |||
244 | #endregion | 332 | #endregion |
245 | 333 | ||
246 | 334 | ||
247 | private string GetFileName(uint zoomLevel, int x, int y) | 335 | private string GetFileName(uint zoomLevel, int x, int y, UUID scopeID) |
248 | { | 336 | { |
249 | string extension = "jpg"; | 337 | string extension = "jpg"; |
250 | return Path.Combine(m_TilesStoragePath, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension)); | 338 | string path = Path.Combine(m_TilesStoragePath, scopeID.ToString()); |
339 | Directory.CreateDirectory(path); | ||
340 | return Path.Combine(path, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension)); | ||
251 | } | 341 | } |
252 | 342 | ||
253 | private Bitmap GetInputTileImage(string fileName) | 343 | private Bitmap GetInputTileImage(string fileName) |
@@ -276,7 +366,7 @@ namespace OpenSim.Services.MapImageService | |||
276 | { | 366 | { |
277 | // Create a new output tile with a transparent background | 367 | // Create a new output tile with a transparent background |
278 | Bitmap bm = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH, PixelFormat.Format24bppRgb); | 368 | Bitmap bm = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH, PixelFormat.Format24bppRgb); |
279 | bm.MakeTransparent(); | 369 | //bm.MakeTransparent(); // 24bpp does not have transparency, this whould make it 32bpp |
280 | return bm; | 370 | return bm; |
281 | } | 371 | } |
282 | } | 372 | } |
@@ -288,7 +378,7 @@ namespace OpenSim.Services.MapImageService | |||
288 | return null; | 378 | return null; |
289 | } | 379 | } |
290 | 380 | ||
291 | private bool CreateTile(uint zoomLevel, int x, int y) | 381 | private bool CreateTile(uint zoomLevel, int x, int y, UUID scopeID) |
292 | { | 382 | { |
293 | // m_log.DebugFormat("[MAP IMAGE SERVICE]: Create tile for {0} {1}, zoom {2}", x, y, zoomLevel); | 383 | // 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); | 384 | int prevWidth = (int)Math.Pow(2, (double)zoomLevel - 2); |
@@ -303,55 +393,60 @@ namespace OpenSim.Services.MapImageService | |||
303 | int yOut = y - (y % thisWidth); | 393 | int yOut = y - (y % thisWidth); |
304 | 394 | ||
305 | // Try to open the four input tiles from the previous zoom level | 395 | // Try to open the four input tiles from the previous zoom level |
306 | Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn)); | 396 | Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn, scopeID)); |
307 | Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn)); | 397 | Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn, scopeID)); |
308 | Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth)); | 398 | Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth, scopeID)); |
309 | Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth)); | 399 | Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth, scopeID)); |
310 | 400 | ||
311 | // Open the output tile (current zoom level) | 401 | // Open the output tile (current zoom level) |
312 | string outputFile = GetFileName(zoomLevel, xOut, yOut); | 402 | string outputFile = GetFileName(zoomLevel, xOut, yOut, scopeID); |
313 | Bitmap output = GetOutputTileImage(outputFile); | 403 | |
314 | if (output == null) | 404 | int ntiles = 0; |
315 | return false; | 405 | Bitmap output = (Bitmap)m_WaterBitmap.Clone(); |
316 | FillImage(output, m_Watercolor); | ||
317 | 406 | ||
318 | if (inputBL != null) | 407 | if (inputBL != null) |
319 | { | 408 | { |
320 | ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0); | 409 | ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0); |
321 | inputBL.Dispose(); | 410 | inputBL.Dispose(); |
411 | ntiles++; | ||
322 | } | 412 | } |
323 | if (inputBR != null) | 413 | if (inputBR != null) |
324 | { | 414 | { |
325 | ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0); | 415 | ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0); |
326 | inputBR.Dispose(); | 416 | inputBR.Dispose(); |
417 | ntiles++; | ||
327 | } | 418 | } |
328 | if (inputTL != null) | 419 | if (inputTL != null) |
329 | { | 420 | { |
330 | ImageCopyResampled(output, inputTL, 0, 0, 0, 0); | 421 | ImageCopyResampled(output, inputTL, 0, 0, 0, 0); |
331 | inputTL.Dispose(); | 422 | inputTL.Dispose(); |
423 | ntiles++; | ||
332 | } | 424 | } |
333 | if (inputTR != null) | 425 | if (inputTR != null) |
334 | { | 426 | { |
335 | ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0); | 427 | ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0); |
336 | inputTR.Dispose(); | 428 | inputTR.Dispose(); |
429 | ntiles++; | ||
337 | } | 430 | } |
338 | 431 | ||
339 | // Write the modified output | 432 | // Write the modified output |
340 | try | 433 | if (ntiles == 0) |
434 | File.Delete(outputFile); | ||
435 | |||
436 | else | ||
341 | { | 437 | { |
342 | using (Bitmap final = new Bitmap(output)) | 438 | |
439 | try | ||
343 | { | 440 | { |
344 | output.Dispose(); | 441 | output.Save(outputFile, ImageFormat.Jpeg); |
345 | final.Save(outputFile, ImageFormat.Jpeg); | ||
346 | } | 442 | } |
347 | } | 443 | catch (Exception e) |
348 | catch (Exception e) | 444 | { |
349 | { | 445 | 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); | 446 | } |
351 | } | 447 | } // Save also as png? |
352 | |||
353 | // Save also as png? | ||
354 | 448 | ||
449 | output.Dispose(); | ||
355 | return true; | 450 | return true; |
356 | } | 451 | } |
357 | 452 | ||