using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Threading.Tasks; using UnityEngine; using UnityEngine.UIElements; using UnityEditor.UIElements; using static UnityEngine.UI.InputField; using Object = UnityEngine.Object; using System; using SLZ.SLZEditorTools; using UnityEngine.Rendering; namespace UnityEditor.SLZMaterialUI { public class TextureField : VisualElement, BaseMaterialField { public MaterialProperty textureProperty; public VisualElement leftAlignBox { get; private set; } public VisualElement rightAlignBox { get; private set; } public string tooltip2 { get { return texObjField.tooltip; } set { texObjField.tooltip = value; } } public Texture defaultTexture; public UnityEditor.UIElements.ObjectField texObjField; Texture currentValue; Image thumbnail; bool isNormalMap; RenderTexture thumbnailRT; UnityEngine.Rendering.TextureDimension textureType; public int shaderPropertyIdx; public int GetShaderPropIdx() { return shaderPropertyIdx; } static Action s_updateObjDelegate; static Action UpdateObjDelegate { get { if (s_updateObjDelegate == null) { MethodInfo m = typeof(UnityEditor.UIElements.ObjectField).GetMethod("UpdateDisplay", BindingFlags.Instance | BindingFlags.NonPublic); if (m == null) { Debug.LogError("Missing UpdateDisplay method"); } s_updateObjDelegate = (Action)m.CreateDelegate(typeof(Action)); } return s_updateObjDelegate; } } public TextureField(MaterialProperty textureProperty, int texturePropertyIdx, bool isNormalMap, Texture defaultTexture = null) { this.textureProperty = textureProperty; this.currentValue = textureProperty.textureValue; this.shaderPropertyIdx = texturePropertyIdx; this.isNormalMap = isNormalMap; this.defaultTexture = defaultTexture; RegisterCallback(evt => Dispose()); leftAlignBox = new VisualElement(); leftAlignBox.AddToClassList("materialGUILeftBox"); rightAlignBox = new VisualElement(); rightAlignBox.AddToClassList("materialGUIRightBox"); style.flexDirection = FlexDirection.Row; texObjField = new UnityEditor.UIElements.ObjectField(); //List providers = new List() { new SearchProvider("sfklahlkjhsa", "hello") }; //textureField.searchContext = new SearchContext(providers, "t:Texture2D", SearchFlags.Default); //textureField.bindingPath = "m_SavedProperties.m_TexEnvs.Array.data[0].second.m_Texture"; textureType = textureProperty.textureDimension; switch (textureProperty.textureDimension) { case (UnityEngine.Rendering.TextureDimension.Tex2D): texObjField.objectType = typeof(Texture2D); break; case (UnityEngine.Rendering.TextureDimension.Tex3D): texObjField.objectType = typeof(Texture3D); break; case (UnityEngine.Rendering.TextureDimension.Tex2DArray): texObjField.objectType = typeof(Texture2DArray); break; case (UnityEngine.Rendering.TextureDimension.Cube): texObjField.objectType = typeof(Cubemap); break; case (UnityEngine.Rendering.TextureDimension.CubeArray): texObjField.objectType = typeof(CubemapArray); break; } VisualElement background = texObjField.ElementAt(0); background.style.backgroundColor = StyleKeyword.None; background.style.borderBottomColor = StyleKeyword.None; background.style.borderLeftColor = StyleKeyword.None; background.style.borderRightColor = StyleKeyword.None; background.style.borderTopColor = StyleKeyword.None; background.style.borderBottomWidth = StyleKeyword.None; background.style.borderLeftWidth = StyleKeyword.None; background.style.borderRightWidth = StyleKeyword.None; background.style.borderTopWidth = StyleKeyword.None; background.style.borderTopLeftRadius = StyleKeyword.None; background.style.borderTopRightRadius = StyleKeyword.None; background.style.borderBottomLeftRadius = StyleKeyword.None; background.style.borderBottomRightRadius = StyleKeyword.None; background.style.justifyContent = Justify.FlexStart; background.style.flexWrap = Wrap.NoWrap; background.style.overflow = Overflow.Hidden; VisualElement contents = background.ElementAt(0); contents.style.flexShrink = 0; contents.style.flexGrow = 1; contents.style.overflow = Overflow.Hidden; contents.style.flexBasis = StyleKeyword.Auto; VisualElement oldlabel = contents.ElementAt(1); oldlabel.style.display = DisplayStyle.None; VisualElement searchButton = background.ElementAt(1); searchButton.style.width = StyleKeyword.Auto; searchButton.style.backgroundImage = StyleKeyword.None; searchButton.style.flexDirection = FlexDirection.Row; searchButton.style.overflow = Overflow.Hidden; searchButton.style.flexBasis = StyleKeyword.Auto; VisualElement fakeRadial = new VisualElement(); fakeRadial.AddToClassList("unity-object-field__selector"); fakeRadial.pickingMode = PickingMode.Ignore; fakeRadial.style.backgroundColor = Color.clear; Label label = new Label(textureProperty.displayName); label.pickingMode = PickingMode.Ignore; label.style.textOverflow = TextOverflow.Ellipsis; searchButton.Add(fakeRadial); searchButton.Add(label); Image oldThumbnail = contents.ElementAt(0) as Image; oldThumbnail.style.display = DisplayStyle.None; thumbnail = new Image(); thumbnail.AddToClassList("textureFieldThumb"); thumbnail.AddToClassList("unity-object-field-display__icon"); thumbnail.pickingMode = PickingMode.Ignore; thumbnail.scaleMode = ScaleMode.StretchToFill; thumbnail.tintColor = Color.white; thumbnailRT = new RenderTexture((int)(32.0f * EditorGUIUtility.pixelsPerPoint), (int)(32.0f * EditorGUIUtility.pixelsPerPoint), 1, RenderTextureFormat.ARGB32, 1); thumbnailRT.depth = 0; thumbnailRT.name = textureProperty.name + "_icon"; thumbnailRT.Create(); thumbnail.image = thumbnailRT; contents.Insert(0, thumbnail); texObjField.RegisterValueChangedCallback(OnObjectFieldChanged); if (textureProperty.hasMixedValue) { currentValue = null; texObjField.showMixedValue = true; } else { //if (textureProperty.textureValue == null && defaultTexture != null) //{ // textureProperty.textureValue = defaultTexture; // currentValue = defaultTexture; //} texObjField.showMixedValue = false; } texObjField.SetValueWithoutNotify(currentValue); UpdateThumbnail(); leftAlignBox.Add(texObjField); Add(leftAlignBox); Add(rightAlignBox); } void OnObjectFieldChanged(ChangeEvent evt) { value = evt.newValue; } public void SetValueWithoutNotify(Object newValue) { if (newValue == null || newValue is Texture) { currentValue = (Texture) newValue; if (currentValue == null && defaultTexture != null) { currentValue = defaultTexture; } UpdateThumbnail(); textureProperty.textureValue = currentValue; texObjField.SetValueWithoutNotify(currentValue); UpdateObjDelegate.Invoke(texObjField); texObjField.showMixedValue = newValue == null; } else throw new System.ArgumentException($"Expected object of type {typeof(Texture2D)}"); } public Object value { get => currentValue; set { if (value == currentValue) return; Object previous = currentValue; SetValueWithoutNotify(value); } } void UpdateThumbnail() { BlitTextureIcon(thumbnailRT, currentValue, textureType); } public void UpdateMaterialProperty(MaterialProperty boundProp) { bool valueChanged = currentValue != boundProp.textureValue; textureProperty = boundProp; if (valueChanged) { currentValue = boundProp.textureValue; texObjField.SetValueWithoutNotify(currentValue); UpdateThumbnail(); } texObjField.showMixedValue = boundProp.hasMixedValue; } void Dispose() { if (thumbnailRT != null) { thumbnailRT.Clear(); } } static Material s_blitMaterial; static LocalKeyword[] dimKeywords; static LocalKeyword normalMapKeyword; static int prop_Blit2D = Shader.PropertyToID("_Blit2D"); static int prop_Blit2DArray = Shader.PropertyToID("_Blit2DArray"); static int prop_BlitCube = Shader.PropertyToID("_BlitCube"); static int prop_BlitCubeArray = Shader.PropertyToID("_BlitCubeArray"); static int prop_Blit3D = Shader.PropertyToID("_Blit3D"); static int prop_BlitDim = Shader.PropertyToID("_BlitDim"); static void UpdateKeywords() { Shader blitShader = s_blitMaterial.shader; dimKeywords[(int)TextureDimension.Tex2D - 2] = new LocalKeyword(blitShader, "DIM_2D"); dimKeywords[(int)TextureDimension.Tex2DArray - 2] = new LocalKeyword(blitShader, "DIM_2DARRAY"); dimKeywords[(int)TextureDimension.Cube - 2] = new LocalKeyword(blitShader, "DIM_CUBE"); dimKeywords[(int)TextureDimension.CubeArray - 2] = new LocalKeyword(blitShader, "DIM_CUBEARRAY"); dimKeywords[(int)TextureDimension.Tex3D - 2] = new LocalKeyword(blitShader, "DIM_3D"); normalMapKeyword = new LocalKeyword(blitShader, "NORMAL_MAP"); } void BlitTextureIcon(RenderTexture icon, Texture tex, TextureDimension texType) { if (icon == null) return; RenderTexture active = RenderTexture.active; if (tex == null) { RenderTexture.active = icon; GL.Clear(false, true, Color.clear, 0); RenderTexture.active = active; return; } if (s_blitMaterial == null || s_blitMaterial.shader == null || dimKeywords == null) { Shader blitShader = Shader.Find("Hidden/ShaderGUITextureIconBlit"); if (blitShader == null) { Debug.LogError("Could not find Blit_ShaderGUI.shader (Hidden/ShaderGUITextureIconBlit), cannot generate material thumbnails"); return; } s_blitMaterial = new Material(blitShader); dimKeywords = new LocalKeyword[5]; } UpdateKeywords(); int offsetDimEnum = (int)texType - 2; for (int i = 0; i < 5; i++) { if (i == offsetDimEnum) s_blitMaterial.EnableKeyword(dimKeywords[i]); else s_blitMaterial.DisableKeyword(dimKeywords[i]); } switch (texType) { case TextureDimension.Tex2D: s_blitMaterial.SetTexture(prop_Blit2D, tex); break; case TextureDimension.Tex2DArray: s_blitMaterial.SetTexture(prop_Blit2DArray, tex); break; case TextureDimension.Cube: s_blitMaterial.SetTexture(prop_BlitCube, tex); s_blitMaterial.SetVector(prop_BlitDim, new Vector4(tex.width, tex.height, 0, 0)); break; case TextureDimension.CubeArray: s_blitMaterial.SetTexture(prop_BlitCubeArray, tex); s_blitMaterial.SetVector(prop_BlitDim, new Vector4(tex.width, tex.height, 0, 0)); break; case TextureDimension.Tex3D: s_blitMaterial.SetTexture(prop_Blit3D, tex); s_blitMaterial.SetVector(prop_BlitDim, new Vector4(tex.width, tex.height, 0, 0)); break; default: Debug.LogError("Shader GUI Icon Blitter: Unknown texture dimension " + texType); return; } if (isNormalMap) { s_blitMaterial.EnableKeyword(normalMapKeyword); } Graphics.Blit(tex, icon, s_blitMaterial); RenderTexture.active = active; if (isNormalMap) { s_blitMaterial.DisableKeyword(normalMapKeyword); } switch (texType) { case TextureDimension.Tex2D: s_blitMaterial.SetTexture(prop_Blit2D, null); break; case TextureDimension.Tex2DArray: s_blitMaterial.SetTexture(prop_Blit2DArray, null); break; case TextureDimension.Cube: s_blitMaterial.SetTexture(prop_BlitCube, null); break; case TextureDimension.CubeArray: s_blitMaterial.SetTexture(prop_BlitCubeArray, null); break; case TextureDimension.Tex3D: s_blitMaterial.SetTexture(prop_Blit3D, null); break; } } } }