29 using System.Collections.Generic;
31 using System.Drawing.Imaging;
34 using OpenMetaverse.Imaging;
35 using OpenSim.Framework;
36 using OpenSim.Region.Framework.Interfaces;
37 using OpenSim.Region.Framework.Scenes;
39 using System.Reflection;
42 namespace OpenSim.
Region.CoreModules.Scripting.DynamicTexture
44 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"DynamicTextureModule")]
49 private const int ALL_SIDES = -1;
51 public const int DISP_EXPIRE = 1;
52 public const int DISP_TEMP = 2;
57 public bool ReuseTextures {
get; set; }
68 public bool ReuseLowDataTextures {
get; set; }
70 private Dictionary<UUID, Scene> RegisteredScenes =
new Dictionary<UUID, Scene>();
72 private Dictionary<string, IDynamicTextureRender> RenderPlugins =
73 new Dictionary<string, IDynamicTextureRender>();
75 private Dictionary<UUID, DynamicTextureUpdater> Updaters =
new Dictionary<UUID, DynamicTextureUpdater>();
84 private Cache m_reuseableDynamicTextures;
93 m_reuseableDynamicTextures.DefaultTTL =
new TimeSpan(24, 0, 0);
96 #region IDynamicTextureManager Members
100 if (!RenderPlugins.ContainsKey(handleType))
102 RenderPlugins.Add(handleType, render);
117 if (Updaters.ContainsKey(updaterId))
119 updater = Updaters[updaterId];
125 if (RegisteredScenes.ContainsKey(updater.
SimUUID))
127 Scene scene = RegisteredScenes[updater.SimUUID];
128 UUID newTextureID = updater.DataReceived(texture.Data, scene);
133 && (ReuseLowDataTextures || IsDataSizeReuseable(texture)))
135 m_reuseableDynamicTextures.Store(
145 if (!Updaters.ContainsKey(updater.
UpdaterID))
147 Updaters.Remove(updater.UpdaterID);
165 int discardLevel2DataThreshold = (int)Math.Ceiling((texture.
Size.Width >> 2) * (texture.
Size.Height >> 2) * 0.5);
171 return discardLevel2DataThreshold < texture.Data.Length;
175 string extraParams,
int updateTimer)
177 return AddDynamicTextureURL(simID, primID, contentType, url, extraParams, updateTimer,
false, 255);
181 string extraParams,
int updateTimer,
bool SetBlending, byte AlphaValue)
183 return AddDynamicTextureURL(simID, primID, contentType, url,
184 extraParams, updateTimer, SetBlending,
185 (
int)(DISP_TEMP|DISP_EXPIRE), AlphaValue, ALL_SIDES);
189 string extraParams,
int updateTimer,
bool SetBlending,
190 int disp, byte AlphaValue,
int face)
192 if (RenderPlugins.ContainsKey(contentType))
195 updater.SimUUID = simID;
196 updater.PrimID = primID;
197 updater.ContentType = contentType;
199 updater.UpdateTimer = updateTimer;
200 updater.UpdaterID = UUID.Random();
201 updater.Params = extraParams;
202 updater.BlendWithOldTexture = SetBlending;
203 updater.FrontAlpha = AlphaValue;
209 if (!Updaters.ContainsKey(updater.
UpdaterID))
211 Updaters.Add(updater.UpdaterID, updater);
215 RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams);
216 return updater.UpdaterID;
222 string extraParams,
int updateTimer)
224 return AddDynamicTextureData(simID, primID, contentType, data, extraParams, updateTimer,
false, 255);
228 string extraParams,
int updateTimer,
bool SetBlending, byte AlphaValue)
230 return AddDynamicTextureData(simID, primID, contentType, data, extraParams, updateTimer, SetBlending,
231 (
int) (DISP_TEMP|DISP_EXPIRE), AlphaValue, ALL_SIDES);
235 string extraParams,
int updateTimer,
bool SetBlending,
int disp, byte AlphaValue,
int face)
237 if (!RenderPlugins.ContainsKey(contentType))
241 RegisteredScenes.TryGetValue(simID, out scene);
254 disp = disp & ~DISP_EXPIRE;
257 updater.SimUUID = simID;
258 updater.PrimID = primID;
259 updater.ContentType = contentType;
260 updater.BodyData = data;
261 updater.UpdateTimer = updateTimer;
262 updater.UpdaterID = UUID.Random();
263 updater.Params = extraParams;
264 updater.BlendWithOldTexture = SetBlending;
265 updater.FrontAlpha = AlphaValue;
267 updater.Url =
"Local image";
270 object objReusableTextureUUID = null;
274 string reuseableTextureKey = GenerateReusableTextureKey(data, extraParams);
275 objReusableTextureUUID = m_reuseableDynamicTextures.Get(reuseableTextureKey);
277 if (objReusableTextureUUID != null)
281 if (scene.AssetService.GetMetadata(objReusableTextureUUID.ToString()) == null)
283 m_reuseableDynamicTextures.Invalidate(reuseableTextureKey);
284 objReusableTextureUUID = null;
290 if (objReusableTextureUUID == null)
294 if (!Updaters.ContainsKey(updater.
UpdaterID))
296 Updaters.Add(updater.UpdaterID, updater);
304 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
314 updater.UpdatePart(part, (
UUID)objReusableTextureUUID);
317 return updater.UpdaterID;
320 private string GenerateReusableTextureKey(
string data,
string extraParams)
322 return string.Format(
"{0}{1}", data, extraParams);
326 out
double xSize, out
double ySize)
330 if (RenderPlugins.ContainsKey(contentType))
332 RenderPlugins[contentType].GetDrawStringSize(text, fontName, fontSize, out xSize, out ySize);
338 #region ISharedRegionModule Members
342 IConfig texturesConfig = config.Configs[
"Textures"];
343 if (texturesConfig != null)
345 ReuseTextures = texturesConfig.GetBoolean(
"ReuseDynamicTextures",
false);
346 ReuseLowDataTextures = texturesConfig.GetBoolean(
"ReuseDynamicLowDataTextures",
false);
351 m_reuseableDynamicTextures.DefaultTTL =
new TimeSpan(24, 0, 0);
364 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
385 get {
return "DynamicTextureModule"; }
388 public Type ReplaceableInterface
395 #region Nested type: DynamicTextureUpdater
399 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
401 public bool BlendWithOldTexture =
false;
404 public byte FrontAlpha = 255;
407 public bool SetNewFrontAlpha =
false;
434 Primitive.TextureEntry tmptex = part.Shape.Textures;
437 oldID = tmptex.DefaultTexture.TextureID;
439 if (Face == ALL_SIDES)
441 oldID = tmptex.DefaultTexture.TextureID;
442 tmptex.DefaultTexture.TextureID = textureID;
448 Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
449 texface.TextureID = textureID;
450 tmptex.FaceTextures[Face] = texface;
454 tmptex.DefaultTexture.TextureID = textureID;
462 part.UpdateTextureEntry(tmptex.GetBytes());
479 if (part == null || data == null || data.Length <= 1)
482 String.Format(
"DynamicTextureModule: Error preparing image using URL {0}",
Url);
483 scene.SimChat(Utils.StringToBytes(msg),
ChatTypeEnum.Say,
489 byte[] assetData = null;
492 if (BlendWithOldTexture)
494 Primitive.TextureEntryFace defaultFace = part.Shape.Textures.DefaultTexture;
495 if (defaultFace != null)
497 oldAsset = scene.AssetService.Get(defaultFace.TextureID.ToString());
499 if (oldAsset != null)
500 assetData = BlendTextures(data, oldAsset.
Data, SetNewFrontAlpha, FrontAlpha);
504 if (assetData == null)
506 assetData =
new byte[data.Length];
507 Array.Copy(data, assetData, data.Length);
513 UUID.Random(),
"DynamicImage" + Util.RandomClass.Next(1, 10000), (sbyte)AssetType.Texture,
514 scene.RegionInfo.RegionID.ToString());
515 asset.Data = assetData;
516 asset.Description = String.Format(
"URL image : {0}",
Url);
518 asset.Description = asset.Description.Substring(0, 128);
520 asset.Temporary = ((Disp & DISP_TEMP) != 0);
521 scene.AssetService.Store(asset);
524 if (cacheLayerDecode != null)
526 if (!cacheLayerDecode.Decode(asset.
FullID, asset.
Data))
528 "[DYNAMIC TEXTURE MODULE]: Decoding of dynamically generated asset {0} for {1} in {2} failed",
534 if (oldID !=
UUID.Zero && ((Disp & DISP_EXPIRE) != 0))
536 if (oldAsset == null)
537 oldAsset = scene.AssetService.Get(oldID.ToString());
539 if (oldAsset != null)
543 scene.AssetService.Delete(oldID.ToString());
551 private byte[] BlendTextures(byte[] frontImage, byte[] backImage,
bool setNewAlpha, byte newAlpha)
553 ManagedImage managedImage;
556 if (OpenJPEG.DecodeToImage(frontImage, out managedImage, out image))
558 Bitmap image1 =
new Bitmap(image);
560 if (OpenJPEG.DecodeToImage(backImage, out managedImage, out image))
562 Bitmap image2 =
new Bitmap(image);
565 SetAlpha(ref image1, newAlpha);
567 Bitmap joint = MergeBitMaps(image1, image2);
569 byte[] result =
new byte[0];
573 result = OpenJPEG.EncodeFromImage(joint,
true);
578 "[DYNAMICTEXTUREMODULE]: OpenJpeg Encode Failed. Exception {0}{1}",
579 e.Message, e.StackTrace);
594 joint =
new Bitmap(back.Width, back.Height, PixelFormat.Format32bppArgb);
595 jG = Graphics.FromImage(joint);
597 jG.DrawImage(back, 0, 0, back.Width, back.Height);
598 jG.DrawImage(front, 0, 0, back.Width, back.Height);
603 private void SetAlpha(ref Bitmap b, byte alpha)
605 for (
int w = 0; w < b.Width; w++)
607 for (
int h = 0; h < b.Height; h++)
609 b.SetPixel(w, h, Color.FromArgb(alpha, b.GetPixel(w, h)));
UUID DataReceived(byte[] data, Scene scene)
Called once new texture data has been received for this updater.
UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams, int updateTimer)
Bitmap MergeBitMaps(Bitmap front, Bitmap back)
UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams, int updateTimer, bool SetBlending, byte AlphaValue)
UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face)
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
UUID UpdatePart(SceneObjectPart part, UUID textureID)
Update the given part with the new texture.
Scene Scene
The scene to which this entity belongs
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Size Size
Size of texture.
string InputCommands
Input commands used to generate this data.
UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, int updateTimer, bool SetBlending, byte AlphaValue)
DynamicTextureModule()
This constructor is only here because of the Unit Tests... Don't use it.
bool IsReuseable
Signal whether the texture is reuseable (i.e. whether the same input data will always generate the sa...
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
Asset class. All Assets are reference by this class or a class derived from this class ...
void ReturnData(UUID updaterId, IDynamicTexture texture)
Called by code which actually renders the dynamic texture to supply texture data. ...
void RegisterRender(string handleType, IDynamicTextureRender render)
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, int updateTimer)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
SceneObjectGroup ParentGroup
string InputParams
Extra input params used to generate this data.
virtual RegionInfo RegionInfo
UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face)
Apply a dynamically generated texture to the given prim.
void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, out double xSize, out double ySize)
string ID
Asset MetaData ID (transferring from UUID to string ID)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool Temporary
Is this asset going to be saved to the asset database?