Files
ichni_Official/Packages/NB_FX/XuanXuanRenderUtility/Editor/ShaderGUIItems/TextureItem.cs
SoulliesOfficial 40fa80cd70 NB_FX
2026-07-17 17:46:16 -04:00

499 lines
18 KiB
C#

using System;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
public class TextureItem : ShaderGUIItem
{
private readonly string _texturePropertyName;
private readonly TexturePropertyGroupItem _groupItem;
private readonly Func<bool> _isVisible;
private readonly Action<MaterialProperty> _afterDraw;
public TextureItem(
ShaderGUIRootItem rootItem,
ShaderGUIItem parentItem,
string texturePropertyName,
Func<GUIContent> contentProvider,
string colorPropertyName = null,
bool drawScaleOffset = true,
Action<MaterialProperty> afterDraw = null,
Func<bool> isVisible = null,
Func<GUIContent> tillingContentProvider = null,
Func<GUIContent> offsetContentProvider = null) : base(rootItem, parentItem)
{
_texturePropertyName = texturePropertyName;
_isVisible = isVisible;
_afterDraw = afterDraw;
_groupItem = new TexturePropertyGroupItem(
rootItem,
this,
texturePropertyName,
colorPropertyName,
contentProvider,
drawScaleOffset,
tillingContentProvider: tillingContentProvider,
offsetContentProvider: offsetContentProvider);
InitTriggerByChild();
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
_groupItem.ClearTextureIfRequested();
return;
}
_groupItem.OnGUI();
if (_afterDraw != null && RootItem.PropertyInfoDic.TryGetValue(_texturePropertyName, out ShaderPropertyInfo texturePropertyInfo))
{
_afterDraw(texturePropertyInfo.Property);
}
}
}
public class TexturePropertyGroupItem : ShaderGUIItem
{
private readonly TextureObjectItem _textureItem;
private readonly ColorLineItem _colorItem;
private readonly TextureScaleOffsetItem _scaleOffsetItem;
private readonly Func<bool> _isVisible;
public TexturePropertyGroupItem(
ShaderGUIRootItem rootItem,
ShaderGUIItem parentItem,
string texturePropertyName,
string colorPropertyName,
Func<GUIContent> contentProvider,
bool drawScaleOffset = true,
Func<bool> isVisible = null,
Func<GUIContent> tillingContentProvider = null,
Func<GUIContent> offsetContentProvider = null) : base(rootItem, parentItem)
{
_isVisible = isVisible;
_textureItem = new TextureObjectItem(rootItem, this, texturePropertyName, contentProvider);
_colorItem = string.IsNullOrEmpty(colorPropertyName)
? null
: new ColorLineItem(rootItem, this, colorPropertyName, false, contentProvider);
_scaleOffsetItem = drawScaleOffset
? new TextureScaleOffsetItem(
rootItem,
this,
texturePropertyName,
false,
tillingContentProvider: tillingContentProvider,
offsetContentProvider: offsetContentProvider)
: null;
InitTriggerByChild();
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
_textureItem.ClearTextureIfRequested();
return;
}
float singleLineHeight = EditorGUIUtility.singleLineHeight;
float rowGap = EditorGUIUtility.standardVerticalSpacing;
float textureFieldHeight = 3f * singleLineHeight + 2f * rowGap;
float textureContentGap = EditorGUIUtility.standardVerticalSpacing;
Rect textureGroupRect = ApplyGlobalRectCompensation(LayoutRect(textureFieldHeight));
Rect textureLabelRow = new Rect(textureGroupRect.x, textureGroupRect.y, textureGroupRect.width, singleLineHeight);
Rect tillingRow = new Rect(textureGroupRect.x, textureGroupRect.y + singleLineHeight + rowGap, textureGroupRect.width, singleLineHeight);
Rect offsetRow = new Rect(textureGroupRect.x, tillingRow.y + singleLineHeight + rowGap, textureGroupRect.width, singleLineHeight);
Rect indentedTextureLabelRow = ApplyDirectLabelIndentWidth(textureLabelRow);
Rect textureRect = new Rect(indentedTextureLabelRow.x + 2f, textureLabelRow.y, textureFieldHeight, textureFieldHeight);
textureRect.x -= 2f;
textureRect.y += 2f;
float contentX = textureRect.x + textureRect.width + textureContentGap;
Rect textureLabelRect = MoveRectLeftKeepingRight(textureLabelRow, contentX);
SplitLineRect(tillingRow, out _, out Rect tillingVec2Rect, out Rect tillingResetRect, false);
Rect tillingLabelRect = MakeLabelRect(tillingRow, contentX, tillingVec2Rect.x);
tillingVec2Rect = ApplyControlIndentCompensation(tillingVec2Rect);
SplitLineRect(offsetRow, out _, out Rect offsetVec2Rect, out Rect offsetResetRect, false);
Rect offsetLabelRect = MakeLabelRect(offsetRow, contentX, offsetVec2Rect.x);
offsetVec2Rect = ApplyControlIndentCompensation(offsetVec2Rect);
_textureItem.Draw(textureRect, textureLabelRect);
_scaleOffsetItem?.Draw(tillingLabelRect, tillingVec2Rect, tillingResetRect, offsetLabelRect, offsetVec2Rect, offsetResetRect);
_colorItem?.OnGUI();
}
public void ClearTextureIfRequested()
{
_textureItem.ClearTextureIfRequested();
}
private static Rect MoveRectLeftKeepingRight(Rect rect, float x)
{
float xMax = rect.xMax;
rect.x = Mathf.Min(x, xMax);
rect.width = xMax - rect.x;
return rect;
}
private static Rect MakeLabelRect(Rect rowRect, float labelX, float controlX)
{
Rect labelRect = rowRect;
labelRect.x = Mathf.Min(labelX, controlX);
labelRect.width = Mathf.Max(0f, controlX - labelRect.x);
return labelRect;
}
private static Rect ApplyControlIndentCompensation(Rect rect)
{
rect.x -= ControlIndentCompensation;
rect.width += ControlIndentCompensation;
return rect;
}
}
public class TextureObjectItem : ShaderGUIItem
{
private readonly Func<GUIContent> _contentProvider;
private readonly Func<bool> _isVisible;
public TextureObjectItem(
ShaderGUIRootItem rootItem,
ShaderGUIItem parentItem,
string texturePropertyName,
Func<GUIContent> contentProvider,
Func<bool> isVisible = null) : base(rootItem, parentItem)
{
PropertyName = texturePropertyName;
_contentProvider = contentProvider ?? (() => GUIContent.none);
_isVisible = isVisible;
GuiContent = _contentProvider();
InitTriggerByChild();
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
ClearTextureIfRequested();
return;
}
GetRect();
Draw(ControlRect, LabelRect, ResetRect);
DrawBlock();
}
public void Draw(Rect textureRect, Rect labelAndResetRect)
{
SplitControlAndResetRect(labelAndResetRect, out Rect labelRect, out Rect resetRect, false);
Draw(textureRect, labelRect, resetRect);
}
public void Draw(Rect textureRect, Rect labelRect, Rect resetRect)
{
ControlRect = textureRect;
LabelRect = labelRect;
ResetRect = resetRect;
MaterialProperty property = PropertyInfo.Property;
if (RootItem.ClearUnusedTextureReferencesRequested && (IsParentControlDisabled || !GUI.enabled))
{
ClearTextureIfRequested();
}
using (ParentControlDisabledScope())
{
GUI.Label(LabelRect, GuiContent, EditorStyles.boldLabel);
}
using (ParentControlDisabledScope())
{
EditorGUI.showMixedValue = property.hasMixedValue;
EditorGUI.BeginChangeCheck();
bool animatedScope = BeginAnimatedPropertyBackground(ControlRect, property);
Texture texture;
using (new EditorGUIIndentLevelScope(0))
{
texture = (Texture)EditorGUI.ObjectField(ControlRect, property.textureValue, typeof(Texture2D), false);
}
EndAnimatedPropertyBackground(animatedScope);
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
property.textureValue = texture;
OnEndChange();
}
}
DrawResetButton();
}
public void ClearTextureIfRequested()
{
if (!RootItem.ClearUnusedTextureReferencesRequested || PropertyInfo == null)
{
return;
}
MaterialProperty property = PropertyInfo.Property;
if (property == null || property.textureValue == null)
{
return;
}
property.textureValue = null;
OnEndChange();
}
public override void CheckIsPropertyModified(bool isCallByChild = false)
{
if (!isCallByChild)
{
bool isDefaultValue = PropertyInfo == null ||
(!PropertyInfo.Property.hasMixedValue && PropertyInfo.Property.textureValue == null);
if (isDefaultValue == PropertyIsDefaultValue)
{
return;
}
PropertyIsDefaultValue = isDefaultValue;
}
HasModified = !PropertyIsDefaultValue;
foreach (ShaderGUIItem childItem in ChildrenItemList)
{
HasModified |= childItem.HasModified;
}
ParentItem?.CheckIsPropertyModified(true);
}
public override void ExecuteReset(bool isCallByParent = false)
{
if (PropertyInfo != null)
{
PropertyInfo.Property.textureValue = null;
PropertyIsDefaultValue = true;
}
HasModified = false;
if (!isCallByParent)
{
ParentItem?.CheckIsPropertyModified(true);
}
}
}
public class TextureScaleOffsetItem : ShaderGUIItem
{
private static readonly GUIContent TillingContent = new GUIContent("Tilling");
private static readonly GUIContent OffsetContent = new GUIContent("Offset");
private static readonly Vector4 DefaultScaleOffset = new Vector4(1f, 1f, 0f, 0f);
private readonly bool _isVectorProperty;
private readonly Func<bool> _isVisible;
private readonly Func<GUIContent> _tillingContentProvider;
private readonly Func<GUIContent> _offsetContentProvider;
private readonly GUIContent _tillingContent;
private readonly GUIContent _offsetContent;
public TextureScaleOffsetItem(
ShaderGUIRootItem rootItem,
ShaderGUIItem parentItem,
string propertyName,
bool isVectorProperty,
Func<bool> isVisible = null,
Func<GUIContent> tillingContentProvider = null,
Func<GUIContent> offsetContentProvider = null) : base(rootItem, parentItem)
{
PropertyName = propertyName;
_isVectorProperty = isVectorProperty;
_isVisible = isVisible;
_tillingContentProvider = tillingContentProvider ?? (() => TillingContent);
_offsetContentProvider = offsetContentProvider ?? (() => OffsetContent);
_tillingContent = _tillingContentProvider();
_offsetContent = _offsetContentProvider();
InitTriggerByChild();
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
return;
}
GetRect();
Rect tillingLabelRect = LabelRect;
Rect tillingVec2Rect = ControlRect;
Rect tillingResetRect = ResetRect;
GetRect();
Rect offsetLabelRect = LabelRect;
Rect offsetVec2Rect = ControlRect;
Rect offsetResetRect = ResetRect;
Draw(tillingLabelRect, tillingVec2Rect, tillingResetRect, offsetLabelRect, offsetVec2Rect, offsetResetRect, true);
DrawBlock();
}
public void Draw(
Rect tillingLabelRect,
Rect tillingVec2Rect,
Rect tillingResetRect,
Rect offsetLabelRect,
Rect offsetVec2Rect,
Rect offsetResetRect,
bool useEditorLabelField = false)
{
MaterialProperty property = PropertyInfo.Property;
Vector4 scaleOffset = GetScaleOffset(property);
DrawLabel(tillingLabelRect, _tillingContent, useEditorLabelField);
using (ParentControlDisabledScope())
{
Vector2 tilling = new Vector2(scaleOffset.x, scaleOffset.y);
EditorGUI.showMixedValue = property.hasMixedValue;
EditorGUI.BeginChangeCheck();
bool tillingAnimatedScope = BeginAnimatedPropertyBackground(tillingVec2Rect, property);
using (new EditorGUIIndentLevelScope(0))
{
tilling = EditorGUI.Vector2Field(tillingVec2Rect, GUIContent.none, tilling);
}
EndAnimatedPropertyBackground(tillingAnimatedScope);
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
scaleOffset.x = tilling.x;
scaleOffset.y = tilling.y;
Apply(scaleOffset);
}
bool tillingModified = property.hasMixedValue || tilling != Vector2.one;
if (GUI.Button(tillingResetRect, tillingModified ? "R" : string.Empty, tillingModified ? GUI.skin.button : GUI.skin.label))
{
scaleOffset.x = 1f;
scaleOffset.y = 1f;
Apply(scaleOffset);
}
}
DrawLabel(offsetLabelRect, _offsetContent, useEditorLabelField);
using (ParentControlDisabledScope())
{
Vector2 offset = new Vector2(scaleOffset.z, scaleOffset.w);
EditorGUI.showMixedValue = property.hasMixedValue;
EditorGUI.BeginChangeCheck();
bool offsetAnimatedScope = BeginAnimatedPropertyBackground(offsetVec2Rect, property);
using (new EditorGUIIndentLevelScope(0))
{
offset = EditorGUI.Vector2Field(offsetVec2Rect, GUIContent.none, offset);
}
EndAnimatedPropertyBackground(offsetAnimatedScope);
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
scaleOffset.z = offset.x;
scaleOffset.w = offset.y;
Apply(scaleOffset);
}
bool offsetModified = property.hasMixedValue || offset != Vector2.zero;
if (GUI.Button(offsetResetRect, offsetModified ? "R" : string.Empty, offsetModified ? GUI.skin.button : GUI.skin.label))
{
scaleOffset.z = 0f;
scaleOffset.w = 0f;
Apply(scaleOffset);
}
}
}
private void DrawLabel(Rect rect, GUIContent content, bool useEditorLabelField)
{
using (ParentControlDisabledScope())
{
if (useEditorLabelField)
{
EditorGUI.LabelField(rect, content);
return;
}
GUI.Label(rect, content);
}
}
public override void CheckIsPropertyModified(bool isCallByChild = false)
{
if (!isCallByChild)
{
bool isDefaultValue = true;
if (PropertyInfo != null)
{
MaterialProperty property = PropertyInfo.Property;
isDefaultValue = !property.hasMixedValue && Approximately(GetScaleOffset(property), DefaultScaleOffset);
}
if (isDefaultValue == PropertyIsDefaultValue)
{
return;
}
PropertyIsDefaultValue = isDefaultValue;
}
HasModified = !PropertyIsDefaultValue;
foreach (ShaderGUIItem childItem in ChildrenItemList)
{
HasModified |= childItem.HasModified;
}
ParentItem?.CheckIsPropertyModified(true);
}
public override void ExecuteReset(bool isCallByParent = false)
{
if (PropertyInfo != null)
{
SetScaleOffset(PropertyInfo.Property, DefaultScaleOffset);
PropertyIsDefaultValue = true;
}
HasModified = false;
if (!isCallByParent)
{
ParentItem?.CheckIsPropertyModified(true);
}
}
private Vector4 GetScaleOffset(MaterialProperty property)
{
return _isVectorProperty ? property.vectorValue : property.textureScaleAndOffset;
}
private void Apply(Vector4 scaleOffset)
{
SetScaleOffset(PropertyInfo.Property, scaleOffset);
OnEndChange();
}
private void SetScaleOffset(MaterialProperty property, Vector4 scaleOffset)
{
if (_isVectorProperty)
{
property.vectorValue = scaleOffset;
}
else
{
property.textureScaleAndOffset = scaleOffset;
}
}
}
}