479 lines
14 KiB
C#
479 lines
14 KiB
C#
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;
|
|
using UnityEditor.Callbacks;
|
|
#endif
|
|
|
|
namespace X.Rendering.Assets
|
|
{
|
|
public interface IGradientTextureForEditor
|
|
{
|
|
void CreateTexture();
|
|
|
|
Texture2D GetTexture();
|
|
|
|
void LoadExisitingTexture();
|
|
}
|
|
|
|
/// <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;
|
|
|
|
public Texture2D GetTexture() => _texture;
|
|
|
|
public bool GetSRGB() => _sRGB;
|
|
|
|
public void SetSRGB(bool value)
|
|
{
|
|
_sRGB = value;
|
|
OnValidate();
|
|
}
|
|
|
|
int _width => _resolution.x;
|
|
int _height => _resolution.y;
|
|
|
|
public static implicit operator Texture2D(GradientTexture asset) => asset.GetTexture();
|
|
|
|
static Gradient GetDefaultGradient() => new Gradient
|
|
{
|
|
alphaKeys = new[] { new GradientAlphaKey(1, 1) },
|
|
colorKeys = new[]
|
|
{
|
|
new GradientColorKey(Color.black, 0),
|
|
new GradientColorKey(Color.white, 1)
|
|
}
|
|
};
|
|
|
|
public void FillColors(bool useRGB)
|
|
{
|
|
bool isLinear = QualitySettings.activeColorSpace == ColorSpace.Linear;
|
|
|
|
float tVertical = 0;
|
|
|
|
for (int y = 0; y < _height; y++)
|
|
{
|
|
tVertical = _verticalLerp.Evaluate((float)y / _height);
|
|
|
|
for (int x = 0; x < _width; x++)
|
|
{
|
|
float tHorizontal = (float)x / _width;
|
|
|
|
Color color = Color.Lerp(_horizontalBottom.Evaluate(tHorizontal),
|
|
_horizontalTop.Evaluate(tHorizontal),
|
|
tVertical);
|
|
|
|
color = useRGB && isLinear ? color.linear : color;
|
|
_texture.SetPixel(x, y, color);
|
|
}
|
|
}
|
|
|
|
_texture.Apply();
|
|
}
|
|
|
|
public bool Equals(Texture2D other)
|
|
{
|
|
return _texture.Equals(other);
|
|
}
|
|
|
|
void OnValidate() => ValidateTextureValues();
|
|
|
|
void IGradientTextureForEditor.LoadExisitingTexture()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!_texture)
|
|
{
|
|
string assetPath = AssetDatabase.GetAssetPath(this);
|
|
_texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void IGradientTextureForEditor.CreateTexture()
|
|
{
|
|
#if UNITY_EDITOR
|
|
//if (EditorApplication.isUpdating) return;
|
|
|
|
string assetPath = AssetDatabase.GetAssetPath(this);
|
|
if (string.IsNullOrEmpty(assetPath)) return;
|
|
|
|
if (!_texture && this != null && !EditorApplication.isUpdating)
|
|
{
|
|
AssetDatabase.ImportAsset(assetPath);
|
|
_texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
|
|
}
|
|
|
|
if (!_texture)
|
|
{
|
|
#if UNITY_2018
|
|
_texture = new Texture2D(_resolution.x, _resolution.y);
|
|
#else
|
|
_texture = new Texture2D(_resolution.x, _resolution.y, DefaultFormat.LDR, TextureCreationFlags.None);
|
|
#endif
|
|
if (_texture.name != name) _texture.name = name;
|
|
}
|
|
|
|
if (!_texture) return;
|
|
|
|
ValidateTextureValues();
|
|
|
|
if (!EditorUtility.IsPersistent(this)) return;
|
|
if (AssetDatabase.IsSubAsset(_texture)) return;
|
|
if (AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath)) return;
|
|
|
|
#if UNITY_2020_1_OR_NEWER
|
|
if (AssetDatabase.IsAssetImportWorkerProcess()) return;
|
|
#endif
|
|
AssetDatabase.AddObjectToAsset(_texture, this);
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
|
#endif
|
|
}
|
|
|
|
void ValidateTextureValues()
|
|
{
|
|
if (!_texture) return;
|
|
if (_texture.name != name)
|
|
{
|
|
_texture.name = name;
|
|
}
|
|
else
|
|
{
|
|
if (_texture.width != _resolution.x ||
|
|
_texture.height != _resolution.y)
|
|
{
|
|
#if UNITY_2022_1_OR_NEWER
|
|
_texture.Reinitialize(_resolution.x, _resolution.y);
|
|
#else
|
|
_texture.Resize(_resolution.x, _resolution.y);
|
|
#endif
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
_texture.alphaIsTransparency = true;
|
|
#endif
|
|
FillColors(_sRGB);
|
|
|
|
SetDirtyTexture();
|
|
}
|
|
}
|
|
|
|
#region Editor
|
|
|
|
[System.Diagnostics.Conditional("UNITY_EDITOR")]
|
|
void SetDirtyTexture()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!_texture) return;
|
|
|
|
EditorUtility.SetDirty(_texture);
|
|
#endif
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void OnAfterDeserialize()
|
|
{
|
|
}
|
|
|
|
public void OnBeforeSerialize()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!_texture || _texture.name == name) return;
|
|
|
|
_texture.name = name;
|
|
|
|
//AssetDatabase.SaveAssets();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[CustomEditor(typeof(GradientTexture), true), CanEditMultipleObjects]
|
|
public class GradientTextureEditor : UnityEditor.Editor
|
|
{
|
|
GradientTexture _gradientTexture;
|
|
UnityEditor.Editor _editor;
|
|
|
|
public override bool HasPreviewGUI() => true;
|
|
|
|
void OnEnable()
|
|
{
|
|
_gradientTexture = target as GradientTexture;
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
if (_gradientTexture.GetTexture() == null)
|
|
{
|
|
(_gradientTexture as IGradientTextureForEditor).CreateTexture();
|
|
}
|
|
|
|
base.OnInspectorGUI();
|
|
|
|
string buttonText = "Encode to PNG" + (targets.Length > 1 ? $" ({targets.Length})" : "");
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void DrawPreview(Rect previewArea)
|
|
{
|
|
Texture2D texture = _gradientTexture.GetTexture();
|
|
bool check = !_editor || _editor.target != texture;
|
|
|
|
if (check && texture && (_editor == null || _editor.target != texture))
|
|
{
|
|
try
|
|
{
|
|
_editor = CreateEditor(targets.Select(t => (t as GradientTexture)?.GetTexture()).ToArray());
|
|
}
|
|
catch
|
|
{
|
|
_editor = null;
|
|
//Debug.LogException(e);
|
|
//throw;
|
|
}
|
|
}
|
|
|
|
if (_editor && _editor.target)
|
|
{
|
|
try
|
|
{
|
|
_editor.DrawPreview(previewArea);
|
|
}
|
|
catch
|
|
{
|
|
//Debug.LogException(e);
|
|
//throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void OnPreviewSettings()
|
|
{
|
|
if (_editor && _editor.target)
|
|
{
|
|
try
|
|
{
|
|
_editor.OnPreviewSettings();
|
|
}
|
|
catch
|
|
{
|
|
//Debug.LogException(e);
|
|
//throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void ReloadPreviewInstances()
|
|
{
|
|
if (_editor && _editor.target)
|
|
{
|
|
try
|
|
{
|
|
_editor.ReloadPreviewInstances();
|
|
}
|
|
catch
|
|
{
|
|
//Debug.LogException(e);
|
|
//throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
|
|
{
|
|
if (_editor && _editor.target)
|
|
{
|
|
try
|
|
{
|
|
_editor.OnInteractivePreviewGUI(r, background);
|
|
}
|
|
catch
|
|
{
|
|
//Debug.LogException(e);
|
|
//throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void OnPreviewGUI(Rect r, GUIStyle background)
|
|
{
|
|
if (_editor && _editor.target)
|
|
{
|
|
try
|
|
{
|
|
_editor.OnPreviewGUI(r, background);
|
|
}
|
|
catch
|
|
{
|
|
//Debug.LogException(e);
|
|
//throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
|
|
{
|
|
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)
|
|
{
|
|
_editor.GetType().GetMethod("OnDisable", BindingFlags.NonPublic)?.Invoke(_editor, null);
|
|
}
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
if (_editor)
|
|
{
|
|
DestroyImmediate(_editor);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class DragAndDropUtility
|
|
{
|
|
static DragAndDrop.ProjectBrowserDropHandler _handlerProject;
|
|
|
|
[InitializeOnLoadMethod]
|
|
public static void Init()
|
|
{
|
|
_handlerProject = ProjectDropHandler;
|
|
DragAndDrop.RemoveDropHandler(_handlerProject);
|
|
DragAndDrop.AddDropHandler(_handlerProject);
|
|
}
|
|
|
|
private static DragAndDropVisualMode ProjectDropHandler(int dragInstanceId, string dropUponPath, bool perform)
|
|
{
|
|
if (!perform)
|
|
{
|
|
var dragged = DragAndDrop.objectReferences;
|
|
bool found = false;
|
|
for (var i = 0; i < dragged.Length; i++)
|
|
{
|
|
if (dragged[i] is GradientTexture gradient)
|
|
{
|
|
dragged[i] = gradient.GetTexture();
|
|
found = true;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
DragAndDrop.objectReferences = dragged;
|
|
GUI.changed = true;
|
|
return default;
|
|
}
|
|
|
|
}
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public class ProjectIconsUtility
|
|
{
|
|
[DidReloadScripts]
|
|
static ProjectIconsUtility()
|
|
{
|
|
EditorApplication.projectWindowItemOnGUI -= ItemOnGUI;
|
|
EditorApplication.projectWindowItemOnGUI += ItemOnGUI;
|
|
}
|
|
|
|
static void ItemOnGUI(string guid, Rect rect)
|
|
{
|
|
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
|
var asset = AssetDatabase.LoadAssetAtPath<GradientTexture>(assetPath);
|
|
|
|
if (asset == null) return;
|
|
if (!asset.GetTexture()) return;
|
|
|
|
|
|
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());
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
} |