/Aurora/Modules/Scripting/DynamicTexture/DynamicTextureModule.cs

https://bitbucket.org/VirtualReality/software-testing · 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. using Aurora.Framework;
  28. using Aurora.Framework.ClientInterfaces;
  29. using Aurora.Framework.ConsoleFramework;
  30. using Aurora.Framework.Modules;
  31. using Aurora.Framework.SceneInfo;
  32. using Aurora.Framework.Services.ClassHelpers.Assets;
  33. using Aurora.Framework.Utilities;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenMetaverse.Imaging;
  37. using System;
  38. using System.Collections.Generic;
  39. using System.Drawing;
  40. using System.Drawing.Imaging;
  41. namespace Aurora.Modules.Scripting
  42. {
  43. public class DynamicTextureModule : INonSharedRegionModule, IDynamicTextureManager
  44. {
  45. //private static readonly ILog MainConsole.Instance = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  46. private const int ALL_SIDES = -1;
  47. public const int DISP_EXPIRE = 1;
  48. public const int DISP_TEMP = 2;
  49. private readonly Dictionary<UUID, IScene> RegisteredScenes = new Dictionary<UUID, IScene>();
  50. private readonly Dictionary<string, IDynamicTextureRender> RenderPlugins =
  51. new Dictionary<string, IDynamicTextureRender>();
  52. private readonly Dictionary<UUID, DynamicTextureUpdater> Updaters =
  53. new Dictionary<UUID, DynamicTextureUpdater>();
  54. #region IDynamicTextureManager Members
  55. public void RegisterRender(string handleType, IDynamicTextureRender render)
  56. {
  57. if (!RenderPlugins.ContainsKey(handleType))
  58. {
  59. RenderPlugins.Add(handleType, render);
  60. }
  61. }
  62. /// <summary>
  63. /// Called by code which actually renders the dynamic texture to supply texture data.
  64. /// </summary>
  65. /// <param name="id"></param>
  66. /// <param name="data"></param>
  67. public void ReturnData(UUID id, byte[] data)
  68. {
  69. DynamicTextureUpdater updater = null;
  70. lock (Updaters)
  71. {
  72. if (Updaters.ContainsKey(id))
  73. {
  74. updater = Updaters[id];
  75. }
  76. }
  77. if (updater != null)
  78. {
  79. if (RegisteredScenes.ContainsKey(updater.SimUUID))
  80. {
  81. IScene scene = RegisteredScenes[updater.SimUUID];
  82. updater.DataReceived(data, scene);
  83. }
  84. }
  85. if (updater.UpdateTimer == 0)
  86. {
  87. lock (Updaters)
  88. {
  89. if (!Updaters.ContainsKey(updater.UpdaterID))
  90. {
  91. Updaters.Remove(updater.UpdaterID);
  92. }
  93. }
  94. }
  95. }
  96. public UUID AddDynamicTextureURL(UUID simID, UUID primID, UUID oldAssetID, string contentType, string url,
  97. string extraParams, int updateTimer)
  98. {
  99. return AddDynamicTextureURL(simID, primID, oldAssetID, contentType, url, extraParams, updateTimer, false,
  100. 255);
  101. }
  102. public UUID AddDynamicTextureURL(UUID simID, UUID primID, UUID oldAssetID, string contentType, string url,
  103. string extraParams, int updateTimer, bool SetBlending, byte AlphaValue)
  104. {
  105. return AddDynamicTextureURL(simID, primID, oldAssetID, contentType, url,
  106. extraParams, updateTimer, SetBlending,
  107. (DISP_TEMP | DISP_EXPIRE), AlphaValue, ALL_SIDES);
  108. }
  109. public UUID AddDynamicTextureURL(UUID simID, UUID primID, UUID oldAssetID, string contentType, string url,
  110. string extraParams, int updateTimer, bool SetBlending,
  111. int disp, byte AlphaValue, int face)
  112. {
  113. if (RenderPlugins.ContainsKey(contentType))
  114. {
  115. DynamicTextureUpdater updater = new DynamicTextureUpdater
  116. {
  117. SimUUID = simID,
  118. PrimID = primID,
  119. ContentType = contentType,
  120. Url = url,
  121. UpdateTimer = updateTimer,
  122. UpdaterID = UUID.Random(),
  123. Params = extraParams,
  124. BlendWithOldTexture = SetBlending,
  125. FrontAlpha = AlphaValue,
  126. Face = face,
  127. Disp = disp,
  128. LastAssetID = oldAssetID
  129. };
  130. lock (Updaters)
  131. {
  132. if (!Updaters.ContainsKey(updater.UpdaterID))
  133. {
  134. Updaters.Add(updater.UpdaterID, updater);
  135. }
  136. }
  137. RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams);
  138. return updater.UpdaterID;
  139. }
  140. return UUID.Zero;
  141. }
  142. public UUID AddDynamicTextureData(UUID simID, UUID primID, UUID oldAssetID, string contentType, string data,
  143. string extraParams, int updateTimer)
  144. {
  145. return AddDynamicTextureData(simID, primID, oldAssetID, contentType, data, extraParams, updateTimer, false,
  146. 255);
  147. }
  148. public UUID AddDynamicTextureData(UUID simID, UUID primID, UUID oldAssetID, string contentType, string data,
  149. string extraParams, int updateTimer, bool SetBlending, byte AlphaValue)
  150. {
  151. return AddDynamicTextureData(simID, primID, oldAssetID, contentType, data, extraParams, updateTimer,
  152. SetBlending,
  153. (DISP_TEMP | DISP_EXPIRE), AlphaValue, ALL_SIDES);
  154. }
  155. public UUID AddDynamicTextureData(UUID simID, UUID primID, UUID oldAssetID, string contentType, string data,
  156. string extraParams, int updateTimer, bool SetBlending, int disp,
  157. byte AlphaValue, int face)
  158. {
  159. if (RenderPlugins.ContainsKey(contentType))
  160. {
  161. DynamicTextureUpdater updater = new DynamicTextureUpdater
  162. {
  163. SimUUID = simID,
  164. PrimID = primID,
  165. ContentType = contentType,
  166. BodyData = data,
  167. UpdateTimer = updateTimer,
  168. UpdaterID = UUID.Random(),
  169. Params = extraParams,
  170. BlendWithOldTexture = SetBlending,
  171. FrontAlpha = AlphaValue,
  172. Face = face,
  173. Url = "Local image",
  174. Disp = disp,
  175. LastAssetID = oldAssetID
  176. };
  177. lock (Updaters)
  178. {
  179. if (!Updaters.ContainsKey(updater.UpdaterID))
  180. {
  181. Updaters.Add(updater.UpdaterID, updater);
  182. }
  183. }
  184. RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
  185. return updater.UpdaterID;
  186. }
  187. return UUID.Zero;
  188. }
  189. public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize,
  190. out double xSize, out double ySize)
  191. {
  192. xSize = 0;
  193. ySize = 0;
  194. if (RenderPlugins.ContainsKey(contentType))
  195. {
  196. RenderPlugins[contentType].GetDrawStringSize(text, fontName, fontSize, out xSize, out ySize);
  197. }
  198. }
  199. #endregion
  200. #region INonSharedRegionModule Members
  201. public void Initialise(IConfigSource config)
  202. {
  203. }
  204. public void AddRegion(IScene scene)
  205. {
  206. if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
  207. {
  208. RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
  209. scene.RegisterModuleInterface<IDynamicTextureManager>(this);
  210. }
  211. }
  212. public void RemoveRegion(IScene scene)
  213. {
  214. }
  215. public void RegionLoaded(IScene scene)
  216. {
  217. }
  218. public Type ReplaceableInterface
  219. {
  220. get { return null; }
  221. }
  222. public void Close()
  223. {
  224. }
  225. public string Name
  226. {
  227. get { return "DynamicTextureModule"; }
  228. }
  229. #endregion
  230. #region Nested type: DynamicTextureUpdater
  231. public class DynamicTextureUpdater
  232. {
  233. public bool BlendWithOldTexture;
  234. public string BodyData;
  235. public string ContentType;
  236. public int Disp;
  237. public int Face;
  238. public byte FrontAlpha = 255;
  239. public UUID LastAssetID = UUID.Zero;
  240. public string Params;
  241. public UUID PrimID;
  242. public bool SetNewFrontAlpha;
  243. public UUID SimUUID;
  244. public int UpdateTimer;
  245. public UUID UpdaterID;
  246. public string Url;
  247. public DynamicTextureUpdater()
  248. {
  249. UpdateTimer = 0;
  250. BodyData = null;
  251. }
  252. /// <summary>
  253. /// Called once new texture data has been received for this updater.
  254. /// </summary>
  255. public void DataReceived(byte[] data, IScene scene)
  256. {
  257. ISceneChildEntity part = scene.GetSceneObjectPart(PrimID);
  258. if (part == null || data == null || data.Length <= 1)
  259. {
  260. string msg =
  261. String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url);
  262. IChatModule chatModule = scene.RequestModuleInterface<IChatModule>();
  263. if (chatModule != null)
  264. chatModule.SimChat(msg, ChatTypeEnum.Say, 0,
  265. part.ParentEntity.AbsolutePosition, part.Name, part.UUID, false, scene);
  266. return;
  267. }
  268. byte[] assetData = null;
  269. AssetBase oldAsset = null;
  270. if (BlendWithOldTexture)
  271. {
  272. Primitive.TextureEntryFace defaultFace = part.Shape.Textures.DefaultTexture;
  273. if (defaultFace != null)
  274. {
  275. oldAsset = scene.AssetService.Get(defaultFace.TextureID.ToString());
  276. if (oldAsset != null)
  277. assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha, scene);
  278. }
  279. }
  280. if (assetData == null)
  281. {
  282. assetData = new byte[data.Length];
  283. Array.Copy(data, assetData, data.Length);
  284. }
  285. AssetBase asset = null;
  286. if (LastAssetID != UUID.Zero)
  287. {
  288. asset = scene.AssetService.Get(LastAssetID.ToString());
  289. asset.Description = String.Format("URL image : {0}", Url);
  290. asset.Data = assetData;
  291. if ((asset.Flags & AssetFlags.Local) == AssetFlags.Local)
  292. {
  293. asset.Flags = asset.Flags & ~AssetFlags.Local;
  294. }
  295. if (((asset.Flags & AssetFlags.Temporary) == AssetFlags.Temporary) != ((Disp & DISP_TEMP) != 0))
  296. {
  297. if ((Disp & DISP_TEMP) != 0) asset.Flags |= AssetFlags.Temporary;
  298. else asset.Flags = asset.Flags & ~AssetFlags.Temporary;
  299. }
  300. asset.ID = scene.AssetService.Store(asset);
  301. }
  302. else
  303. {
  304. // Create a new asset for user
  305. asset = new AssetBase(UUID.Random(), "DynamicImage" + Util.RandomClass.Next(1, 10000),
  306. AssetType.Texture,
  307. scene.RegionInfo.RegionID)
  308. {Data = assetData, Description = String.Format("URL image : {0}", Url)};
  309. if ((Disp & DISP_TEMP) != 0) asset.Flags = AssetFlags.Temporary;
  310. asset.ID = scene.AssetService.Store(asset);
  311. }
  312. IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
  313. if (cacheLayerDecode != null)
  314. {
  315. cacheLayerDecode.Decode(asset.ID, asset.Data);
  316. cacheLayerDecode = null;
  317. LastAssetID = asset.ID;
  318. }
  319. UUID oldID = UUID.Zero;
  320. lock (part)
  321. {
  322. // mostly keep the values from before
  323. Primitive.TextureEntry tmptex = part.Shape.Textures;
  324. // remove the old asset from the cache
  325. oldID = tmptex.DefaultTexture.TextureID;
  326. if (Face == ALL_SIDES)
  327. {
  328. tmptex.DefaultTexture.TextureID = asset.ID;
  329. }
  330. else
  331. {
  332. try
  333. {
  334. Primitive.TextureEntryFace texface = tmptex.CreateFace((uint) Face);
  335. texface.TextureID = asset.ID;
  336. tmptex.FaceTextures[Face] = texface;
  337. }
  338. catch (Exception)
  339. {
  340. tmptex.DefaultTexture.TextureID = asset.ID;
  341. }
  342. }
  343. // I'm pretty sure we always want to force this to true
  344. // I'm pretty sure noone whats to set fullbright true if it wasn't true before.
  345. // tmptex.DefaultTexture.Fullbright = true;
  346. part.UpdateTexture(tmptex, true);
  347. }
  348. if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0))
  349. {
  350. if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString());
  351. if (oldAsset != null)
  352. {
  353. if ((oldAsset.Flags & AssetFlags.Temporary) == AssetFlags.Temporary)
  354. {
  355. scene.AssetService.Delete(oldID);
  356. }
  357. }
  358. }
  359. }
  360. private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha,
  361. IScene scene)
  362. {
  363. Image image = scene.RequestModuleInterface<IJ2KDecoder>().DecodeToImage(frontImage);
  364. if (image != null)
  365. {
  366. Bitmap image1 = new Bitmap(image);
  367. image = scene.RequestModuleInterface<IJ2KDecoder>().DecodeToImage(backImage);
  368. if (image != null)
  369. {
  370. Bitmap image2 = new Bitmap(image);
  371. if (setNewAlpha)
  372. SetAlpha(ref image1, newAlpha);
  373. Bitmap joint = MergeBitMaps(image1, image2);
  374. byte[] result = new byte[0];
  375. try
  376. {
  377. result = OpenJPEG.EncodeFromImage(joint, true);
  378. }
  379. catch (Exception)
  380. {
  381. MainConsole.Instance.Error(
  382. "[DYNAMICTEXTUREMODULE]: OpenJpeg Encode Failed. Empty byte data returned!");
  383. }
  384. return result;
  385. }
  386. }
  387. return null;
  388. }
  389. public Bitmap MergeBitMaps(Bitmap front, Bitmap back)
  390. {
  391. Bitmap joint;
  392. Graphics jG;
  393. joint = new Bitmap(back.Width, back.Height, PixelFormat.Format32bppArgb);
  394. jG = Graphics.FromImage(joint);
  395. jG.DrawImage(back, 0, 0, back.Width, back.Height);
  396. jG.DrawImage(front, 0, 0, back.Width, back.Height);
  397. return joint;
  398. }
  399. private void SetAlpha(ref Bitmap b, byte alpha)
  400. {
  401. for (int w = 0; w < b.Width; w++)
  402. {
  403. for (int h = 0; h < b.Height; h++)
  404. {
  405. b.SetPixel(w, h, Color.FromArgb(alpha, b.GetPixel(w, h)));
  406. }
  407. }
  408. }
  409. }
  410. #endregion
  411. }
  412. }