MaterialsModule.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. /*
  2. * Copyright (c) Contributors, 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 OpenSimulator 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 System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Reflection;
  31. using System.Security.Cryptography; // for computing md5 hash
  32. using log4net;
  33. using Mono.Addins;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenMetaverse.StructuredData;
  37. using OpenSim.Framework;
  38. using OpenSim.Framework.Servers;
  39. using OpenSim.Framework.Servers.HttpServer;
  40. using OpenSim.Region.Framework.Interfaces;
  41. using OpenSim.Region.Framework.Scenes;
  42. using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType;
  43. using Ionic.Zlib;
  44. namespace OpenSim.Region.OptionalModules.Materials
  45. {
  46. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsModule")]
  47. public class MaterialsModule : INonSharedRegionModule, IMaterialsModule
  48. {
  49. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  50. public string Name { get { return "MaterialsModule"; } }
  51. public Type ReplaceableInterface { get { return null; } }
  52. IAssetCache m_cache;
  53. private Scene m_scene = null;
  54. private bool m_enabled = false;
  55. private int m_maxMaterialsPerTransaction = 50;
  56. private object materialslock = new object();
  57. public Dictionary<UUID, FaceMaterial> m_Materials = new Dictionary<UUID, FaceMaterial>();
  58. public Dictionary<UUID, int> m_MaterialsRefCount = new Dictionary<UUID, int>();
  59. private Dictionary<FaceMaterial, double> m_changed = new Dictionary<FaceMaterial, double>();
  60. public void Initialise(IConfigSource source)
  61. {
  62. m_enabled = true; // default is enabled
  63. IConfig config = source.Configs["Materials"];
  64. if (config != null)
  65. {
  66. m_enabled = config.GetBoolean("enable_materials", m_enabled);
  67. m_maxMaterialsPerTransaction = config.GetInt("MaxMaterialsPerTransaction", m_maxMaterialsPerTransaction);
  68. }
  69. if (m_enabled)
  70. m_log.DebugFormat("[Materials]: Initialized");
  71. }
  72. public void Close()
  73. {
  74. if (!m_enabled)
  75. return;
  76. }
  77. public void AddRegion(Scene scene)
  78. {
  79. if (!m_enabled)
  80. return;
  81. m_scene = scene;
  82. m_scene.RegisterModuleInterface<IMaterialsModule>(this);
  83. m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
  84. m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
  85. m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManager_OnObjectDeleteFromScene;
  86. m_scene.EventManager.OnBackup += EventManager_OnBackup;
  87. }
  88. public void RemoveRegion(Scene scene)
  89. {
  90. if (!m_enabled)
  91. return;
  92. m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
  93. m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
  94. m_scene.EventManager.OnObjectBeingRemovedFromScene -= EventManager_OnObjectDeleteFromScene;
  95. m_scene.EventManager.OnBackup -= EventManager_OnBackup;
  96. m_scene.UnregisterModuleInterface<IMaterialsModule>(this);
  97. }
  98. public void RegionLoaded(Scene scene)
  99. {
  100. if (!m_enabled) return;
  101. m_cache = scene.RequestModuleInterface<IAssetCache>();
  102. ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>();
  103. if (featuresModule != null)
  104. featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
  105. }
  106. private void EventManager_OnBackup(ISimulationDataService datastore, bool forcedBackup)
  107. {
  108. List<FaceMaterial> toStore;
  109. lock (materialslock)
  110. {
  111. if(m_changed.Count == 0)
  112. return;
  113. if (forcedBackup)
  114. {
  115. toStore = new List<FaceMaterial>(m_changed.Keys);
  116. m_changed.Clear();
  117. }
  118. else
  119. {
  120. toStore = new List<FaceMaterial>();
  121. double storetime = Util.GetTimeStamp() - 60.0;
  122. foreach(KeyValuePair<FaceMaterial, double> kvp in m_changed)
  123. {
  124. if(kvp.Value < storetime)
  125. {
  126. toStore.Add(kvp.Key);
  127. }
  128. }
  129. foreach(FaceMaterial fm in toStore)
  130. {
  131. m_changed.Remove(fm);
  132. }
  133. }
  134. }
  135. if(toStore.Count > 0)
  136. {
  137. if (forcedBackup)
  138. {
  139. foreach (FaceMaterial fm in toStore)
  140. {
  141. AssetBase a = MakeAsset(fm, false);
  142. m_scene.AssetService.Store(a);
  143. }
  144. }
  145. else
  146. {
  147. Util.FireAndForget(delegate
  148. {
  149. foreach (FaceMaterial fm in toStore)
  150. {
  151. AssetBase a = MakeAsset(fm, false);
  152. m_scene.AssetService.Store(a);
  153. }
  154. });
  155. }
  156. }
  157. }
  158. private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
  159. {
  160. foreach (var part in obj.Parts)
  161. if (part != null)
  162. GetStoredMaterialsInPart(part);
  163. }
  164. private void EventManager_OnObjectDeleteFromScene(SceneObjectGroup obj)
  165. {
  166. foreach (var part in obj.Parts)
  167. if (part != null)
  168. RemoveMaterialsInPart(part);
  169. }
  170. private void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps)
  171. {
  172. string capsBase = "/CAPS/" + caps.CapsObjectPath;
  173. IRequestHandler renderMaterialsPostHandler
  174. = new RestStreamHandler("POST", capsBase + "/",
  175. (request, path, param, httpRequest, httpResponse)
  176. => RenderMaterialsPostCap(request, agentID),
  177. "RenderMaterials", null);
  178. caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler);
  179. // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET
  180. // and POST handlers, (at least at the time this was originally written), so we first set up a POST
  181. // handler normally and then add a GET handler via MainServer
  182. IRequestHandler renderMaterialsGetHandler
  183. = new RestStreamHandler("GET", capsBase + "/",
  184. (request, path, param, httpRequest, httpResponse)
  185. => RenderMaterialsGetCap(request),
  186. "RenderMaterials", null);
  187. MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler);
  188. // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well
  189. IRequestHandler renderMaterialsPutHandler
  190. = new RestStreamHandler("PUT", capsBase + "/",
  191. (request, path, param, httpRequest, httpResponse)
  192. => RenderMaterialsPutCap(request, agentID),
  193. "RenderMaterials", null);
  194. MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler);
  195. }
  196. private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
  197. {
  198. features["MaxMaterialsPerTransaction"] = m_maxMaterialsPerTransaction;
  199. features["RenderMaterialsCapability"] = OSD.FromReal(3);
  200. }
  201. /// <summary>
  202. /// Finds any legacy materials stored in DynAttrs that may exist for this part and add them to 'm_regionMaterials'.
  203. /// </summary>
  204. /// <param name="part"></param>
  205. private bool GetLegacyStoredMaterialsInPart(SceneObjectPart part)
  206. {
  207. if (part.DynAttrs == null)
  208. return false;
  209. OSD OSMaterials = null;
  210. OSDArray matsArr = null;
  211. bool partchanged = false;
  212. lock (part.DynAttrs)
  213. {
  214. if (part.DynAttrs.ContainsStore("OpenSim", "Materials"))
  215. {
  216. OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials");
  217. if (materialsStore == null)
  218. return false;
  219. materialsStore.TryGetValue("Materials", out OSMaterials);
  220. part.DynAttrs.RemoveStore("OpenSim", "Materials");
  221. partchanged = true;
  222. }
  223. if (OSMaterials != null && OSMaterials is OSDArray)
  224. matsArr = OSMaterials as OSDArray;
  225. else
  226. return partchanged;
  227. }
  228. if (matsArr == null)
  229. return partchanged;
  230. foreach (OSD elemOsd in matsArr)
  231. {
  232. if (elemOsd != null && elemOsd is OSDMap)
  233. {
  234. OSDMap matMap = elemOsd as OSDMap;
  235. OSD OSDID;
  236. OSD OSDMaterial;
  237. if (matMap.TryGetValue("ID", out OSDID) && matMap.TryGetValue("Material", out OSDMaterial) && OSDMaterial is OSDMap)
  238. {
  239. try
  240. {
  241. lock (materialslock)
  242. {
  243. UUID id = OSDID.AsUUID();
  244. if(m_Materials.ContainsKey(id))
  245. continue;
  246. OSDMap theMatMap = (OSDMap)OSDMaterial;
  247. FaceMaterial fmat = new FaceMaterial(theMatMap);
  248. if(fmat == null ||
  249. ( fmat.DiffuseAlphaMode == 1
  250. && fmat.NormalMapID == UUID.Zero
  251. && fmat.SpecularMapID == UUID.Zero))
  252. continue;
  253. fmat.ID = id;
  254. m_Materials[id] = fmat;
  255. m_MaterialsRefCount[id] = 0;
  256. }
  257. }
  258. catch (Exception e)
  259. {
  260. m_log.Warn("[Materials]: exception decoding persisted legacy material: " + e.ToString());
  261. }
  262. }
  263. }
  264. }
  265. return partchanged;
  266. }
  267. /// <summary>
  268. /// Find the materials used in the SOP, and add them to 'm_regionMaterials'.
  269. /// </summary>
  270. private void GetStoredMaterialsInPart(SceneObjectPart part)
  271. {
  272. if (part.Shape == null)
  273. return;
  274. bool partchanged = false;
  275. bool facechanged = false;
  276. var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length);
  277. if (te == null)
  278. return;
  279. partchanged = GetLegacyStoredMaterialsInPart(part);
  280. if (te.DefaultTexture != null)
  281. facechanged = GetStoredMaterialInFace(part, te.DefaultTexture);
  282. else
  283. m_log.WarnFormat(
  284. "[Materials]: Default texture for part {0} (part of object {1}) in {2} unexpectedly null. Ignoring.",
  285. part.Name, part.ParentGroup.Name, m_scene.Name);
  286. foreach (Primitive.TextureEntryFace face in te.FaceTextures)
  287. {
  288. if (face != null)
  289. facechanged |= GetStoredMaterialInFace(part, face);
  290. }
  291. if(facechanged)
  292. part.Shape.TextureEntry = te.GetBytes(9);
  293. if(facechanged || partchanged)
  294. {
  295. if (part.ParentGroup != null && !part.ParentGroup.IsDeleted)
  296. part.ParentGroup.HasGroupChanged = true;
  297. }
  298. }
  299. /// <summary>
  300. /// Find the materials used in one Face, and add them to 'm_regionMaterials'.
  301. /// </summary>
  302. private bool GetStoredMaterialInFace(SceneObjectPart part, Primitive.TextureEntryFace face)
  303. {
  304. UUID id = face.MaterialID;
  305. if (id == UUID.Zero)
  306. return false;
  307. OSDMap mat;
  308. lock (materialslock)
  309. {
  310. if(m_Materials.ContainsKey(id))
  311. {
  312. m_MaterialsRefCount[id]++;
  313. return false;
  314. }
  315. AssetBase matAsset = m_scene.AssetService.Get(id.ToString());
  316. if (matAsset == null || matAsset.Data == null || matAsset.Data.Length == 0 )
  317. {
  318. // grid may just be down...
  319. return false;
  320. }
  321. byte[] data = matAsset.Data;
  322. // string txt = System.Text.Encoding.ASCII.GetString(data);
  323. try
  324. {
  325. mat = (OSDMap)OSDParser.DeserializeLLSDXml(data);
  326. }
  327. catch (Exception e)
  328. {
  329. m_log.WarnFormat("[Materials]: cannot decode material asset {0}: {1}", id, e.Message);
  330. return false;
  331. }
  332. FaceMaterial fmat = new FaceMaterial(mat);
  333. if(fmat == null ||
  334. (fmat.DiffuseAlphaMode == 1
  335. && fmat.NormalMapID == UUID.Zero
  336. && fmat.SpecularMapID == UUID.Zero))
  337. {
  338. face.MaterialID = UUID.Zero;
  339. return true;
  340. }
  341. fmat.ID = id;
  342. if (m_Materials.ContainsKey(id))
  343. {
  344. m_MaterialsRefCount[id]++;
  345. }
  346. else
  347. {
  348. m_Materials[id] = fmat;
  349. m_MaterialsRefCount[id] = 1;
  350. }
  351. return false;
  352. }
  353. }
  354. private void RemoveMaterialsInPart(SceneObjectPart part)
  355. {
  356. if (part.Shape == null)
  357. return;
  358. var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length);
  359. if (te == null)
  360. return;
  361. if (te.DefaultTexture != null)
  362. RemoveMaterialInFace(te.DefaultTexture);
  363. foreach (Primitive.TextureEntryFace face in te.FaceTextures)
  364. {
  365. if(face != null)
  366. RemoveMaterialInFace(face);
  367. }
  368. }
  369. private void RemoveMaterialInFace(Primitive.TextureEntryFace face)
  370. {
  371. UUID id = face.MaterialID;
  372. if (id == UUID.Zero)
  373. return;
  374. lock (materialslock)
  375. {
  376. if(!m_Materials.ContainsKey(id))
  377. return;
  378. else
  379. {
  380. m_MaterialsRefCount[id]--;
  381. if(m_MaterialsRefCount[id] <= 0)
  382. {
  383. FaceMaterial oldFaceMat = m_Materials[id];
  384. m_changed.Remove(oldFaceMat);
  385. m_Materials.Remove(id);
  386. m_MaterialsRefCount.Remove(id);
  387. m_cache.Expire(id.ToString());
  388. }
  389. }
  390. }
  391. }
  392. public string RenderMaterialsPostCap(string request, UUID agentID)
  393. {
  394. OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
  395. OSDMap resp = new OSDMap();
  396. OSDArray respArr = new OSDArray();
  397. OSD tmpOSD;
  398. if (req.TryGetValue("Zipped", out tmpOSD))
  399. {
  400. OSD osd = null;
  401. byte[] inBytes = tmpOSD.AsBinary();
  402. try
  403. {
  404. osd = ZDecompressBytesToOsd(inBytes);
  405. if (osd != null && osd is OSDArray)
  406. {
  407. foreach (OSD elem in (OSDArray)osd)
  408. {
  409. try
  410. {
  411. UUID id = new UUID(elem.AsBinary(), 0);
  412. lock (materialslock)
  413. {
  414. if (m_Materials.ContainsKey(id))
  415. {
  416. OSDMap matMap = new OSDMap();
  417. matMap["ID"] = OSD.FromBinary(id.GetBytes());
  418. matMap["Material"] = m_Materials[id].toOSD();
  419. respArr.Add(matMap);
  420. }
  421. else
  422. {
  423. m_log.Warn("[Materials]: request for unknown material ID: " + id.ToString());
  424. // Theoretically we could try to load the material from the assets service,
  425. // but that shouldn't be necessary because the viewer should only request
  426. // materials that exist in a prim on the region, and all of these materials
  427. // are already stored in m_regionMaterials.
  428. }
  429. }
  430. }
  431. catch (Exception e)
  432. {
  433. m_log.Error("Error getting materials in response to viewer request", e);
  434. continue;
  435. }
  436. }
  437. }
  438. }
  439. catch (Exception e)
  440. {
  441. m_log.Warn("[Materials]: exception decoding zipped CAP payload ", e);
  442. //return "";
  443. }
  444. }
  445. resp["Zipped"] = ZCompressOSD(respArr, false);
  446. string response = OSDParser.SerializeLLSDXmlString(resp);
  447. //m_log.Debug("[Materials]: cap request: " + request);
  448. //m_log.Debug("[Materials]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary()));
  449. //m_log.Debug("[Materials]: cap response: " + response);
  450. return response;
  451. }
  452. public string RenderMaterialsPutCap(string request, UUID agentID)
  453. {
  454. OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
  455. OSDMap resp = new OSDMap();
  456. OSDMap materialsFromViewer = null;
  457. OSDArray respArr = new OSDArray();
  458. OSD tmpOSD;
  459. HashSet<SceneObjectPart> parts = new HashSet<SceneObjectPart>();
  460. if (req.TryGetValue("Zipped", out tmpOSD))
  461. {
  462. OSD osd = null;
  463. byte[] inBytes = tmpOSD.AsBinary();
  464. try
  465. {
  466. osd = ZDecompressBytesToOsd(inBytes);
  467. if (osd != null && osd is OSDMap)
  468. {
  469. materialsFromViewer = osd as OSDMap;
  470. if (materialsFromViewer.TryGetValue("FullMaterialsPerFace", out tmpOSD) && (tmpOSD is OSDArray))
  471. {
  472. OSDArray matsArr = tmpOSD as OSDArray;
  473. try
  474. {
  475. foreach (OSDMap matsMap in matsArr)
  476. {
  477. uint primLocalID = 0;
  478. try
  479. {
  480. primLocalID = matsMap["ID"].AsUInteger();
  481. }
  482. catch (Exception e)
  483. {
  484. m_log.Warn("[Materials]: cannot decode \"ID\" from matsMap: " + e.Message);
  485. continue;
  486. }
  487. SceneObjectPart sop = m_scene.GetSceneObjectPart(primLocalID);
  488. if (sop == null)
  489. {
  490. m_log.WarnFormat("[Materials]: SOP not found for localId: {0}", primLocalID.ToString());
  491. continue;
  492. }
  493. if (!m_scene.Permissions.CanEditObject(sop.UUID, agentID))
  494. {
  495. m_log.WarnFormat("User {0} can't edit object {1} {2}", agentID, sop.Name, sop.UUID);
  496. continue;
  497. }
  498. OSDMap mat = null;
  499. try
  500. {
  501. mat = matsMap["Material"] as OSDMap;
  502. }
  503. catch (Exception e)
  504. {
  505. m_log.Warn("[Materials]: cannot decode \"Material\" from matsMap: " + e.Message);
  506. continue;
  507. }
  508. Primitive.TextureEntry te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length);
  509. if (te == null)
  510. {
  511. m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID);
  512. continue;
  513. }
  514. int face = -1;
  515. UUID oldid = UUID.Zero;
  516. Primitive.TextureEntryFace faceEntry = null;
  517. if (matsMap.TryGetValue("Face", out tmpOSD))
  518. {
  519. face = tmpOSD.AsInteger();
  520. faceEntry = te.CreateFace((uint)face);
  521. }
  522. else
  523. faceEntry = te.DefaultTexture;
  524. if (faceEntry == null)
  525. continue;
  526. UUID id;
  527. FaceMaterial newFaceMat = null;
  528. if (mat == null)
  529. {
  530. // This happens then the user removes a material from a prim
  531. id = UUID.Zero;
  532. }
  533. else
  534. {
  535. newFaceMat = new FaceMaterial(mat);
  536. if(newFaceMat.DiffuseAlphaMode == 1
  537. && newFaceMat.NormalMapID == UUID.Zero
  538. && newFaceMat.SpecularMapID == UUID.Zero
  539. )
  540. id = UUID.Zero;
  541. else
  542. {
  543. newFaceMat.genID();
  544. id = newFaceMat.ID;
  545. }
  546. }
  547. oldid = faceEntry.MaterialID;
  548. if(oldid == id)
  549. continue;
  550. if (faceEntry != null)
  551. {
  552. faceEntry.MaterialID = id;
  553. //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id);
  554. // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually
  555. sop.Shape.TextureEntry = te.GetBytes(9);
  556. }
  557. if(oldid != UUID.Zero)
  558. RemoveMaterial(oldid);
  559. lock(materialslock)
  560. {
  561. if(id != UUID.Zero)
  562. {
  563. if (m_Materials.ContainsKey(id))
  564. m_MaterialsRefCount[id]++;
  565. else
  566. {
  567. m_Materials[id] = newFaceMat;
  568. m_MaterialsRefCount[id] = 1;
  569. m_changed[newFaceMat] = Util.GetTimeStamp();
  570. }
  571. }
  572. }
  573. if(!parts.Contains(sop))
  574. parts.Add(sop);
  575. }
  576. foreach(SceneObjectPart sop in parts)
  577. {
  578. if (sop.ParentGroup != null && !sop.ParentGroup.IsDeleted)
  579. {
  580. sop.TriggerScriptChangedEvent(Changed.TEXTURE);
  581. sop.ScheduleFullUpdate();
  582. sop.ParentGroup.HasGroupChanged = true;
  583. }
  584. }
  585. }
  586. catch (Exception e)
  587. {
  588. m_log.Warn("[Materials]: exception processing received material ", e);
  589. }
  590. }
  591. }
  592. }
  593. catch (Exception e)
  594. {
  595. m_log.Warn("[Materials]: exception decoding zipped CAP payload ", e);
  596. //return "";
  597. }
  598. }
  599. resp["Zipped"] = ZCompressOSD(respArr, false);
  600. string response = OSDParser.SerializeLLSDXmlString(resp);
  601. //m_log.Debug("[Materials]: cap request: " + request);
  602. //m_log.Debug("[Materials]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary()));
  603. //m_log.Debug("[Materials]: cap response: " + response);
  604. return response;
  605. }
  606. private AssetBase MakeAsset(FaceMaterial fm, bool local)
  607. {
  608. // this are not true assets, should had never been...
  609. AssetBase asset = null;
  610. string txt = fm.toLLSDxml();
  611. byte[] data = System.Text.Encoding.ASCII.GetBytes(txt);
  612. asset = new AssetBase(fm.ID, "llmaterial", (sbyte)OpenSimAssetType.Material, "00000000-0000-0000-0000-000000000000");
  613. asset.Data = data;
  614. asset.Local = local;
  615. return asset;
  616. }
  617. public string RenderMaterialsGetCap(string request)
  618. {
  619. OSDMap resp = new OSDMap();
  620. OSDArray allOsd = new OSDArray();
  621. /*
  622. // this violates all idea of caching and geting things only if needed, so disabled
  623. int matsCount = 0;
  624. lock (m_Materials)
  625. {
  626. foreach (KeyValuePair<UUID, FaceMaterial> kvp in m_Materials)
  627. {
  628. OSDMap matMap = new OSDMap();
  629. matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes());
  630. matMap["Material"] = kvp.Value.toOSD();
  631. allOsd.Add(matMap);
  632. matsCount++;
  633. }
  634. }
  635. */
  636. resp["Zipped"] = ZCompressOSD(allOsd, false);
  637. return OSDParser.SerializeLLSDXmlString(resp);
  638. }
  639. private static string ZippedOsdBytesToString(byte[] bytes)
  640. {
  641. try
  642. {
  643. return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes));
  644. }
  645. catch (Exception e)
  646. {
  647. return "ZippedOsdBytesToString caught an exception: " + e.ToString();
  648. }
  649. }
  650. public static OSD ZCompressOSD(OSD inOsd, bool useHeader)
  651. {
  652. OSD osd = null;
  653. byte[] data = OSDParser.SerializeLLSDBinary(inOsd, useHeader);
  654. using (MemoryStream msSinkCompressed = new MemoryStream())
  655. {
  656. using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed,
  657. Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true))
  658. {
  659. zOut.Write(data, 0, data.Length);
  660. }
  661. msSinkCompressed.Seek(0L, SeekOrigin.Begin);
  662. osd = OSD.FromBinary(msSinkCompressed.ToArray());
  663. }
  664. return osd;
  665. }
  666. public static OSD ZDecompressBytesToOsd(byte[] input)
  667. {
  668. OSD osd = null;
  669. using (MemoryStream msSinkUnCompressed = new MemoryStream())
  670. {
  671. using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true))
  672. {
  673. zOut.Write(input, 0, input.Length);
  674. }
  675. msSinkUnCompressed.Seek(0L, SeekOrigin.Begin);
  676. osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray());
  677. }
  678. return osd;
  679. }
  680. public FaceMaterial GetMaterial(UUID ID)
  681. {
  682. FaceMaterial fm = null;
  683. if(m_Materials.TryGetValue(ID, out fm))
  684. return fm;
  685. return null;
  686. }
  687. public FaceMaterial GetMaterialCopy(UUID ID)
  688. {
  689. FaceMaterial fm = null;
  690. if(m_Materials.TryGetValue(ID, out fm))
  691. return new FaceMaterial(fm);
  692. return null;
  693. }
  694. public UUID AddNewMaterial(FaceMaterial fm)
  695. {
  696. if(fm.DiffuseAlphaMode == 1 && fm.NormalMapID == UUID.Zero && fm.SpecularMapID == UUID.Zero)
  697. {
  698. fm.ID = UUID.Zero;
  699. return UUID.Zero;
  700. }
  701. fm.genID();
  702. UUID id = fm.ID;
  703. lock(materialslock)
  704. {
  705. if(m_Materials.ContainsKey(id))
  706. m_MaterialsRefCount[id]++;
  707. else
  708. {
  709. m_Materials[id] = fm;
  710. m_MaterialsRefCount[id] = 1;
  711. m_changed[fm] = Util.GetTimeStamp();
  712. }
  713. }
  714. return id;
  715. }
  716. public void RemoveMaterial(UUID id)
  717. {
  718. if(id == UUID.Zero)
  719. return;
  720. lock(materialslock)
  721. {
  722. if(m_Materials.ContainsKey(id))
  723. {
  724. m_MaterialsRefCount[id]--;
  725. if(m_MaterialsRefCount[id] <= 0)
  726. {
  727. FaceMaterial fm = m_Materials[id];
  728. m_changed.Remove(fm);
  729. m_Materials.Remove(id);
  730. m_MaterialsRefCount.Remove(id);
  731. m_cache.Expire(id.ToString());
  732. }
  733. }
  734. }
  735. }
  736. }
  737. }