365 lines
15 KiB
C#
365 lines
15 KiB
C#
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<ObjectField> s_updateObjDelegate;
|
|
static Action<ObjectField> 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<ObjectField>)m.CreateDelegate(typeof(Action<ObjectField>));
|
|
}
|
|
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<DetachFromPanelEvent>(evt => Dispose());
|
|
leftAlignBox = new VisualElement();
|
|
leftAlignBox.AddToClassList("materialGUILeftBox");
|
|
rightAlignBox = new VisualElement();
|
|
rightAlignBox.AddToClassList("materialGUIRightBox");
|
|
|
|
|
|
style.flexDirection = FlexDirection.Row;
|
|
texObjField = new UnityEditor.UIElements.ObjectField();
|
|
//List<SearchProvider> providers = new List<SearchProvider>() { 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<Object> 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;
|
|
}
|
|
}
|
|
}
|
|
}
|