aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-08-28 23:06:53 +0100
committerJustin Clark-Casey (justincc)2012-08-28 23:06:53 +0100
commitc1cece4b82d24a17a09b66c9ec3975190cc05d95 (patch)
tree702963505eb8a359d9e0ce6f92964b3a03ac3cbe /OpenSim
parentAdd IDynamicTextureManager.ConvertData() to match AsyncConvertData(). Remove... (diff)
downloadopensim-SC_OLD-c1cece4b82d24a17a09b66c9ec3975190cc05d95.zip
opensim-SC_OLD-c1cece4b82d24a17a09b66c9ec3975190cc05d95.tar.gz
opensim-SC_OLD-c1cece4b82d24a17a09b66c9ec3975190cc05d95.tar.bz2
opensim-SC_OLD-c1cece4b82d24a17a09b66c9ec3975190cc05d95.tar.xz
Add experimental DynamicTextureModule.ReuseTextures flag, currently only configurable on compile.
Disabled (status quo) by default. This flag makes the dynamic texture module reuse cache previously dynamically generated textures given the same input commands and extra params for 24 hours. This occurs as long as those commands would always generate the same texture (e.g. they do not contain commands to fetch data from the web). This makes texture changing faster as a viewer-cached texture uuid is sent and may reduce simulator load in regions with generation of lots of dynamic textures. A downside is that this stops expiry of old temporary dynamic textures from the cache, Another downside is that a jpeg2000 generation that partially failed is currently not regenerated until restart or after 24 hours.
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs169
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs125
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs48
-rw-r--r--OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs14
5 files changed, 310 insertions, 56 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
index 18bd018..13b7498 100644
--- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
@@ -49,6 +49,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
49 public const int DISP_EXPIRE = 1; 49 public const int DISP_EXPIRE = 1;
50 public const int DISP_TEMP = 2; 50 public const int DISP_TEMP = 2;
51 51
52 /// <summary>
53 /// If true then where possible dynamic textures are reused.
54 /// </summary>
55 public bool ReuseTextures { get; set; }
56
52 private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>(); 57 private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>();
53 58
54 private Dictionary<string, IDynamicTextureRender> RenderPlugins = 59 private Dictionary<string, IDynamicTextureRender> RenderPlugins =
@@ -56,6 +61,15 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
56 61
57 private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>(); 62 private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>();
58 63
64 /// <summary>
65 /// Record dynamic textures that we can reuse for a given data and parameter combination rather than
66 /// regenerate.
67 /// </summary>
68 /// <remarks>
69 /// Key is string.Format("{0}{1}", data
70 /// </remarks>
71 private Cache m_reuseableDynamicTextures;
72
59 #region IDynamicTextureManager Members 73 #region IDynamicTextureManager Members
60 74
61 public void RegisterRender(string handleType, IDynamicTextureRender render) 75 public void RegisterRender(string handleType, IDynamicTextureRender render)
@@ -71,7 +85,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
71 /// </summary> 85 /// </summary>
72 /// <param name="id"></param> 86 /// <param name="id"></param>
73 /// <param name="data"></param> 87 /// <param name="data"></param>
74 public void ReturnData(UUID id, byte[] data) 88 /// <param name="isReuseable">True if the data generated can be reused for subsequent identical requests</param>
89 public void ReturnData(UUID id, byte[] data, bool isReuseable)
75 { 90 {
76 DynamicTextureUpdater updater = null; 91 DynamicTextureUpdater updater = null;
77 92
@@ -88,7 +103,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
88 if (RegisteredScenes.ContainsKey(updater.SimUUID)) 103 if (RegisteredScenes.ContainsKey(updater.SimUUID))
89 { 104 {
90 Scene scene = RegisteredScenes[updater.SimUUID]; 105 Scene scene = RegisteredScenes[updater.SimUUID];
91 updater.DataReceived(data, scene); 106 UUID newTextureID = updater.DataReceived(data, scene);
107
108 if (ReuseTextures && isReuseable && !updater.BlendWithOldTexture)
109 m_reuseableDynamicTextures.Store(
110 GenerateReusableTextureKey(updater.BodyData, updater.Params), newTextureID);
92 } 111 }
93 } 112 }
94 113
@@ -169,6 +188,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
169 { 188 {
170 if (RenderPlugins.ContainsKey(contentType)) 189 if (RenderPlugins.ContainsKey(contentType))
171 { 190 {
191 // If we want to reuse dynamic textures then we have to ignore any request from the caller to expire
192 // them.
193 if (ReuseTextures)
194 disp = disp & ~DISP_EXPIRE;
195
172 DynamicTextureUpdater updater = new DynamicTextureUpdater(); 196 DynamicTextureUpdater updater = new DynamicTextureUpdater();
173 updater.SimUUID = simID; 197 updater.SimUUID = simID;
174 updater.PrimID = primID; 198 updater.PrimID = primID;
@@ -183,21 +207,49 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
183 updater.Url = "Local image"; 207 updater.Url = "Local image";
184 updater.Disp = disp; 208 updater.Disp = disp;
185 209
186 lock (Updaters) 210 object reusableTextureUUID = null;
211
212 if (ReuseTextures)
213 reusableTextureUUID
214 = m_reuseableDynamicTextures.Get(GenerateReusableTextureKey(data, extraParams));
215
216 // We cannot reuse a dynamic texture if the data is going to be blended with something already there.
217 if (reusableTextureUUID == null || updater.BlendWithOldTexture)
187 { 218 {
188 if (!Updaters.ContainsKey(updater.UpdaterID)) 219 lock (Updaters)
189 { 220 {
190 Updaters.Add(updater.UpdaterID, updater); 221 if (!Updaters.ContainsKey(updater.UpdaterID))
222 {
223 Updaters.Add(updater.UpdaterID, updater);
224 }
225 }
226
227 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
228 }
229 else
230 {
231 // No need to add to updaters as the texture is always the same. Not that this functionality
232 // apppears to be implemented anyway.
233 if (RegisteredScenes.ContainsKey(updater.SimUUID))
234 {
235 SceneObjectPart part = RegisteredScenes[updater.SimUUID].GetSceneObjectPart(updater.PrimID);
236
237 if (part != null)
238 updater.UpdatePart(part, (UUID)reusableTextureUUID);
191 } 239 }
192 } 240 }
193 241
194 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
195 return updater.UpdaterID; 242 return updater.UpdaterID;
196 } 243 }
197 244
198 return UUID.Zero; 245 return UUID.Zero;
199 } 246 }
200 247
248 private string GenerateReusableTextureKey(string data, string extraParams)
249 {
250 return string.Format("{0}{1}", data, extraParams);
251 }
252
201 public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, 253 public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize,
202 out double xSize, out double ySize) 254 out double xSize, out double ySize)
203 { 255 {
@@ -224,6 +276,12 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
224 276
225 public void PostInitialise() 277 public void PostInitialise()
226 { 278 {
279// ReuseTextures = true;
280 if (ReuseTextures)
281 {
282 m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative);
283 m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0);
284 }
227 } 285 }
228 286
229 public void Close() 287 public void Close()
@@ -269,9 +327,60 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
269 } 327 }
270 328
271 /// <summary> 329 /// <summary>
330 /// Update the given part with the new texture.
331 /// </summary>
332 /// <returns>
333 /// The old texture UUID.
334 /// </returns>
335 public UUID UpdatePart(SceneObjectPart part, UUID textureID)
336 {
337 UUID oldID;
338
339 lock (part)
340 {
341 // mostly keep the values from before
342 Primitive.TextureEntry tmptex = part.Shape.Textures;
343
344 // FIXME: Need to return the appropriate ID if only a single face is replaced.
345 oldID = tmptex.DefaultTexture.TextureID;
346
347 if (Face == ALL_SIDES)
348 {
349 oldID = tmptex.DefaultTexture.TextureID;
350 tmptex.DefaultTexture.TextureID = textureID;
351 }
352 else
353 {
354 try
355 {
356 Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
357 texface.TextureID = textureID;
358 tmptex.FaceTextures[Face] = texface;
359 }
360 catch (Exception)
361 {
362 tmptex.DefaultTexture.TextureID = textureID;
363 }
364 }
365
366 // I'm pretty sure we always want to force this to true
367 // I'm pretty sure noone whats to set fullbright true if it wasn't true before.
368 // tmptex.DefaultTexture.Fullbright = true;
369
370 part.UpdateTextureEntry(tmptex.GetBytes());
371 }
372
373 return oldID;
374 }
375
376 /// <summary>
272 /// Called once new texture data has been received for this updater. 377 /// Called once new texture data has been received for this updater.
273 /// </summary> 378 /// </summary>
274 public void DataReceived(byte[] data, Scene scene) 379 /// <param name="data"></param>
380 /// <param name="scene"></param>
381 /// <param name="isReuseable">True if the data given is reuseable.</param>
382 /// <returns>The asset UUID given to the incoming data.</returns>
383 public UUID DataReceived(byte[] data, Scene scene)
275 { 384 {
276 SceneObjectPart part = scene.GetSceneObjectPart(PrimID); 385 SceneObjectPart part = scene.GetSceneObjectPart(PrimID);
277 386
@@ -281,7 +390,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
281 String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); 390 String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url);
282 scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, 391 scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say,
283 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); 392 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false);
284 return; 393
394 return UUID.Zero;
285 } 395 }
286 396
287 byte[] assetData = null; 397 byte[] assetData = null;
@@ -323,52 +433,23 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
323 cacheLayerDecode = null; 433 cacheLayerDecode = null;
324 } 434 }
325 435
326 UUID oldID = UUID.Zero; 436 UUID oldID = UpdatePart(part, asset.FullID);
327
328 lock (part)
329 {
330 // mostly keep the values from before
331 Primitive.TextureEntry tmptex = part.Shape.Textures;
332
333 // remove the old asset from the cache
334 oldID = tmptex.DefaultTexture.TextureID;
335
336 if (Face == ALL_SIDES)
337 {
338 tmptex.DefaultTexture.TextureID = asset.FullID;
339 }
340 else
341 {
342 try
343 {
344 Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
345 texface.TextureID = asset.FullID;
346 tmptex.FaceTextures[Face] = texface;
347 }
348 catch (Exception)
349 {
350 tmptex.DefaultTexture.TextureID = asset.FullID;
351 }
352 }
353
354 // I'm pretty sure we always want to force this to true
355 // I'm pretty sure noone whats to set fullbright true if it wasn't true before.
356 // tmptex.DefaultTexture.Fullbright = true;
357
358 part.UpdateTextureEntry(tmptex.GetBytes());
359 }
360 437
361 if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) 438 if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0))
362 { 439 {
363 if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString()); 440 if (oldAsset == null)
441 oldAsset = scene.AssetService.Get(oldID.ToString());
442
364 if (oldAsset != null) 443 if (oldAsset != null)
365 { 444 {
366 if (oldAsset.Temporary == true) 445 if (oldAsset.Temporary)
367 { 446 {
368 scene.AssetService.Delete(oldID.ToString()); 447 scene.AssetService.Delete(oldID.ToString());
369 } 448 }
370 } 449 }
371 } 450 }
451
452 return asset.FullID;
372 } 453 }
373 454
374 private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) 455 private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha)
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
index 6e38b3f..2b3a0f2 100644
--- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
@@ -67,6 +67,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
67 return true; 67 return true;
68 } 68 }
69 69
70// public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
71// {
72// // We don't support conversion of body data.
73// return false;
74// }
75
70 public byte[] ConvertUrl(string url, string extraParams) 76 public byte[] ConvertUrl(string url, string extraParams)
71 { 77 {
72 return null; 78 return null;
@@ -236,9 +242,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
236 stream.Close(); 242 stream.Close();
237 } 243 }
238 } 244 }
245
239 m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}", 246 m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}",
240 imageJ2000.Length, state.RequestID); 247 imageJ2000.Length, state.RequestID);
241 m_textureManager.ReturnData(state.RequestID, imageJ2000); 248
249 m_textureManager.ReturnData(state.RequestID, imageJ2000, false);
242 } 250 }
243 251
244 #region Nested type: RequestState 252 #region Nested type: RequestState
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
index 180ea9f..b50c0bd 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
@@ -51,12 +51,15 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
51 DynamicTextureModule m_dtm; 51 DynamicTextureModule m_dtm;
52 VectorRenderModule m_vrm; 52 VectorRenderModule m_vrm;
53 53
54 [SetUp] 54 private void SetupScene(bool reuseTextures)
55 public void SetUp()
56 { 55 {
57 m_scene = new SceneHelpers().SetupScene(); 56 m_scene = new SceneHelpers().SetupScene();
57
58 m_dtm = new DynamicTextureModule(); 58 m_dtm = new DynamicTextureModule();
59 m_dtm.ReuseTextures = reuseTextures;
60
59 m_vrm = new VectorRenderModule(); 61 m_vrm = new VectorRenderModule();
62
60 SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm); 63 SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm);
61 } 64 }
62 65
@@ -65,6 +68,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
65 { 68 {
66 TestHelpers.InMethod(); 69 TestHelpers.InMethod();
67 70
71 SetupScene(false);
68 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); 72 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
69 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; 73 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
70 74
@@ -86,6 +90,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
86 90
87 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; 91 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
88 92
93 SetupScene(false);
89 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); 94 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
90 95
91 m_dtm.AddDynamicTextureData( 96 m_dtm.AddDynamicTextureData(
@@ -116,6 +121,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
116 121
117 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; 122 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
118 123
124 SetupScene(false);
119 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); 125 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
120 126
121 m_dtm.AddDynamicTextureData( 127 m_dtm.AddDynamicTextureData(
@@ -147,6 +153,121 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
147 string dtText 153 string dtText
148 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; 154 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
149 155
156 SetupScene(false);
157 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
158
159 m_dtm.AddDynamicTextureData(
160 m_scene.RegionInfo.RegionID,
161 so.UUID,
162 m_vrm.GetContentType(),
163 dtText,
164 "",
165 0);
166
167 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
168
169 m_dtm.AddDynamicTextureData(
170 m_scene.RegionInfo.RegionID,
171 so.UUID,
172 m_vrm.GetContentType(),
173 dtText,
174 "",
175 0);
176
177 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
178 }
179
180 [Test]
181 public void TestDrawReusingTexture()
182 {
183 TestHelpers.InMethod();
184
185 SetupScene(true);
186 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
187 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
188
189 m_dtm.AddDynamicTextureData(
190 m_scene.RegionInfo.RegionID,
191 so.UUID,
192 m_vrm.GetContentType(),
193 "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;",
194 "",
195 0);
196
197 Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
198 }
199
200 [Test]
201 public void TestRepeatSameDrawReusingTexture()
202 {
203 TestHelpers.InMethod();
204
205 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
206
207 SetupScene(true);
208 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
209
210 m_dtm.AddDynamicTextureData(
211 m_scene.RegionInfo.RegionID,
212 so.UUID,
213 m_vrm.GetContentType(),
214 dtText,
215 "",
216 0);
217
218 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
219
220 m_dtm.AddDynamicTextureData(
221 m_scene.RegionInfo.RegionID,
222 so.UUID,
223 m_vrm.GetContentType(),
224 dtText,
225 "",
226 0);
227
228 Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
229 }
230
231 [Test]
232 public void TestRepeatSameDrawDifferentExtraParamsReusingTexture()
233 {
234 TestHelpers.InMethod();
235
236 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
237
238 SetupScene(true);
239 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
240
241 m_dtm.AddDynamicTextureData(
242 m_scene.RegionInfo.RegionID,
243 so.UUID,
244 m_vrm.GetContentType(),
245 dtText,
246 "",
247 0);
248
249 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
250
251 m_dtm.AddDynamicTextureData(
252 m_scene.RegionInfo.RegionID,
253 so.UUID,
254 m_vrm.GetContentType(),
255 dtText,
256 "alpha:250",
257 0);
258
259 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
260 }
261
262 [Test]
263 public void TestRepeatSameDrawContainingImageReusingTexture()
264 {
265 TestHelpers.InMethod();
266
267 string dtText
268 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
269
270 SetupScene(true);
150 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); 271 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
151 272
152 m_dtm.AddDynamicTextureData( 273 m_dtm.AddDynamicTextureData(
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
index 3a758c5..4268f2e 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -30,6 +30,7 @@ using System.Drawing;
30using System.Drawing.Imaging; 30using System.Drawing.Imaging;
31using System.Globalization; 31using System.Globalization;
32using System.IO; 32using System.IO;
33using System.Linq;
33using System.Net; 34using System.Net;
34using Nini.Config; 35using Nini.Config;
35using OpenMetaverse; 36using OpenMetaverse;
@@ -73,6 +74,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
73 return true; 74 return true;
74 } 75 }
75 76
77// public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
78// {
79// string[] lines = GetLines(bodyData);
80// return lines.Any((str, r) => str.StartsWith("Image"));
81// }
82
76 public byte[] ConvertUrl(string url, string extraParams) 83 public byte[] ConvertUrl(string url, string extraParams)
77 { 84 {
78 return null; 85 return null;
@@ -80,7 +87,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
80 87
81 public byte[] ConvertData(string bodyData, string extraParams) 88 public byte[] ConvertData(string bodyData, string extraParams)
82 { 89 {
83 return Draw(bodyData, extraParams); 90 bool reuseable;
91 return Draw(bodyData, extraParams, out reuseable);
92 }
93
94 private byte[] ConvertData(string bodyData, string extraParams, out bool reuseable)
95 {
96 return Draw(bodyData, extraParams, out reuseable);
84 } 97 }
85 98
86 public bool AsyncConvertUrl(UUID id, string url, string extraParams) 99 public bool AsyncConvertUrl(UUID id, string url, string extraParams)
@@ -91,7 +104,11 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
91 public bool AsyncConvertData(UUID id, string bodyData, string extraParams) 104 public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
92 { 105 {
93 // XXX: This isn't actually being done asynchronously! 106 // XXX: This isn't actually being done asynchronously!
94 m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams)); 107 bool reuseable;
108 byte[] data = ConvertData(bodyData, extraParams, out reuseable);
109
110 m_textureManager.ReturnData(id, data, reuseable);
111
95 return true; 112 return true;
96 } 113 }
97 114
@@ -162,7 +179,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
162 179
163 #endregion 180 #endregion
164 181
165 private byte[] Draw(string data, string extraParams) 182 private byte[] Draw(string data, string extraParams, out bool reuseable)
166 { 183 {
167 // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha 184 // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
168 // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255 185 // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
@@ -343,7 +360,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
343 } 360 }
344 } 361 }
345 362
346 GDIDraw(data, graph, altDataDelim); 363 GDIDraw(data, graph, altDataDelim, out reuseable);
347 } 364 }
348 365
349 byte[] imageJ2000 = new byte[0]; 366 byte[] imageJ2000 = new byte[0];
@@ -434,8 +451,21 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
434 } 451 }
435*/ 452*/
436 453
437 private void GDIDraw(string data, Graphics graph, char dataDelim) 454 /// <summary>
455 /// Split input data into discrete command lines.
456 /// </summary>
457 /// <returns></returns>
458 /// <param name='data'></param>
459 /// <param name='dataDelim'></param>
460 private string[] GetLines(string data, char dataDelim)
438 { 461 {
462 char[] lineDelimiter = { dataDelim };
463 return data.Split(lineDelimiter);
464 }
465
466 private void GDIDraw(string data, Graphics graph, char dataDelim, out bool reuseable)
467 {
468 reuseable = true;
439 Point startPoint = new Point(0, 0); 469 Point startPoint = new Point(0, 0);
440 Point endPoint = new Point(0, 0); 470 Point endPoint = new Point(0, 0);
441 Pen drawPen = null; 471 Pen drawPen = null;
@@ -450,11 +480,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
450 myFont = new Font(fontName, fontSize); 480 myFont = new Font(fontName, fontSize);
451 myBrush = new SolidBrush(Color.Black); 481 myBrush = new SolidBrush(Color.Black);
452 482
453 char[] lineDelimiter = {dataDelim};
454 char[] partsDelimiter = {','}; 483 char[] partsDelimiter = {','};
455 string[] lines = data.Split(lineDelimiter);
456 484
457 foreach (string line in lines) 485 foreach (string line in GetLines(data, dataDelim))
458 { 486 {
459 string nextLine = line.Trim(); 487 string nextLine = line.Trim();
460 //replace with switch, or even better, do some proper parsing 488 //replace with switch, or even better, do some proper parsing
@@ -485,6 +513,10 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
485 } 513 }
486 else if (nextLine.StartsWith("Image")) 514 else if (nextLine.StartsWith("Image"))
487 { 515 {
516 // We cannot reuse any generated texture involving fetching an image via HTTP since that image
517 // can change.
518 reuseable = false;
519
488 float x = 0; 520 float x = 0;
489 float y = 0; 521 float y = 0;
490 GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); 522 GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y);
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
index 773ba73..1a3bcbb 100644
--- a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
+++ b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
@@ -33,7 +33,7 @@ namespace OpenSim.Region.Framework.Interfaces
33 public interface IDynamicTextureManager 33 public interface IDynamicTextureManager
34 { 34 {
35 void RegisterRender(string handleType, IDynamicTextureRender render); 35 void RegisterRender(string handleType, IDynamicTextureRender render);
36 void ReturnData(UUID id, byte[] data); 36 void ReturnData(UUID id, byte[] data, bool isReuseable);
37 37
38 UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, 38 UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams,
39 int updateTimer); 39 int updateTimer);
@@ -113,6 +113,18 @@ namespace OpenSim.Region.Framework.Interfaces
113 string GetName(); 113 string GetName();
114 string GetContentType(); 114 string GetContentType();
115 bool SupportsAsynchronous(); 115 bool SupportsAsynchronous();
116
117// /// <summary>
118// /// Return true if converting the input body and extra params data will always result in the same byte[] array
119// /// </summary>
120// /// <remarks>
121// /// This method allows the caller to use a previously generated asset if it has one.
122// /// </remarks>
123// /// <returns></returns>
124// /// <param name='bodyData'></param>
125// /// <param name='extraParams'></param>
126// bool AlwaysIdenticalConversion(string bodyData, string extraParams);
127
116 byte[] ConvertUrl(string url, string extraParams); 128 byte[] ConvertUrl(string url, string extraParams);
117 byte[] ConvertData(string bodyData, string extraParams); 129 byte[] ConvertData(string bodyData, string extraParams);
118 bool AsyncConvertUrl(UUID id, string url, string extraParams); 130 bool AsyncConvertUrl(UUID id, string url, string extraParams);