diff --git a/OpenSim/Region/Framework/Scenes/SOPMaterial.cs b/OpenSim/Region/Framework/Scenes/SOPMaterial.cs index d38ef615ef..e4b9380271 100644 --- a/OpenSim/Region/Framework/Scenes/SOPMaterial.cs +++ b/OpenSim/Region/Framework/Scenes/SOPMaterial.cs @@ -26,10 +26,12 @@ */ using System; -using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Security.Cryptography; // for computing md5 hash +using OpenSim.Framework; using OpenMetaverse; using OpenMetaverse.StructuredData; -using OpenSim.Framework; namespace OpenSim.Region.Framework.Scenes { @@ -93,38 +95,74 @@ namespace OpenSim.Region.Framework.Scenes } } + [StructLayout(LayoutKind.Sequential)] public class FaceMaterial { - public UUID ID; - public UUID NormalMapID = UUID.Zero; - public float NormalOffsetX = 0.0f; - public float NormalOffsetY = 0.0f; - public float NormalRepeatX = 1.0f; - public float NormalRepeatY = 1.0f; - public float NormalRotation = 0.0f; + // ll material data + public byte DiffuseAlphaMode = 1; + public byte AlphaMaskCutoff = 0; + public byte SpecularLightExponent = 51; + public byte EnvironmentIntensity = 0; + // need to have 4 bytes here + public float NormalOffsetX = 0.0f; + public float NormalOffsetY = 0.0f; + public float NormalRepeatX = 1.0f; + public float NormalRepeatY = 1.0f; + public float NormalRotation = 0.0f; - public UUID SpecularMapID = UUID.Zero; - public float SpecularOffsetX = 0.0f; - public float SpecularOffsetY = 0.0f; - public float SpecularRepeatX = 1.0f; - public float SpecularRepeatY = 1.0f; - public float SpecularRotation = 0.0f; + public float SpecularOffsetX = 0.0f; + public float SpecularOffsetY = 0.0f; + public float SpecularRepeatX = 1.0f; + public float SpecularRepeatY = 1.0f; + public float SpecularRotation = 0.0f; - public Color4 SpecularLightColor = new Color4(255,255,255,255); - public Byte SpecularLightExponent = 51; - public Byte EnvironmentIntensity = 0; - public Byte DiffuseAlphaMode = 1; - public Byte AlphaMaskCutoff = 0; + public byte SpecularLightColorR = 255; + public byte SpecularLightColorG = 255; + public byte SpecularLightColorB = 255; + public byte SpecularLightColorA = 255; + // data size 12 ints so far + public UUID NormalMapID = UUID.Zero; + public UUID SpecularMapID = UUID.Zero; + + // other data + public UUID ID; + private int inthash; + private bool validinthash; public FaceMaterial() { } - public FaceMaterial(UUID pID, OSDMap mat) + public FaceMaterial(FaceMaterial other) + { + if(other == null) + return; + + DiffuseAlphaMode = other.DiffuseAlphaMode; + AlphaMaskCutoff = other.AlphaMaskCutoff; + SpecularLightExponent = other.SpecularLightExponent; + EnvironmentIntensity = other.EnvironmentIntensity; + NormalOffsetX = other.NormalOffsetX; + NormalOffsetY = other.NormalOffsetY; + NormalRepeatX = other.NormalRepeatX; + NormalRepeatY = other.NormalRepeatY; + NormalRotation = other.NormalRotation; + SpecularOffsetX = other.SpecularOffsetX; + SpecularOffsetY = other.SpecularOffsetY; + SpecularRepeatX = other.SpecularRepeatX; + SpecularRepeatY = other.SpecularRepeatY; + SpecularRotation = other.SpecularRotation; + SpecularLightColorR = other.SpecularLightColorR; + SpecularLightColorG = other.SpecularLightColorG; + SpecularLightColorB = other.SpecularLightColorB; + NormalMapID = other.NormalMapID; + SpecularMapID = other.SpecularMapID; + } + + public FaceMaterial(OSDMap mat) { - ID = pID; if(mat == null) return; - float scale = 0.0001f; + const float scale = 0.0001f; NormalMapID = mat["NormMap"].AsUUID(); NormalOffsetX = scale * (float)mat["NormOffsetX"].AsReal(); NormalOffsetY = scale * (float)mat["NormOffsetY"].AsReal(); @@ -138,14 +176,88 @@ namespace OpenSim.Region.Framework.Scenes SpecularRepeatX = scale * (float)mat["SpecRepeatX"].AsReal(); SpecularRepeatY = scale * (float)mat["SpecRepeatY"].AsReal(); SpecularRotation = scale * (float)mat["SpecRotation"].AsReal(); + + Color4 SpecularLightColortmp = mat["SpecColor"].AsColor4(); // we can read as color4 + SpecularLightColorR = (byte)(SpecularLightColortmp.R); + SpecularLightColorG = (byte)(SpecularLightColortmp.G); + SpecularLightColorB = (byte)(SpecularLightColortmp.B); - SpecularLightColor = mat["SpecColor"].AsColor4(); SpecularLightExponent = (Byte)mat["SpecExp"].AsUInteger(); EnvironmentIntensity = (Byte)mat["EnvIntensity"].AsUInteger(); DiffuseAlphaMode = (Byte)mat["DiffuseAlphaMode"].AsUInteger(); AlphaMaskCutoff = (Byte)mat["AlphaMaskCutoff"].AsUInteger(); } + public void genID() + { + string lslx = toLLSDxml(); + Byte[] data = System.Text.Encoding.ASCII.GetBytes(lslx); + using (var md5 = MD5.Create()) + ID = new UUID(md5.ComputeHash(data), 0); + } + + public unsafe override int GetHashCode() + { + if(!validinthash) + { + unchecked + { + // if you don't like this, don't read... + int* ptr; + fixed(byte* ptrbase = &DiffuseAlphaMode) + { + ptr = (int*)ptrbase; + inthash = *ptr; + for(int i = 0; i < 11; i++) + inthash ^= *ptr++; + } + fixed(Guid* ptrbase = &NormalMapID.Guid) + { + ptr = (int*)ptrbase; + for(int i = 0; i < 16; i++) + inthash ^= ptr[i]; + } + fixed(Guid* ptrbase = &SpecularMapID.Guid) + { + ptr = (int*)ptrbase; + for(int i = 0; i < 16; i++) + inthash ^= ptr[i]; + } + } + validinthash = true; + } + return inthash; + } + + public override bool Equals(Object o) + { + if(o == null || !(o is FaceMaterial)) + return false; + + FaceMaterial other = (FaceMaterial)o; + return ( + DiffuseAlphaMode == other.DiffuseAlphaMode + && AlphaMaskCutoff == other.AlphaMaskCutoff + && SpecularLightExponent == other.SpecularLightExponent + && EnvironmentIntensity == other.EnvironmentIntensity + && NormalMapID == other.NormalMapID + && NormalOffsetX == other.NormalOffsetX + && NormalOffsetY == other.NormalOffsetY + && NormalRepeatX == other.NormalRepeatX + && NormalRepeatY == other.NormalRepeatY + && NormalRotation == other.NormalRotation + && SpecularMapID == other.SpecularMapID + && SpecularOffsetX == other.SpecularOffsetX + && SpecularOffsetY == other.SpecularOffsetY + && SpecularRepeatX == other.SpecularRepeatX + && SpecularRepeatY == other.SpecularRepeatY + && SpecularRotation == other.SpecularRotation + && SpecularLightColorR == other.SpecularLightColorR + && SpecularLightColorG == other.SpecularLightColorG + && SpecularLightColorB == other.SpecularLightColorB + ); + } + public OSDMap toOSD() { OSDMap mat = new OSDMap(); @@ -165,7 +277,12 @@ namespace OpenSim.Region.Framework.Scenes mat["SpecRepeatY"] = (int) (scale * SpecularRepeatY); mat["SpecRotation"] = (int) (scale * SpecularRotation); - mat["SpecColor"] = SpecularLightColor; + OSDArray carray = new OSDArray(4); + carray.Add(SpecularLightColorR); + carray.Add(SpecularLightColorG); + carray.Add(SpecularLightColorB); + carray.Add(255); // solid color + mat["SpecColor"] = carray; mat["SpecExp"] = SpecularLightExponent; mat["EnvIntensity"] = EnvironmentIntensity; mat["DiffuseAlphaMode"] = DiffuseAlphaMode; @@ -173,5 +290,53 @@ namespace OpenSim.Region.Framework.Scenes return mat; } + + public string toLLSDxml(StringBuilder sb = null) + { + const float scale = 10000f; + bool fullLLSD = false; + if(sb == null) + { + + sb = LLSDxmlEncode.Start(1024,false); + fullLLSD = true; + } + + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("NormMap", NormalMapID, sb); + LLSDxmlEncode.AddElem("NormOffsetX", (int) (scale * NormalOffsetX + 0.5f), sb); + LLSDxmlEncode.AddElem("NormOffsetY", (int) (scale * NormalOffsetY + 0.5f), sb); + LLSDxmlEncode.AddElem("NormRepeatX", (int) (scale * NormalRepeatX + 0.5f), sb); + LLSDxmlEncode.AddElem("NormRepeatY", (int) (scale * NormalRepeatY + 0.5f), sb); + LLSDxmlEncode.AddElem("NormRotation", (int) (scale * NormalRotation + 0.5f), sb); + + LLSDxmlEncode.AddElem("SpecMap", SpecularMapID, sb); + LLSDxmlEncode.AddElem("SpecOffsetX", (int) (scale * SpecularOffsetX + 0.5f), sb); + LLSDxmlEncode.AddElem("SpecOffsetY", (int) (scale * SpecularOffsetY + 0.5f), sb); + LLSDxmlEncode.AddElem("SpecRepeatX", (int) (scale * SpecularRepeatX + 0.5f), sb); + LLSDxmlEncode.AddElem("SpecRepeatY", (int) (scale * SpecularRepeatY + 0.5f), sb); + LLSDxmlEncode.AddElem("SpecRotation", (int) (scale * SpecularRotation + 0.5f), sb); + + LLSDxmlEncode.AddArray("SpecColor", sb); + LLSDxmlEncode.AddElem(SpecularLightColorR, sb); + LLSDxmlEncode.AddElem(SpecularLightColorG, sb); + LLSDxmlEncode.AddElem(SpecularLightColorB, sb); + LLSDxmlEncode.AddElem(255, sb); + LLSDxmlEncode.AddEndArray(sb); + + LLSDxmlEncode.AddElem("SpecExp", SpecularLightExponent, sb); + LLSDxmlEncode.AddElem("EnvIntensity", EnvironmentIntensity, sb); + LLSDxmlEncode.AddElem("DiffuseAlphaMode", DiffuseAlphaMode, sb); + LLSDxmlEncode.AddElem("AlphaMaskCutoff", AlphaMaskCutoff, sb); + + LLSDxmlEncode.AddEndMap(sb); + + if(fullLLSD) + { + return LLSDxmlEncode.End(sb); + } + else + return String.Empty; // ignored if appending + } } } \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index e8cb052263..62e1e5cd03 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -46,16 +46,10 @@ using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; using Ionic.Zlib; -// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already -// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans -// the available DLLs -//[assembly: Addin("MaterialsModule", "1.0")] -//[assembly: AddinDependency("OpenSim", "0.8.1")] - namespace OpenSim.Region.OptionalModules.Materials { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsModule")] - public class MaterialsModule : INonSharedRegionModule + public class MaterialsModule : INonSharedRegionModule, IMaterialsModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -67,12 +61,12 @@ namespace OpenSim.Region.OptionalModules.Materials private Scene m_scene = null; private bool m_enabled = false; private int m_maxMaterialsPerTransaction = 50; + private object materialslock = new object(); - public Dictionary m_Materials = new Dictionary(); + public Dictionary m_Materials = new Dictionary(); public Dictionary m_MaterialsRefCount = new Dictionary(); - private Dictionary m_changes = new Dictionary(); - private Dictionary m_changesTime = new Dictionary(); + private Dictionary m_changed = new Dictionary(); public void Initialise(IConfigSource source) { @@ -101,54 +95,72 @@ namespace OpenSim.Region.OptionalModules.Materials return; m_scene = scene; + m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; + m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManager_OnObjectDeleteFromScene; m_scene.EventManager.OnBackup += EventManager_OnBackup; } + public void RemoveRegion(Scene scene) + { + if (!m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; + m_scene.EventManager.OnObjectBeingRemovedFromScene -= EventManager_OnObjectDeleteFromScene; + m_scene.EventManager.OnBackup -= EventManager_OnBackup; + m_scene.UnregisterModuleInterface(this); + } + + public void RegionLoaded(Scene scene) + { + if (!m_enabled) return; + + m_cache = scene.RequestModuleInterface(); + ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface(); + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + } + private void EventManager_OnBackup(ISimulationDataService datastore, bool forcedBackup) { - List toStore; - List hashlist; + List toStore; - - lock (m_Materials) + lock (materialslock) { - if(m_changes.Count == 0) + if(m_changed.Count == 0) return; if(forcedBackup) { - toStore = new List(m_changes.Values); - m_changes.Clear(); - m_changesTime.Clear(); + toStore = new List(m_changed.Keys); + m_changed.Clear(); } else { - toStore = new List(); - hashlist = new List(); - double storetime = Util.GetTimeStampMS() - 60000; - foreach(KeyValuePair kvp in m_changesTime) + toStore = new List(); + double storetime = Util.GetTimeStamp() - 60.0; + foreach(KeyValuePair kvp in m_changed) { if(kvp.Value < storetime) { - toStore.Add(m_changes[kvp.Key]); - hashlist.Add(kvp.Key); + toStore.Add(kvp.Key); } } - foreach(ulong u in hashlist) + foreach(FaceMaterial fm in toStore) { - m_changesTime.Remove(u); - m_changes.Remove(u); + m_changed.Remove(fm); } } if(toStore.Count > 0) Util.FireAndForget(delegate { - foreach(AssetBase a in toStore) + foreach(FaceMaterial fm in toStore) { - a.Local = false; + AssetBase a = MakeAsset(fm, false); m_scene.AssetService.Store(a); } }); @@ -162,6 +174,13 @@ namespace OpenSim.Region.OptionalModules.Materials GetStoredMaterialsInPart(part); } + private void EventManager_OnObjectDeleteFromScene(SceneObjectGroup obj) + { + foreach (var part in obj.Parts) + if (part != null) + RemoveMaterialsInPart(part); + } + private void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) { string capsBase = "/CAPS/" + caps.CapsObjectPath; @@ -193,26 +212,6 @@ namespace OpenSim.Region.OptionalModules.Materials MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); } - public void RemoveRegion(Scene scene) - { - if (!m_enabled) - return; - - m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; - m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; - m_scene.EventManager.OnBackup -= EventManager_OnBackup; - } - - public void RegionLoaded(Scene scene) - { - if (!m_enabled) return; - - m_cache = scene.RequestModuleInterface(); - ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface(); - if (featuresModule != null) - featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; - } - private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) { features["MaxMaterialsPerTransaction"] = m_maxMaterialsPerTransaction; @@ -222,14 +221,16 @@ namespace OpenSim.Region.OptionalModules.Materials /// Finds any legacy materials stored in DynAttrs that may exist for this part and add them to 'm_regionMaterials'. /// /// - private void GetLegacyStoredMaterialsInPart(SceneObjectPart part) + private bool GetLegacyStoredMaterialsInPart(SceneObjectPart part) { if (part.DynAttrs == null) - return; + return false; OSD OSMaterials = null; OSDArray matsArr = null; + bool partchanged = false; + lock (part.DynAttrs) { if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) @@ -237,20 +238,22 @@ namespace OpenSim.Region.OptionalModules.Materials OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); if (materialsStore == null) - return; + return false; materialsStore.TryGetValue("Materials", out OSMaterials); + part.DynAttrs.RemoveStore("OpenSim", "Materials"); + partchanged = true; } if (OSMaterials != null && OSMaterials is OSDArray) matsArr = OSMaterials as OSDArray; else - return; + return partchanged; } if (matsArr == null) - return; - + return partchanged; + foreach (OSD elemOsd in matsArr) { if (elemOsd != null && elemOsd is OSDMap) @@ -260,16 +263,24 @@ namespace OpenSim.Region.OptionalModules.Materials { try { - lock (m_Materials) + lock (materialslock) { UUID id = matMap["ID"].AsUUID(); if(m_Materials.ContainsKey(id)) - m_MaterialsRefCount[id]++; - else - { - m_Materials[id] = (OSDMap)matMap["Material"]; - m_MaterialsRefCount[id] = 1; - } + continue; + + OSDMap theMatMap = (OSDMap)matMap["Material"]; + FaceMaterial fmat = new FaceMaterial(theMatMap); + + if(fmat == null || + ( fmat.DiffuseAlphaMode == 1 + && fmat.NormalMapID == UUID.Zero + && fmat.SpecularMapID == UUID.Zero)) + continue; + + fmat.ID = id; + m_Materials[id] = fmat; + m_MaterialsRefCount[id] = 0; } } catch (Exception e) @@ -279,6 +290,7 @@ namespace OpenSim.Region.OptionalModules.Materials } } } + return partchanged; } /// @@ -289,14 +301,16 @@ namespace OpenSim.Region.OptionalModules.Materials if (part.Shape == null) return; + bool partchanged = false; + bool facechanged = false; var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); if (te == null) return; - GetLegacyStoredMaterialsInPart(part); + partchanged = GetLegacyStoredMaterialsInPart(part); if (te.DefaultTexture != null) - GetStoredMaterialInFace(part, te.DefaultTexture); + facechanged = GetStoredMaterialInFace(part, te.DefaultTexture); else m_log.WarnFormat( "[Materials]: Default texture for part {0} (part of object {1}) in {2} unexpectedly null. Ignoring.", @@ -305,36 +319,47 @@ namespace OpenSim.Region.OptionalModules.Materials foreach (Primitive.TextureEntryFace face in te.FaceTextures) { if (face != null) - GetStoredMaterialInFace(part, face); + facechanged |= GetStoredMaterialInFace(part, face); + } + + if(facechanged) + part.Shape.TextureEntry = te.GetBytes(); + + if(facechanged || partchanged) + { + if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) + part.ParentGroup.HasGroupChanged = true; } } /// /// Find the materials used in one Face, and add them to 'm_regionMaterials'. /// - private void GetStoredMaterialInFace(SceneObjectPart part, Primitive.TextureEntryFace face) + private bool GetStoredMaterialInFace(SceneObjectPart part, Primitive.TextureEntryFace face) { UUID id = face.MaterialID; if (id == UUID.Zero) - return; + return false; - lock (m_Materials) + OSDMap mat; + lock (materialslock) { - if (m_Materials.ContainsKey(id)) + if(m_Materials.ContainsKey(id)) { m_MaterialsRefCount[id]++; - return; + return false; } AssetBase matAsset = m_scene.AssetService.Get(id.ToString()); if (matAsset == null || matAsset.Data == null || matAsset.Data.Length == 0 ) { - //m_log.WarnFormat("[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id); - return; + // grid may just be down... + return false; } byte[] data = matAsset.Data; - OSDMap mat; + + string txt = System.Text.Encoding.ASCII.GetString(data); try { mat = (OSDMap)OSDParser.DeserializeLLSDXml(data); @@ -342,11 +367,76 @@ namespace OpenSim.Region.OptionalModules.Materials catch (Exception e) { m_log.WarnFormat("[Materials]: cannot decode material asset {0}: {1}", id, e.Message); - return; + return false; } - m_Materials[id] = mat; - m_MaterialsRefCount[id] = 1; + FaceMaterial fmat = new FaceMaterial(mat); + + if(fmat == null || + (fmat.DiffuseAlphaMode == 1 + && fmat.NormalMapID == UUID.Zero + && fmat.SpecularMapID == UUID.Zero)) + { + face.MaterialID = UUID.Zero; + return true; + } + + fmat.ID = id; + + if (m_Materials.ContainsKey(id)) + { + m_MaterialsRefCount[id]++; + } + else + { + m_Materials[id] = fmat; + m_MaterialsRefCount[id] = 1; + } + return false; + } + } + + private void RemoveMaterialsInPart(SceneObjectPart part) + { + if (part.Shape == null) + return; + + var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); + if (te == null) + return; + + if (te.DefaultTexture != null) + RemoveMaterialInFace(te.DefaultTexture); + + foreach (Primitive.TextureEntryFace face in te.FaceTextures) + { + if(face != null) + RemoveMaterialInFace(face); + } + } + + private void RemoveMaterialInFace(Primitive.TextureEntryFace face) + { + UUID id = face.MaterialID; + if (id == UUID.Zero) + return; + + lock (materialslock) + { + if(!m_Materials.ContainsKey(id)) + return; + else + { + m_MaterialsRefCount[id]--; + if(m_MaterialsRefCount[id] <= 0) + { + FaceMaterial oldFaceMat = m_Materials[id]; + m_changed.Remove(oldFaceMat); + m_Materials.Remove(id); + m_MaterialsRefCount.Remove(id); + m_cache.Expire(id.ToString()); + } + } } } @@ -375,13 +465,13 @@ namespace OpenSim.Region.OptionalModules.Materials { UUID id = new UUID(elem.AsBinary(), 0); - lock (m_Materials) + lock (materialslock) { if (m_Materials.ContainsKey(id)) { OSDMap matMap = new OSDMap(); matMap["ID"] = OSD.FromBinary(id.GetBytes()); - matMap["Material"] = m_Materials[id]; + matMap["Material"] = m_Materials[id].toOSD(); respArr.Add(matMap); } else @@ -455,10 +545,12 @@ namespace OpenSim.Region.OptionalModules.Materials foreach (OSDMap matsMap in matsArr) { uint primLocalID = 0; - try { + try + { primLocalID = matsMap["ID"].AsUInteger(); } - catch (Exception e) { + catch (Exception e) + { m_log.Warn("[Materials]: cannot decode \"ID\" from matsMap: " + e.Message); continue; } @@ -494,7 +586,22 @@ namespace OpenSim.Region.OptionalModules.Materials continue; } + int face = -1; + UUID oldid = UUID.Zero; + Primitive.TextureEntryFace faceEntry = null; + if (matsMap.ContainsKey("Face")) + { + face = matsMap["Face"].AsInteger(); + faceEntry = te.CreateFace((uint)face); + } + else + faceEntry = te.DefaultTexture; + + if (faceEntry == null) + continue; + UUID id; + FaceMaterial newFaceMat = null; if (mat == null) { // This happens then the user removes a material from a prim @@ -502,60 +609,48 @@ namespace OpenSim.Region.OptionalModules.Materials } else { - id = getNewID(mat); - } - - int face = -1; - UUID oldid = UUID.Zero; - if (matsMap.ContainsKey("Face")) - { - face = matsMap["Face"].AsInteger(); - Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face); - oldid = faceEntry.MaterialID; - faceEntry.MaterialID = id; - } - else - { - if (te.DefaultTexture == null) - m_log.WarnFormat("[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); + newFaceMat = new FaceMaterial(mat); + if(newFaceMat.DiffuseAlphaMode == 1 + && newFaceMat.NormalMapID == UUID.Zero + && newFaceMat.SpecularMapID == UUID.Zero + ) + id = UUID.Zero; else { - oldid = te.DefaultTexture.MaterialID; - te.DefaultTexture.MaterialID = id; + newFaceMat.genID(); + id = newFaceMat.ID; } } - //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); + oldid = faceEntry.MaterialID; - // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually - sop.Shape.TextureEntry = te.GetBytes(); + if(oldid == id) + continue; - lock(m_Materials) + if (faceEntry != null) { - if(oldid != UUID.Zero && m_MaterialsRefCount.ContainsKey(oldid)) - { - m_MaterialsRefCount[oldid]--; - if(m_MaterialsRefCount[oldid] <= 0) - { - m_Materials.Remove(oldid); - m_MaterialsRefCount.Remove(oldid); - m_cache.Expire(oldid.ToString()); - } - } + faceEntry.MaterialID = id; + //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); + + // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually + sop.Shape.TextureEntry = te.GetBytes(); + } + + if(oldid != UUID.Zero) + RemoveMaterial(oldid); + + lock(materialslock) + { if(id != UUID.Zero) { - AssetBase asset = CacheMaterialAsAsset(id, agentID, mat, sop); - if(asset != null) + if (m_Materials.ContainsKey(id)) + m_MaterialsRefCount[id]++; + else { - ulong materialHash = (ulong)primLocalID << 32; - if(face < 0) - materialHash += 0xffffffff; - else - materialHash +=(ulong)face; - - m_changes[materialHash] = asset; - m_changesTime[materialHash] = Util.GetTimeStampMS(); + m_Materials[id] = newFaceMat; + m_MaterialsRefCount[id] = 1; + m_changed[newFaceMat] = Util.GetTimeStamp(); } } } @@ -598,119 +693,39 @@ namespace OpenSim.Region.OptionalModules.Materials return response; } - private UUID getNewID(OSDMap mat) - { - // ugly and done twice but keep compatibility for now - Byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); - using (var md5 = MD5.Create()) - return new UUID(md5.ComputeHash(data), 0); - } - - private AssetBase CacheMaterialAsAsset(UUID id, UUID agentID, OSDMap mat, SceneObjectPart sop) + private AssetBase MakeAsset(FaceMaterial fm, bool local) { + // this are not true assets, should had never been... AssetBase asset = null; - lock (m_Materials) - { - if (!m_Materials.ContainsKey(id)) - { - m_Materials[id] = mat; - m_MaterialsRefCount[id] = 1; + string txt = fm.toLLSDxml(); + byte[] data = System.Text.Encoding.ASCII.GetBytes(txt); - byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); - - // This asset might exist already, but it's ok to try to store it again - string name = "Material " + ChooseMaterialName(mat, sop); - name = name.Substring(0, Math.Min(64, name.Length)).Trim(); - asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); - asset.Data = data; - asset.Local = true; - m_cache.Cache(asset); - } - else - m_MaterialsRefCount[id]++; - } + asset = new AssetBase(fm.ID, "llmaterial", (sbyte)OpenSimAssetType.Material, "00000000-0000-0000-0000-000000000000"); + asset.Data = data; + asset.Local = local; return asset; } - private UUID StoreMaterialAsAsset(UUID agentID, OSDMap mat, SceneObjectPart sop) - { - UUID id; - // Material UUID = hash of the material's data. - // This makes materials deduplicate across the entire grid (but isn't otherwise required). - byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); - using (var md5 = MD5.Create()) - id = new UUID(md5.ComputeHash(data), 0); - - lock (m_Materials) - { - if (!m_Materials.ContainsKey(id)) - { - m_Materials[id] = mat; - m_MaterialsRefCount[id] = 1; - - // This asset might exist already, but it's ok to try to store it again - string name = "Material " + ChooseMaterialName(mat, sop); - name = name.Substring(0, Math.Min(64, name.Length)).Trim(); - AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); - asset.Data = data; - m_scene.AssetService.Store(asset); - } - else - m_MaterialsRefCount[id]++; - } - return id; - } - - /// - /// Use heuristics to choose a good name for the material. - /// - private string ChooseMaterialName(OSDMap mat, SceneObjectPart sop) - { - UUID normMap = mat["NormMap"].AsUUID(); - if (normMap != UUID.Zero) - { - AssetBase asset = m_scene.AssetService.GetCached(normMap.ToString()); - if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR")) - return asset.Name; - } - - UUID specMap = mat["SpecMap"].AsUUID(); - if (specMap != UUID.Zero) - { - AssetBase asset = m_scene.AssetService.GetCached(specMap.ToString()); - if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR")) - return asset.Name; - } - - if (sop.Name != "Primitive") - return sop.Name; - - if ((sop.ParentGroup != null) && (sop.ParentGroup.Name != "Primitive")) - return sop.ParentGroup.Name; - - return ""; - } - - public string RenderMaterialsGetCap(string request) { OSDMap resp = new OSDMap(); - int matsCount = 0; OSDArray allOsd = new OSDArray(); +/* + // this violates all idea of caching and geting things only if needed, so disabled + int matsCount = 0; lock (m_Materials) { - foreach (KeyValuePair kvp in m_Materials) + foreach (KeyValuePair kvp in m_Materials) { OSDMap matMap = new OSDMap(); - matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); - matMap["Material"] = kvp.Value; + matMap["Material"] = kvp.Value.toOSD(); allOsd.Add(matMap); matsCount++; } } - +*/ resp["Zipped"] = ZCompressOSD(allOsd, false); return OSDParser.SerializeLLSDXmlString(resp); @@ -728,18 +743,6 @@ namespace OpenSim.Region.OptionalModules.Materials } } - /// - /// computes a UUID by hashing a OSD object - /// - /// - /// - private static UUID HashOsd(OSD osd) - { - byte[] data = OSDParser.SerializeLLSDBinary(osd, false); - using (var md5 = MD5.Create()) - return new UUID(md5.ComputeHash(data), 0); - } - public static OSD ZCompressOSD(OSD inOsd, bool useHeader) { OSD osd = null; @@ -761,7 +764,6 @@ namespace OpenSim.Region.OptionalModules.Materials return osd; } - public static OSD ZDecompressBytesToOsd(byte[] input) { OSD osd = null; @@ -779,5 +781,67 @@ namespace OpenSim.Region.OptionalModules.Materials return osd; } + + public FaceMaterial GetMaterial(UUID ID) + { + FaceMaterial fm = null; + if(m_Materials.TryGetValue(ID, out fm)) + return fm; + return null; + } + + public FaceMaterial GetMaterialCopy(UUID ID) + { + FaceMaterial fm = null; + if(m_Materials.TryGetValue(ID, out fm)) + return new FaceMaterial(fm); + return null; + } + + public UUID AddNewMaterial(FaceMaterial fm) + { + if(fm.DiffuseAlphaMode == 1 && fm.NormalMapID == UUID.Zero && fm.SpecularMapID == UUID.Zero) + { + fm.ID = UUID.Zero; + return UUID.Zero; + } + + fm.genID(); + UUID id = fm.ID; + lock(materialslock) + { + if(m_Materials.ContainsKey(id)) + m_MaterialsRefCount[id]++; + else + { + m_Materials[id] = fm; + m_MaterialsRefCount[id] = 1; + m_changed[fm] = Util.GetTimeStamp(); + } + } + return id; + } + + public void RemoveMaterial(UUID id) + { + if(id == UUID.Zero) + return; + + lock(materialslock) + { + if(m_Materials.ContainsKey(id)) + { + m_MaterialsRefCount[id]--; + if(m_MaterialsRefCount[id] <= 0) + { + FaceMaterial fm = m_Materials[id]; + m_changed.Remove(fm); + m_Materials.Remove(id); + m_MaterialsRefCount.Remove(id); + m_cache.Expire(id.ToString()); + } + } + } + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 0124e32439..014de69361 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -124,6 +124,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected bool m_debuggerSafe = false; protected IUrlModule m_UrlModule = null; + protected IMaterialsModule m_materialsModule = null; + protected Dictionary m_userInfoCache = new Dictionary(); protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp. protected int m_sleepMsOnSetTexture = 200; @@ -306,6 +308,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine.World.RequestModuleInterface(); m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); m_SoundModule = m_ScriptEngine.World.RequestModuleInterface(); + m_materialsModule = m_ScriptEngine.World.RequestModuleInterface(); AsyncCommands = new AsyncCommandManager(m_ScriptEngine); } @@ -2458,7 +2461,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - Primitive.TextureEntry tex = part.Shape.Textures; int nsides = GetNumberOfSides(part); @@ -8910,6 +8912,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SceneObjectGroup parentgrp = part.ParentGroup; bool positionChanged = false; + bool materialChanged = false; LSL_Vector currentPosition = GetPartLocalPos(part); try @@ -10206,6 +10209,231 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; + case ScriptBaseClass.PRIM_ALPHA_MODE: + if (remain < 3) + return new LSL_List(); + + try + { + face = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + int materialAlphaMode; + try + { + materialAlphaMode = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + if(materialAlphaMode < 0 || materialAlphaMode > 3) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be 0 to 3", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + int materialMaskCutoff; + try + { + materialMaskCutoff = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + if(materialMaskCutoff < 0 || materialMaskCutoff > 255) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be 0 to 255", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + materialChanged |= SetMaterialAlphaMode(part, face, materialAlphaMode, materialMaskCutoff); + break; + + case ScriptBaseClass.PRIM_NORMAL: + if (remain < 5) + return new LSL_List(); + + try + { + face = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + string mapname = rules.Data[idx++].ToString(); + + UUID mapID = ScriptUtils.GetAssetIdFromItemName(m_host, mapname, (int)AssetType.Texture); + if (mapID == UUID.Zero) + { + if (!UUID.TryParse(mapname, out mapID)) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + } + + LSL_Vector mnrepeat; + try + { + mnrepeat = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Vector mnoffset; + try + { + mnoffset = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Float mnrot; + try + { + mnrot = rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + float repeatX = (float)Util.Clamp(mnrepeat.x,-100.0, 100.0); + float repeatY = (float)Util.Clamp(mnrepeat.y,-100.0, 100.0); + float offsetX = (float)Util.Clamp(mnoffset.x, 0, 1.0); + float offsetY = (float)Util.Clamp(mnoffset.y, 0, 1.0); + + materialChanged |= SetMaterialNormalMap(part, face, mapID, repeatX, repeatY, offsetX, offsetY, (float)mnrot); + break; + + case ScriptBaseClass.PRIM_SPECULAR: + if (remain < 8) + return new LSL_List(); + + try + { + face = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + string smapname = rules.Data[idx++].ToString(); + + UUID smapID = ScriptUtils.GetAssetIdFromItemName(m_host, smapname, (int)AssetType.Texture); + if (smapID == UUID.Zero) + { + if (!UUID.TryParse(smapname, out smapID)) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + } + + LSL_Vector msrepeat; + try + { + msrepeat = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Vector msoffset; + try + { + msoffset = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Float msrot; + try + { + msrot = rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Vector mscolor; + try + { + mscolor = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Integer msgloss; + try + { + msgloss = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + LSL_Integer msenv; + try + { + msenv = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + float srepeatX = (float)Util.Clamp(msrepeat.x, -100.0, 100.0); + float srepeatY = (float)Util.Clamp(msrepeat.y, -100.0, 100.0); + float soffsetX = (float)Util.Clamp(msoffset.x, -1.0, 1.0); + float soffsetY = (float)Util.Clamp(msoffset.y, -1.0, 1.0); + byte colorR = (byte)(255.0 * Util.Clamp(mscolor.x, 0, 1.0) + 0.5); + byte colorG = (byte)(255.0 * Util.Clamp(mscolor.y, 0, 1.0) + 0.5); + byte colorB = (byte)(255.0 * Util.Clamp(mscolor.z, 0, 1.0) + 0.5); + byte gloss = (byte)Util.Clamp((int)msgloss, 0, 255); + byte env = (byte)Util.Clamp((int)msenv, 0, 255); + + materialChanged |= SetMaterialSpecMap(part, face, smapID, srepeatX, srepeatY, soffsetX, soffsetY, + (float)msrot, colorR, colorG, colorB, gloss, env); + + break; + case ScriptBaseClass.PRIM_LINK_TARGET: if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. return new LSL_List(); @@ -10242,11 +10470,194 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.ScheduleTerseUpdate(); } } + if(materialChanged) + { + if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) + { + part.TriggerScriptChangedEvent(Changed.TEXTURE); + part.ScheduleFullUpdate(); + part.ParentGroup.HasGroupChanged = true; + } + } } return new LSL_List(); } + protected bool SetMaterialAlphaMode(SceneObjectPart part, int face, int materialAlphaMode, int materialMaskCutoff) + { + if(m_materialsModule == null) + return false; + + int nsides = part.GetNumberOfSides(); + + if(face == ScriptBaseClass.ALL_SIDES) + { + bool changed = false; + for(int i = 0; i < nsides; i++) + changed |= SetFaceMaterialAlphaMode(part, i, materialAlphaMode, materialMaskCutoff); + return changed; + } + + if( face >= 0 && face < nsides) + return SetFaceMaterialAlphaMode(part, face, materialAlphaMode, materialMaskCutoff); + + return false; + } + + protected bool SetFaceMaterialAlphaMode(SceneObjectPart part, int face, int materialAlphaMode, int materialMaskCutoff) + { + Primitive.TextureEntry tex = part.Shape.Textures; + Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); + if(texface == null) + return false; + + FaceMaterial mat = null; + UUID oldid = texface.MaterialID; + + if(oldid != UUID.Zero) + mat = m_materialsModule.GetMaterialCopy(oldid); + + if(mat == null) + mat = new FaceMaterial(); + + mat.DiffuseAlphaMode = (byte)materialAlphaMode; + mat.AlphaMaskCutoff = (byte)materialMaskCutoff; + + UUID id = m_materialsModule.AddNewMaterial(mat); + if(oldid == id) + return false; + + texface.MaterialID = id; + part.Shape.TextureEntry = tex.GetBytes(); + m_materialsModule.RemoveMaterial(oldid); + return true; + } + + protected bool SetMaterialNormalMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY, + float offsetX, float offsetY, float rot) + { + if(m_materialsModule == null) + return false; + + int nsides = part.GetNumberOfSides(); + + if(face == ScriptBaseClass.ALL_SIDES) + { + bool changed = false; + for(int i = 0; i < nsides; i++) + changed |= SetFaceMaterialNormalMap(part, i, mapID, repeatX, repeatY, offsetX, offsetY, rot); + return changed; + } + + if( face >= 0 && face < nsides) + return SetFaceMaterialNormalMap(part, face, mapID, repeatX, repeatY, offsetX, offsetY, rot); + + return false; + } + + protected bool SetFaceMaterialNormalMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY, + float offsetX, float offsetY, float rot) + + { + Primitive.TextureEntry tex = part.Shape.Textures; + Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); + if(texface == null) + return false; + + FaceMaterial mat = null; + UUID oldid = texface.MaterialID; + + if(oldid != UUID.Zero) + mat = m_materialsModule.GetMaterialCopy(oldid); + + if(mat == null) + mat = new FaceMaterial(); + + mat.NormalMapID = mapID; + mat.NormalOffsetX = offsetX; + mat.NormalOffsetY = offsetY; + mat.NormalRepeatX = repeatX; + mat.NormalRepeatY = repeatY; + mat.NormalRotation = rot; + + UUID id = m_materialsModule.AddNewMaterial(mat); + if(oldid == id) + return false; + + texface.MaterialID = id; + part.Shape.TextureEntry = tex.GetBytes(); + m_materialsModule.RemoveMaterial(oldid); + return true; + } + + protected bool SetMaterialSpecMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY, + float offsetX, float offsetY, float rot, + byte colorR, byte colorG, byte colorB, + byte gloss, byte env) + { + if(m_materialsModule == null) + return false; + + int nsides = part.GetNumberOfSides(); + + if(face == ScriptBaseClass.ALL_SIDES) + { + bool changed = false; + for(int i = 0; i < nsides; i++) + changed |= SetFaceMaterialSpecMap(part, i, mapID, repeatX, repeatY, offsetX, offsetY, rot, + colorR, colorG, colorB, gloss, env); + return changed; + } + + if( face >= 0 && face < nsides) + return SetFaceMaterialSpecMap(part, face, mapID, repeatX, repeatY, offsetX, offsetY, rot, + colorR, colorG, colorB, gloss, env); + + return false; + } + + protected bool SetFaceMaterialSpecMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY, + float offsetX, float offsetY, float rot, + byte colorR, byte colorG, byte colorB, + byte gloss, byte env) + { + Primitive.TextureEntry tex = part.Shape.Textures; + Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); + if(texface == null) + return false; + + FaceMaterial mat = null; + UUID oldid = texface.MaterialID; + + if(oldid != UUID.Zero) + mat = m_materialsModule.GetMaterialCopy(oldid); + + if(mat == null) + mat = new FaceMaterial(); + + mat.SpecularMapID = mapID; + mat.SpecularOffsetX = offsetX; + mat.SpecularOffsetY = offsetY; + mat.SpecularRepeatX = repeatX; + mat.SpecularRepeatY = repeatY; + mat.SpecularRotation = rot; + mat.SpecularLightColorR = colorR; + mat.SpecularLightColorG = colorG; + mat.SpecularLightColorB = colorB; + mat.SpecularLightExponent = gloss; + mat.EnvironmentIntensity = env; + + UUID id = m_materialsModule.AddNewMaterial(mat); + if(oldid == id) + return false; + + texface.MaterialID = id; + part.Shape.TextureEntry = tex.GetBytes(); + m_materialsModule.RemoveMaterial(oldid); + return true; + } + protected LSL_List SetAgentParams(ScenePresence sp, LSL_List rules, string originFunc, ref uint rulesParsed) { int idx = 0; @@ -11363,107 +11774,83 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_List(); } -/* - private string filterTextureUUIDbyRights(UUID origID, SceneObjectPart part, bool checkTaskInventory, bool returnInvName) + private string GetMaterialTextureUUIDbyRights(UUID origID, SceneObjectPart part) { - if(checkTaskInventory) - { - lock (part.TaskInventory) - { - foreach (KeyValuePair inv in part.TaskInventory) - { - if (inv.Value.AssetID == origID) - { - if(inv.Value.InvType == (int)InventoryType.Texture) - { - if(returnInvName) - return inv.Value.Name; - else - return origID.ToString(); - } - else - return UUID.Zero.ToString(); - } - } - } - } - if(World.Permissions.CanEditObject(m_host.ParentGroup.UUID, m_host.ParentGroup.RootPart.OwnerID)) return origID.ToString(); + lock(part.TaskInventory) + { + foreach(KeyValuePair inv in part.TaskInventory) + { + if(inv.Value.InvType == (int)InventoryType.Texture && inv.Value.AssetID == origID) + return origID.ToString(); + } + } + return UUID.Zero.ToString(); } -*/ + private void getLSLFaceMaterial(ref LSL_List res, int code, SceneObjectPart part, Primitive.TextureEntryFace texface) { - UUID matID = texface.MaterialID; + UUID matID = UUID.Zero; + if(m_materialsModule != null) + matID = texface.MaterialID; + if(matID != UUID.Zero) { - AssetBase MatAsset = World.AssetService.Get(matID.ToString()); - if(MatAsset != null) + FaceMaterial mat = m_materialsModule.GetMaterial(matID); + if(mat != null) { - Byte[] data = MatAsset.Data; - OSDMap osdmat = (OSDMap)OSDParser.DeserializeLLSDXml(data); - if(osdmat != null && osdmat.ContainsKey("NormMap")) + if(code == ScriptBaseClass.PRIM_NORMAL) { - string mapIDstr; - FaceMaterial mat = new FaceMaterial(matID, osdmat); - if(code == ScriptBaseClass.PRIM_NORMAL) - { -// mapIDstr = filterTextureUUIDbyRights(mat.NormalMapID, part, true, false); - mapIDstr = mat.NormalMapID.ToString(); - res.Add(new LSL_String(mapIDstr)); - res.Add(new LSL_Vector(mat.NormalRepeatX, mat.NormalRepeatY, 0)); - res.Add(new LSL_Vector(mat.NormalOffsetX, mat.NormalOffsetY, 0)); - res.Add(new LSL_Float(mat.NormalRotation)); - } - else if(code == ScriptBaseClass.PRIM_SPECULAR ) - { -// mapIDstr = filterTextureUUIDbyRights(mat.SpecularMapID, part, true, false); - const float colorScale = 1.0f/255f; - mapIDstr = mat.SpecularMapID.ToString(); - res.Add(new LSL_String(mapIDstr)); - res.Add(new LSL_Vector(mat.SpecularRepeatX, mat.SpecularRepeatY, 0)); - res.Add(new LSL_Vector(mat.SpecularOffsetX, mat.SpecularOffsetY, 0)); - res.Add(new LSL_Float(mat.SpecularRotation)); - res.Add(new LSL_Vector(mat.SpecularLightColor.R * colorScale, - mat.SpecularLightColor.G * colorScale, - mat.SpecularLightColor.B * colorScale)); - res.Add(new LSL_Integer(mat.SpecularLightExponent)); - res.Add(new LSL_Integer(mat.EnvironmentIntensity)); - } - else if(code == ScriptBaseClass.PRIM_ALPHA_MODE) - { - res.Add(new LSL_Integer(mat.DiffuseAlphaMode)); - res.Add(new LSL_Integer(mat.AlphaMaskCutoff)); - } - return; + res.Add(new LSL_String(GetMaterialTextureUUIDbyRights(mat.NormalMapID, part))); + res.Add(new LSL_Vector(mat.NormalRepeatX, mat.NormalRepeatY, 0)); + res.Add(new LSL_Vector(mat.NormalOffsetX, mat.NormalOffsetY, 0)); + res.Add(new LSL_Float(mat.NormalRotation)); } + else if(code == ScriptBaseClass.PRIM_SPECULAR) + { + const float colorScale = 1.0f / 255f; + res.Add(new LSL_String(GetMaterialTextureUUIDbyRights(mat.SpecularMapID, part))); + res.Add(new LSL_Vector(mat.SpecularRepeatX, mat.SpecularRepeatY, 0)); + res.Add(new LSL_Vector(mat.SpecularOffsetX, mat.SpecularOffsetY, 0)); + res.Add(new LSL_Float(mat.SpecularRotation)); + res.Add(new LSL_Vector(mat.SpecularLightColorR * colorScale, + mat.SpecularLightColorG * colorScale, + mat.SpecularLightColorB * colorScale)); + res.Add(new LSL_Integer(mat.SpecularLightExponent)); + res.Add(new LSL_Integer(mat.EnvironmentIntensity)); + } + else if(code == ScriptBaseClass.PRIM_ALPHA_MODE) + { + res.Add(new LSL_Integer(mat.DiffuseAlphaMode)); + res.Add(new LSL_Integer(mat.AlphaMaskCutoff)); + } + return; } - matID = UUID.Zero; } - if(matID == UUID.Zero) + + // material not found + if(code == (int)ScriptBaseClass.PRIM_NORMAL || code == (int)ScriptBaseClass.PRIM_SPECULAR) { - if(code == (int)ScriptBaseClass.PRIM_NORMAL || code == (int)ScriptBaseClass.PRIM_SPECULAR ) + res.Add(new LSL_String(UUID.Zero.ToString())); + res.Add(new LSL_Vector(1.0, 1.0, 0)); + res.Add(new LSL_Vector(0, 0, 0)); + res.Add(new LSL_Float(0)); + + if(code == (int)ScriptBaseClass.PRIM_SPECULAR) { - res.Add(new LSL_String(UUID.Zero.ToString())); - res.Add(new LSL_Vector(1.0, 1.0, 0)); - res.Add(new LSL_Vector(0, 0, 0)); - res.Add(new LSL_Float(0)); - - if(code == (int)ScriptBaseClass.PRIM_SPECULAR) - { - res.Add(new LSL_Vector(1.0, 1.0, 1.0)); - res.Add(new LSL_Integer(51)); - res.Add(new LSL_Integer(0)); - } - } - else if(code == (int)ScriptBaseClass.PRIM_ALPHA_MODE) - { - res.Add(new LSL_Integer(1)); + res.Add(new LSL_Vector(1.0, 1.0, 1.0)); + res.Add(new LSL_Integer(51)); res.Add(new LSL_Integer(0)); } } + else if(code == (int)ScriptBaseClass.PRIM_ALPHA_MODE) + { + res.Add(new LSL_Integer(1)); + res.Add(new LSL_Integer(0)); + } } public LSL_List llGetPrimMediaParams(int face, LSL_List rules) diff --git a/opensim/Region/Framework/Interfaces/IMaterialsModule.cs b/opensim/Region/Framework/Interfaces/IMaterialsModule.cs new file mode 100644 index 0000000000..3f25874471 --- /dev/null +++ b/opensim/Region/Framework/Interfaces/IMaterialsModule.cs @@ -0,0 +1,41 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenSim.Region.Framework.Scenes; +using OpenMetaverse; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IMaterialsModule + { + FaceMaterial GetMaterial(UUID ID); + FaceMaterial GetMaterialCopy(UUID ID); + UUID AddNewMaterial(FaceMaterial fm); + void RemoveMaterial(UUID id); + } +}