480 lines
14 KiB
C#
Raw Normal View History

2025-09-11 11:04:02 +08:00
using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using System.Linq;
using System.Reflection;
using System.IO;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor;
2025-09-11 20:42:09 +08:00
using UnityEditor.Callbacks;
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
namespace X.Rendering.Assets
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
public interface IGradientTextureForEditor
{
void CreateTexture();
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
Texture2D GetTexture();
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
void LoadExisitingTexture();
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
/// <summary>
/// Main Asset, holds settings, create, hold and change Texture2D's pixels, name
/// </summary>
[CreateAssetMenu(fileName = "NewGradientName", menuName = "Texture/Gradient")]
public class GradientTexture : ScriptableObject, IEquatable<Texture2D>, ISerializationCallbackReceiver,
IGradientTextureForEditor
{
[SerializeField] Vector2Int _resolution = new Vector2Int(256, 256);
[SerializeField] bool _sRGB = true;
[SerializeField] AnimationCurve _verticalLerp = AnimationCurve.Linear(0, 0, 1, 1);
[SerializeField, GradientUsage(true)] Gradient _horizontalTop = GetDefaultGradient();
[SerializeField, GradientUsage(true)] Gradient _horizontalBottom = GetDefaultGradient();
[SerializeField, HideInInspector] Texture2D _texture = default;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public Texture2D GetTexture() => _texture;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public bool GetSRGB() => _sRGB;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public void SetSRGB(bool value)
{
_sRGB = value;
OnValidate();
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
int _width => _resolution.x;
int _height => _resolution.y;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public static implicit operator Texture2D(GradientTexture asset) => asset.GetTexture();
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
static Gradient GetDefaultGradient() => new Gradient
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
alphaKeys = new[] { new GradientAlphaKey(1, 1) },
colorKeys = new[]
{
2025-09-11 11:04:02 +08:00
new GradientColorKey(Color.black, 0),
new GradientColorKey(Color.white, 1)
}
2025-09-11 20:42:09 +08:00
};
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public void FillColors(bool useRGB)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
bool isLinear = QualitySettings.activeColorSpace == ColorSpace.Linear;
float tVertical = 0;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
for (int y = 0; y < _height; y++)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
tVertical = _verticalLerp.Evaluate((float)y / _height);
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
for (int x = 0; x < _width; x++)
{
float tHorizontal = (float)x / _width;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
Color color = Color.Lerp(_horizontalBottom.Evaluate(tHorizontal),
_horizontalTop.Evaluate(tHorizontal),
tVertical);
color = useRGB && isLinear ? color.linear : color;
_texture.SetPixel(x, y, color);
}
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
_texture.Apply();
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public bool Equals(Texture2D other)
{
return _texture.Equals(other);
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
void OnValidate() => ValidateTextureValues();
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
void IGradientTextureForEditor.LoadExisitingTexture()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
#if UNITY_EDITOR
if (!_texture)
{
string assetPath = AssetDatabase.GetAssetPath(this);
_texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
}
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
void IGradientTextureForEditor.CreateTexture()
{
2025-09-11 11:04:02 +08:00
#if UNITY_EDITOR
2025-09-11 20:42:09 +08:00
//if (EditorApplication.isUpdating) return;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
string assetPath = AssetDatabase.GetAssetPath(this);
if (string.IsNullOrEmpty(assetPath)) return;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (!_texture && this != null && !EditorApplication.isUpdating)
{
AssetDatabase.ImportAsset(assetPath);
_texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (!_texture)
{
2025-09-11 11:04:02 +08:00
#if UNITY_2018
_texture = new Texture2D(_resolution.x, _resolution.y);
#else
2025-09-11 20:42:09 +08:00
_texture = new Texture2D(_resolution.x, _resolution.y, DefaultFormat.LDR, TextureCreationFlags.None);
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
if (_texture.name != name) _texture.name = name;
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (!_texture) return;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
ValidateTextureValues();
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (!EditorUtility.IsPersistent(this)) return;
if (AssetDatabase.IsSubAsset(_texture)) return;
if (AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath)) return;
2025-09-11 11:04:02 +08:00
#if UNITY_2020_1_OR_NEWER
2025-09-11 20:42:09 +08:00
if (AssetDatabase.IsAssetImportWorkerProcess()) return;
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
AssetDatabase.AddObjectToAsset(_texture, this);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
2025-09-11 11:04:02 +08:00
#endif
}
2025-09-11 20:42:09 +08:00
void ValidateTextureValues()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (!_texture) return;
if (_texture.name != name)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
_texture.name = name;
}
else
{
if (_texture.width != _resolution.x ||
_texture.height != _resolution.y)
{
2025-09-11 11:04:02 +08:00
#if UNITY_2022_1_OR_NEWER
2025-09-11 20:42:09 +08:00
_texture.Reinitialize(_resolution.x, _resolution.y);
2025-09-11 11:04:02 +08:00
#else
_texture.Resize(_resolution.x, _resolution.y);
#endif
2025-09-11 20:42:09 +08:00
}
2025-09-11 11:04:02 +08:00
#if UNITY_EDITOR
2025-09-11 20:42:09 +08:00
_texture.alphaIsTransparency = true;
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
FillColors(_sRGB);
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
SetDirtyTexture();
}
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
#region Editor
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
[System.Diagnostics.Conditional("UNITY_EDITOR")]
void SetDirtyTexture()
{
2025-09-11 11:04:02 +08:00
#if UNITY_EDITOR
2025-09-11 20:42:09 +08:00
if (!_texture) return;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
EditorUtility.SetDirty(_texture);
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
#endregion
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public void OnAfterDeserialize()
{
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public void OnBeforeSerialize()
{
2025-09-11 11:04:02 +08:00
#if UNITY_EDITOR
2025-09-11 20:42:09 +08:00
if (!_texture || _texture.name == name) return;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
_texture.name = name;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
//AssetDatabase.SaveAssets();
2025-09-11 11:04:02 +08:00
#endif
2025-09-11 20:42:09 +08:00
}
2025-09-11 11:04:02 +08:00
}
#if UNITY_EDITOR
2025-09-11 20:42:09 +08:00
[CustomEditor(typeof(GradientTexture), true), CanEditMultipleObjects]
public class GradientTextureEditor : UnityEditor.Editor
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
GradientTexture _gradientTexture;
UnityEditor.Editor _editor;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
public override bool HasPreviewGUI() => true;
void OnEnable()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
_gradientTexture = target as GradientTexture;
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
public override void OnInspectorGUI()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_gradientTexture.GetTexture() == null)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
(_gradientTexture as IGradientTextureForEditor).CreateTexture();
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
base.OnInspectorGUI();
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
string buttonText = "Encode to PNG" + (targets.Length > 1 ? $" ({targets.Length})" : "");
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (GUILayout.Button(buttonText))
{
foreach (Object target in targets)
{
GradientTexture targetTexture = target as GradientTexture;
string path = EditorUtility.SaveFilePanelInProject("Save file",
$"{targetTexture.name}_baked",
"png",
"Choose path to save file");
if (string.IsNullOrEmpty(path))
{
Debug.LogError("[ GradientTextureEditor ] EncodeToPNG() save path is empty! canceled",
targetTexture);
return;
}
bool wasSRGB = targetTexture.GetSRGB();
if (wasSRGB) targetTexture.SetSRGB(false);
byte[] bytes = ImageConversion.EncodeToPNG(targetTexture.GetTexture());
targetTexture.SetSRGB(wasSRGB);
int length = "Assets".Length;
string dataPath = Application.dataPath;
dataPath = dataPath.Remove(dataPath.Length - length, length);
dataPath += path;
File.WriteAllBytes(dataPath, bytes);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
AssetDatabase.ImportAsset(path);
Texture2D image = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(path);
importer.sRGBTexture = targetTexture.GetSRGB();
importer.SaveAndReimport();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log($"[ GradientTextureEditor ] EncodeToPNG() Success! png-gradient saved at '{path}'",
image);
EditorGUIUtility.PingObject(image);
Selection.activeObject = image;
2025-09-11 11:04:02 +08:00
}
}
}
2025-09-11 20:42:09 +08:00
public override void DrawPreview(Rect previewArea)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
Texture2D texture = _gradientTexture.GetTexture();
bool check = !_editor || _editor.target != texture;
if (check && texture && (_editor == null || _editor.target != texture))
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
try
{
_editor = CreateEditor(targets.Select(t => (t as GradientTexture)?.GetTexture()).ToArray());
}
catch
{
_editor = null;
//Debug.LogException(e);
//throw;
}
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
if (_editor && _editor.target)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
try
{
_editor.DrawPreview(previewArea);
}
catch
{
//Debug.LogException(e);
//throw;
}
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public override void OnPreviewSettings()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_editor && _editor.target)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
try
{
_editor.OnPreviewSettings();
}
catch
{
//Debug.LogException(e);
//throw;
}
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public override void ReloadPreviewInstances()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_editor && _editor.target)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
try
{
_editor.ReloadPreviewInstances();
}
catch
{
//Debug.LogException(e);
//throw;
}
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_editor && _editor.target)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
try
{
_editor.OnInteractivePreviewGUI(r, background);
}
catch
{
//Debug.LogException(e);
//throw;
}
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public override void OnPreviewGUI(Rect r, GUIStyle background)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_editor && _editor.target)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
try
{
_editor.OnPreviewGUI(r, background);
}
catch
{
//Debug.LogException(e);
//throw;
}
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_gradientTexture == null) return null;
if (_gradientTexture.GetTexture() == null) return null;
Texture2D tex = new Texture2D(width, height);
EditorUtility.CopySerialized(_gradientTexture.GetTexture(), tex);
return tex;
}
void OnDisable()
{
if (_editor)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
_editor.GetType().GetMethod("OnDisable", BindingFlags.NonPublic)?.Invoke(_editor, null);
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
void OnDestroy()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (_editor)
{
DestroyImmediate(_editor);
}
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public static class DragAndDropUtility
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
static DragAndDrop.ProjectBrowserDropHandler _handlerProject;
[InitializeOnLoadMethod]
public static void Init()
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
_handlerProject = ProjectDropHandler;
DragAndDrop.RemoveDropHandler(_handlerProject);
DragAndDrop.AddDropHandler(_handlerProject);
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
private static DragAndDropVisualMode ProjectDropHandler(int dragInstanceId, string dropUponPath, bool perform)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (!perform)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
var dragged = DragAndDrop.objectReferences;
bool found = false;
for (var i = 0; i < dragged.Length; i++)
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
if (dragged[i] is GradientTexture gradient)
{
dragged[i] = gradient.GetTexture();
found = true;
}
}
if (found)
{
DragAndDrop.objectReferences = dragged;
GUI.changed = true;
return default;
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
}
return default;
2025-09-11 11:04:02 +08:00
}
}
2025-09-11 20:42:09 +08:00
public class ProjectIconsUtility
2025-09-11 11:04:02 +08:00
{
2025-09-11 20:42:09 +08:00
[DidReloadScripts]
static ProjectIconsUtility()
{
EditorApplication.projectWindowItemOnGUI -= ItemOnGUI;
EditorApplication.projectWindowItemOnGUI += ItemOnGUI;
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
static void ItemOnGUI(string guid, Rect rect)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
var asset = AssetDatabase.LoadAssetAtPath<GradientTexture>(assetPath);
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (asset == null) return;
if (!asset.GetTexture()) return;
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
if (rect.height > 30)
{
// rect.position = new Vector2(rect.position.x + rect.height * .1f + rect.width - rect.height, rect.position.y);
// rect.height *= .87f;
// rect.width = rect.height - 5;
// rect.height *= .95f;
}
else
{
//rect.position = new Vector2(rect.position.x-2 + rect.width - rect.height, rect.position.y);
rect.width = rect.height *= .9f;
GUI.DrawTexture(rect, asset.GetTexture());
}
2025-09-11 11:04:02 +08:00
2025-09-11 20:42:09 +08:00
}
2025-09-11 11:04:02 +08:00
}
2025-09-11 20:42:09 +08:00
#endif
}