/Aurora/Modules/Scripting/DynamicTexture/DynamicTextureModule.cs
C# | 480 lines | 371 code | 68 blank | 41 comment | 62 complexity | 0f816d5b2c00ecc6b5fe06b83095a307 MD5 | raw file
1/* 2 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/ 3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the Aurora-Sim Project nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 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 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28using Aurora.Framework; 29using Aurora.Framework.ClientInterfaces; 30using Aurora.Framework.ConsoleFramework; 31using Aurora.Framework.Modules; 32using Aurora.Framework.SceneInfo; 33using Aurora.Framework.Services.ClassHelpers.Assets; 34using Aurora.Framework.Utilities; 35using Nini.Config; 36using OpenMetaverse; 37using OpenMetaverse.Imaging; 38using System; 39using System.Collections.Generic; 40using System.Drawing; 41using System.Drawing.Imaging; 42 43namespace Aurora.Modules.Scripting 44{ 45 public class DynamicTextureModule : INonSharedRegionModule, IDynamicTextureManager 46 { 47 //private static readonly ILog MainConsole.Instance = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 49 private const int ALL_SIDES = -1; 50 51 public const int DISP_EXPIRE = 1; 52 public const int DISP_TEMP = 2; 53 54 private readonly Dictionary<UUID, IScene> RegisteredScenes = new Dictionary<UUID, IScene>(); 55 56 private readonly Dictionary<string, IDynamicTextureRender> RenderPlugins = 57 new Dictionary<string, IDynamicTextureRender>(); 58 59 private readonly Dictionary<UUID, DynamicTextureUpdater> Updaters = 60 new Dictionary<UUID, DynamicTextureUpdater>(); 61 62 #region IDynamicTextureManager Members 63 64 public void RegisterRender(string handleType, IDynamicTextureRender render) 65 { 66 if (!RenderPlugins.ContainsKey(handleType)) 67 { 68 RenderPlugins.Add(handleType, render); 69 } 70 } 71 72 /// <summary> 73 /// Called by code which actually renders the dynamic texture to supply texture data. 74 /// </summary> 75 /// <param name="id"></param> 76 /// <param name="data"></param> 77 public void ReturnData(UUID id, byte[] data) 78 { 79 DynamicTextureUpdater updater = null; 80 81 lock (Updaters) 82 { 83 if (Updaters.ContainsKey(id)) 84 { 85 updater = Updaters[id]; 86 } 87 } 88 89 if (updater != null) 90 { 91 if (RegisteredScenes.ContainsKey(updater.SimUUID)) 92 { 93 IScene scene = RegisteredScenes[updater.SimUUID]; 94 updater.DataReceived(data, scene); 95 } 96 } 97 98 if (updater.UpdateTimer == 0) 99 { 100 lock (Updaters) 101 { 102 if (!Updaters.ContainsKey(updater.UpdaterID)) 103 { 104 Updaters.Remove(updater.UpdaterID); 105 } 106 } 107 } 108 } 109 110 public UUID AddDynamicTextureURL(UUID simID, UUID primID, UUID oldAssetID, string contentType, string url, 111 string extraParams, int updateTimer) 112 { 113 return AddDynamicTextureURL(simID, primID, oldAssetID, contentType, url, extraParams, updateTimer, false, 114 255); 115 } 116 117 public UUID AddDynamicTextureURL(UUID simID, UUID primID, UUID oldAssetID, string contentType, string url, 118 string extraParams, int updateTimer, bool SetBlending, byte AlphaValue) 119 { 120 return AddDynamicTextureURL(simID, primID, oldAssetID, contentType, url, 121 extraParams, updateTimer, SetBlending, 122 (DISP_TEMP | DISP_EXPIRE), AlphaValue, ALL_SIDES); 123 } 124 125 public UUID AddDynamicTextureURL(UUID simID, UUID primID, UUID oldAssetID, string contentType, string url, 126 string extraParams, int updateTimer, bool SetBlending, 127 int disp, byte AlphaValue, int face) 128 { 129 if (RenderPlugins.ContainsKey(contentType)) 130 { 131 DynamicTextureUpdater updater = new DynamicTextureUpdater 132 { 133 SimUUID = simID, 134 PrimID = primID, 135 ContentType = contentType, 136 Url = url, 137 UpdateTimer = updateTimer, 138 UpdaterID = UUID.Random(), 139 Params = extraParams, 140 BlendWithOldTexture = SetBlending, 141 FrontAlpha = AlphaValue, 142 Face = face, 143 Disp = disp, 144 LastAssetID = oldAssetID 145 }; 146 147 lock (Updaters) 148 { 149 if (!Updaters.ContainsKey(updater.UpdaterID)) 150 { 151 Updaters.Add(updater.UpdaterID, updater); 152 } 153 } 154 155 RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams); 156 return updater.UpdaterID; 157 } 158 return UUID.Zero; 159 } 160 161 public UUID AddDynamicTextureData(UUID simID, UUID primID, UUID oldAssetID, string contentType, string data, 162 string extraParams, int updateTimer) 163 { 164 return AddDynamicTextureData(simID, primID, oldAssetID, contentType, data, extraParams, updateTimer, false, 165 255); 166 } 167 168 public UUID AddDynamicTextureData(UUID simID, UUID primID, UUID oldAssetID, string contentType, string data, 169 string extraParams, int updateTimer, bool SetBlending, byte AlphaValue) 170 { 171 return AddDynamicTextureData(simID, primID, oldAssetID, contentType, data, extraParams, updateTimer, 172 SetBlending, 173 (DISP_TEMP | DISP_EXPIRE), AlphaValue, ALL_SIDES); 174 } 175 176 public UUID AddDynamicTextureData(UUID simID, UUID primID, UUID oldAssetID, string contentType, string data, 177 string extraParams, int updateTimer, bool SetBlending, int disp, 178 byte AlphaValue, int face) 179 { 180 if (RenderPlugins.ContainsKey(contentType)) 181 { 182 DynamicTextureUpdater updater = new DynamicTextureUpdater 183 { 184 SimUUID = simID, 185 PrimID = primID, 186 ContentType = contentType, 187 BodyData = data, 188 UpdateTimer = updateTimer, 189 UpdaterID = UUID.Random(), 190 Params = extraParams, 191 BlendWithOldTexture = SetBlending, 192 FrontAlpha = AlphaValue, 193 Face = face, 194 Url = "Local image", 195 Disp = disp, 196 LastAssetID = oldAssetID 197 }; 198 199 lock (Updaters) 200 { 201 if (!Updaters.ContainsKey(updater.UpdaterID)) 202 { 203 Updaters.Add(updater.UpdaterID, updater); 204 } 205 } 206 207 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); 208 return updater.UpdaterID; 209 } 210 return UUID.Zero; 211 } 212 213 public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, 214 out double xSize, out double ySize) 215 { 216 xSize = 0; 217 ySize = 0; 218 if (RenderPlugins.ContainsKey(contentType)) 219 { 220 RenderPlugins[contentType].GetDrawStringSize(text, fontName, fontSize, out xSize, out ySize); 221 } 222 } 223 224 #endregion 225 226 #region INonSharedRegionModule Members 227 228 public void Initialise(IConfigSource config) 229 { 230 } 231 232 public void AddRegion(IScene scene) 233 { 234 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) 235 { 236 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); 237 scene.RegisterModuleInterface<IDynamicTextureManager>(this); 238 } 239 } 240 241 public void RemoveRegion(IScene scene) 242 { 243 } 244 245 public void RegionLoaded(IScene scene) 246 { 247 } 248 249 public Type ReplaceableInterface 250 { 251 get { return null; } 252 } 253 254 public void Close() 255 { 256 } 257 258 public string Name 259 { 260 get { return "DynamicTextureModule"; } 261 } 262 263 #endregion 264 265 #region Nested type: DynamicTextureUpdater 266 267 public class DynamicTextureUpdater 268 { 269 public bool BlendWithOldTexture; 270 public string BodyData; 271 public string ContentType; 272 public int Disp; 273 public int Face; 274 public byte FrontAlpha = 255; 275 public UUID LastAssetID = UUID.Zero; 276 public string Params; 277 public UUID PrimID; 278 public bool SetNewFrontAlpha; 279 public UUID SimUUID; 280 public int UpdateTimer; 281 public UUID UpdaterID; 282 public string Url; 283 284 public DynamicTextureUpdater() 285 { 286 UpdateTimer = 0; 287 BodyData = null; 288 } 289 290 /// <summary> 291 /// Called once new texture data has been received for this updater. 292 /// </summary> 293 public void DataReceived(byte[] data, IScene scene) 294 { 295 ISceneChildEntity part = scene.GetSceneObjectPart(PrimID); 296 297 if (part == null || data == null || data.Length <= 1) 298 { 299 string msg = 300 String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); 301 IChatModule chatModule = scene.RequestModuleInterface<IChatModule>(); 302 if (chatModule != null) 303 chatModule.SimChat(msg, ChatTypeEnum.Say, 0, 304 part.ParentEntity.AbsolutePosition, part.Name, part.UUID, false, scene); 305 return; 306 } 307 308 byte[] assetData = null; 309 AssetBase oldAsset = null; 310 311 if (BlendWithOldTexture) 312 { 313 Primitive.TextureEntryFace defaultFace = part.Shape.Textures.DefaultTexture; 314 if (defaultFace != null) 315 { 316 oldAsset = scene.AssetService.Get(defaultFace.TextureID.ToString()); 317 318 if (oldAsset != null) 319 assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha, scene); 320 } 321 } 322 323 if (assetData == null) 324 { 325 assetData = new byte[data.Length]; 326 Array.Copy(data, assetData, data.Length); 327 } 328 329 AssetBase asset = null; 330 331 if (LastAssetID != UUID.Zero) 332 { 333 asset = scene.AssetService.Get(LastAssetID.ToString()); 334 asset.Description = String.Format("URL image : {0}", Url); 335 asset.Data = assetData; 336 if ((asset.Flags & AssetFlags.Local) == AssetFlags.Local) 337 { 338 asset.Flags = asset.Flags & ~AssetFlags.Local; 339 } 340 if (((asset.Flags & AssetFlags.Temporary) == AssetFlags.Temporary) != ((Disp & DISP_TEMP) != 0)) 341 { 342 if ((Disp & DISP_TEMP) != 0) asset.Flags |= AssetFlags.Temporary; 343 else asset.Flags = asset.Flags & ~AssetFlags.Temporary; 344 } 345 asset.ID = scene.AssetService.Store(asset); 346 } 347 else 348 { 349 // Create a new asset for user 350 asset = new AssetBase(UUID.Random(), "DynamicImage" + Util.RandomClass.Next(1, 10000), 351 AssetType.Texture, 352 scene.RegionInfo.RegionID) 353 {Data = assetData, Description = String.Format("URL image : {0}", Url)}; 354 if ((Disp & DISP_TEMP) != 0) asset.Flags = AssetFlags.Temporary; 355 asset.ID = scene.AssetService.Store(asset); 356 } 357 358 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); 359 if (cacheLayerDecode != null) 360 { 361 cacheLayerDecode.Decode(asset.ID, asset.Data); 362 cacheLayerDecode = null; 363 LastAssetID = asset.ID; 364 } 365 366 UUID oldID = UUID.Zero; 367 368 lock (part) 369 { 370 // mostly keep the values from before 371 Primitive.TextureEntry tmptex = part.Shape.Textures; 372 373 // remove the old asset from the cache 374 oldID = tmptex.DefaultTexture.TextureID; 375 376 if (Face == ALL_SIDES) 377 { 378 tmptex.DefaultTexture.TextureID = asset.ID; 379 } 380 else 381 { 382 try 383 { 384 Primitive.TextureEntryFace texface = tmptex.CreateFace((uint) Face); 385 texface.TextureID = asset.ID; 386 tmptex.FaceTextures[Face] = texface; 387 } 388 catch (Exception) 389 { 390 tmptex.DefaultTexture.TextureID = asset.ID; 391 } 392 } 393 394 // I'm pretty sure we always want to force this to true 395 // I'm pretty sure noone whats to set fullbright true if it wasn't true before. 396 // tmptex.DefaultTexture.Fullbright = true; 397 398 part.UpdateTexture(tmptex, true); 399 } 400 401 if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) 402 { 403 if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString()); 404 if (oldAsset != null) 405 { 406 if ((oldAsset.Flags & AssetFlags.Temporary) == AssetFlags.Temporary) 407 { 408 scene.AssetService.Delete(oldID); 409 } 410 } 411 } 412 } 413 414 private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha, 415 IScene scene) 416 { 417 Image image = scene.RequestModuleInterface<IJ2KDecoder>().DecodeToImage(frontImage); 418 419 if (image != null) 420 { 421 Bitmap image1 = new Bitmap(image); 422 423 image = scene.RequestModuleInterface<IJ2KDecoder>().DecodeToImage(backImage); 424 if (image != null) 425 { 426 Bitmap image2 = new Bitmap(image); 427 428 if (setNewAlpha) 429 SetAlpha(ref image1, newAlpha); 430 431 Bitmap joint = MergeBitMaps(image1, image2); 432 433 byte[] result = new byte[0]; 434 435 try 436 { 437 result = OpenJPEG.EncodeFromImage(joint, true); 438 } 439 catch (Exception) 440 { 441 MainConsole.Instance.Error( 442 "[DYNAMICTEXTUREMODULE]: OpenJpeg Encode Failed. Empty byte data returned!"); 443 } 444 445 return result; 446 } 447 } 448 449 return null; 450 } 451 452 public Bitmap MergeBitMaps(Bitmap front, Bitmap back) 453 { 454 Bitmap joint; 455 Graphics jG; 456 457 joint = new Bitmap(back.Width, back.Height, PixelFormat.Format32bppArgb); 458 jG = Graphics.FromImage(joint); 459 460 jG.DrawImage(back, 0, 0, back.Width, back.Height); 461 jG.DrawImage(front, 0, 0, back.Width, back.Height); 462 463 return joint; 464 } 465 466 private void SetAlpha(ref Bitmap b, byte alpha) 467 { 468 for (int w = 0; w < b.Width; w++) 469 { 470 for (int h = 0; h < b.Height; h++) 471 { 472 b.SetPixel(w, h, Color.FromArgb(alpha, b.GetPixel(w, h))); 473 } 474 } 475 } 476 } 477 478 #endregion 479 } 480}