using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using System.Linq;
using System.Reflection;
using System.IO;
using Object = UnityEngine.Object;
using UnityEditor.Callbacks;
#if UNITY_EDITOR
using UnityEditor;
#endif
public interface IGradientTextureForEditor
{
void CreateTexture();
Texture2D GetTexture();
void LoadExisitingTexture();
}
///
/// Main Asset, holds settings, create, hold and change Texture2D's pixels, name
///
[CreateAssetMenu(fileName = "NewGradientName", menuName = "Texture/Gradient")]
public class GradientTexture : ScriptableObject, IEquatable, 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(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(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(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(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(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