Files
KopMap/Assets/FImpossible Creations/Editor/Editor Tools/F Texture Tools/FTexture Edit Windows/FTexEqualizeWindow.cs
2025-09-02 18:55:19 +08:00

346 lines
15 KiB
C#

using FIMSpace.FEditor;
using UnityEditor;
using UnityEngine;
namespace FIMSpace.FTextureTools
{
public class FTexEqualizeWindow : FTextureProcessWindow
{
private float Equalize = 0.5f;
private float EqualizeWhites = 1f;
private float EqualizeBlacks = 1f;
private float EqualizeTexture = 0f;
bool MaskingMode = false;
Texture2D TexturizeWith;
Color MaskingColor = Color.white;
bool TexturizeReadable = false;
float TexturizeTiling = 1f;
AnimationCurve WhitesIntensity = AnimationCurve.EaseInOut(0f, 1f, 1f, 1f);
AnimationCurve ShadowsIntensity = AnimationCurve.EaseInOut(0f, 1f, 1f, 1f);
Texture2D texturizeMemo = null;
EMaskExport maskExport = EMaskExport.None;
public static void Init()
{
FTexEqualizeWindow window = (FTexEqualizeWindow)GetWindow(typeof(FTexEqualizeWindow));
window.titleContent = new GUIContent("Texure Equalize", FTextureToolsGUIUtilities.FindIcon("SPR_EqualizerGen"), "Tweak too bright or too dark parts of your texture");
window.previewScale = FEPreview.m_1x1;
window.drawPreviewScale = true;
window.position = new Rect(340, 50, 585, 630);
window.Show();
called = true;
}
protected override void OnGUICustom()
{
EditorGUI.BeginChangeCheck();
GUI.backgroundColor = new Color(0.6f, 1f, 0.7f);
Equalize = EditorGUILayout.Slider(new GUIContent("Equalize Amount"), Equalize, 0.0f, 1f);
GUI.backgroundColor = Color.white;
GUILayout.Space(8);
EditorGUI.indentLevel++;
EditorGUILayout.BeginHorizontal();
EditorGUIUtility.labelWidth = 0;
EqualizeWhites = EditorGUILayout.Slider(new GUIContent("Whites"), EqualizeWhites, 0f, 2f, GUILayout.MaxWidth(position.width - 60));
EditorGUIUtility.labelWidth = 5;
WhitesIntensity = EditorGUILayout.CurveField(new GUIContent(" ", "Whites mapping power intensity control basing on the pixel brightness. X = brightness value -> 0 is black 1 is white, Y = highlights intensity blend from 0 to 1"), WhitesIntensity, Color.cyan, new Rect(0f, 0, 1f, 1f), GUILayout.Width(44));
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUIUtility.labelWidth = 0;
EqualizeBlacks = EditorGUILayout.Slider(new GUIContent("Shadows"), EqualizeBlacks, 0f, 2f, GUILayout.MaxWidth(position.width - 60));
EditorGUIUtility.labelWidth = 5;
ShadowsIntensity = EditorGUILayout.CurveField(new GUIContent(" ", "shadows mapping power intensity control basing on the pixel brightness. X = brightness value -> 0 is black 1 is white, Y = shadows intensity blend from 0 to 1"), ShadowsIntensity, Color.gray, new Rect(0f, 0, 1f, 1f), GUILayout.Width(44));
EditorGUIUtility.labelWidth = 0;
EditorGUILayout.EndHorizontal();
GUILayout.Space(8);
EditorGUILayout.BeginHorizontal();
MaskingMode = EditorGUILayout.Toggle(new GUIContent("Masking Mode:", "Using single color to replace target texture areas, which can be useful when generating masks for shaders."), MaskingMode);
if (MaskingMode)
{
MaskingColor = EditorGUILayout.ColorField("Masking Color", MaskingColor);
if (GUILayout.Button(new GUIContent(" Export", FTextureToolsGUIUtilities.FindIcon("SPR_GrayscaleS"), "Export mask as grayscale .png file"), GUILayout.MaxWidth(70)))
{
Texture2D newFile = GenerateExtraFile();
if (newFile != null)
{
maskExport = EMaskExport.Grayscale;
ApplyTexProcessToFile(newFile);
}
}
if (GUILayout.Button(new GUIContent(" Export", FTextureToolsGUIUtilities.FindIcon("SPR_rgbscale"), "Export mask as color channel .png file"), GUILayout.MaxWidth(70)))
{
Texture2D newFile = GenerateExtraFile();
if (newFile != null)
{
maskExport = EMaskExport.Color;
ApplyTexProcessToFile(newFile);
}
}
EditorGUILayout.EndHorizontal();
}
else
{
EditorGUILayout.EndHorizontal();
GUI.backgroundColor = new Color(0.6f, 1f, 0.6f, 1f);
EqualizeTexture = EditorGUILayout.Slider(new GUIContent("Texturize Blend:"), EqualizeTexture, 0f, 1f);
GUI.backgroundColor = Color.white;
TexturizeReadable = false;
if (EqualizeTexture > 0f)
{
EditorGUILayout.HelpBox("Texture should be tileable in order to paint mask without seams.", MessageType.None);
TexturizeWith = (Texture2D)EditorGUILayout.ObjectField(new GUIContent("Texturize (Optional)"), TexturizeWith, typeof(Texture2D), false, GUILayout.Height(40));
seed = EditorGUILayout.IntSlider(new GUIContent(" Seed", FTextureToolsGUIUtilities.FindIcon("FRandomIcon")), seed, -50, 50);
if (TexturizeWith != null)
{
string path = AssetDatabase.GetAssetPath(TexturizeWith);
TextureImporter tImp = (TextureImporter)AssetImporter.GetAtPath(path);
if (tImp is null == false)
{
TexturizeReadable = tImp.isReadable;
GUILayout.Space(4);
EditorGUILayout.BeginHorizontal();
GUILayout.Space(32);
if (tImp.isReadable == false) GUI.backgroundColor = Color.green;
if (GUILayout.Button("Switch readonly for '" + TexturizeWith.name + "' to " + (!tImp.isReadable).ToString()))
{
tImp.isReadable = !tImp.isReadable;
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
TexturizeReadable = tImp.isReadable;
}
GUI.backgroundColor = Color.white;
GUILayout.Space(32);
EditorGUILayout.EndHorizontal();
GUILayout.Space(5);
EditorGUILayout.BeginHorizontal();
float highRange = TexturizeTiling > 4f ? 16f : 4.001f;
TexturizeTiling = EditorGUILayout.Slider("Texturize Tiling:", TexturizeTiling, 0.05f, highRange);
EditorGUILayout.EndHorizontal();
Texture2D srcTex = GetFirstTexture;
if (srcTex) if (TexturizeWith.width != srcTex.width)
{
EditorGUILayout.HelpBox("Texture sizes differs, preview can look different than final file result!", MessageType.None);
}
}
if (TexturizeReadable == false)
EditorGUILayout.HelpBox("Texture must have 'Read/Write' enabled", MessageType.Warning);
}
else
TexturizeReadable = false;
}
}
maskExport = EMaskExport.None;
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
somethingChanged = true;
else
somethingChanged = false;
}
protected override void ProcessTexture(Texture2D source, Texture2D target, bool preview = true)
{
if (!preview) EditorUtility.DisplayProgressBar("Equalizing Texture...", "Preparing... ", 2f / 5f);
#region Preparing variables to use down below
Color32[] sourcePixels = source.GetPixels32();
Color32[] newPixels = source.GetPixels32();
Color32[] texturizePixels = sourcePixels;
Texture2D texturizeSource = source;
if (MaskingMode)
{
texturizePixels = texturizeSource.GetPixels32();
for (int i = 0; i < texturizePixels.Length; i++) texturizePixels[i] = (Color32)MaskingColor;
}
else
{
if (TexturizeWith != null) if (TexturizeReadable)
{
int targetWidth = Mathf.RoundToInt(source.width / TexturizeTiling);
int targetHeight = Mathf.RoundToInt(source.height / TexturizeTiling);
if (targetWidth < 1) targetWidth = 1;
if (targetHeight < 1) targetHeight = 1;
if (texturizeMemo == null || texturizeMemo.width != targetWidth || texturizeMemo.height != targetHeight)
{
texturizeMemo = FTextureEditorToolsMethods.GenerateScaledTexture2DReference(TexturizeWith, new Vector2(targetWidth, targetHeight), preview ? 2 : 4);
}
texturizeSource = texturizeMemo;
texturizePixels = texturizeSource.GetPixels32();
}
}
if (source.width != target.width || source.height != target.height)
{
Debug.LogError("[SEAMLESS GENERATOR] Source texture is different scale or target texture! Can't create seamless texture!");
return;
}
Vector2 dimensions = GetDimensions(source);
#endregion
#region Equalizing Texture
if (!preview)
EditorUtility.DisplayProgressBar("Equalizing...", "Equalizing... ", 3f / 5f);
Vector3 rgbAverages = new Vector3(0.0f, 0.0f, 0.0f);
Vector3 hsvAverages = new Vector3(0.0f, 0.0f, 0.0f);
Vector2 dim = new Vector2(source.width, source.height);
for (int x = 0; x < source.width; x++)
{
for (int y = 0; y < source.height; y++)
{
int px = GetPX(x, y, dim);
Color c = sourcePixels[px];
rgbAverages.x += c.r;
rgbAverages.y += c.g;
rgbAverages.z += c.b;
float h, s, v;
Color.RGBToHSV(sourcePixels[px], out h, out s, out v);
hsvAverages.x += h;
hsvAverages.y += s;
hsvAverages.z += v;
}
}
float norm = source.width * source.height;
Vector3 rgbAveragesN = rgbAverages / norm;
Vector3 hsvAveragesN = hsvAverages / norm;
float highestVDiff = 0f;
for (int x = 0; x < source.width; x++)
{
for (int y = 0; y < source.height; y++)
{
int px = GetPX(x, y, dim);
float h, s, v;
Color.RGBToHSV(sourcePixels[px], out h, out s, out v);
hsvAverages.x += h;
hsvAverages.y += s;
hsvAverages.z += v;
float diff = Mathf.Abs(v - hsvAveragesN.z);
if (diff > highestVDiff) highestVDiff = diff;
}
}
Color avgHsvCol = Color.HSVToRGB(hsvAveragesN.x, hsvAveragesN.y, hsvAveragesN.z);
int randX = RandomRange(texturizeSource.width / 2, texturizeSource.width / 2 + (RandomRange(0f, 1f) < 0.5f ? texturizeSource.width / 3 : -source.width / 3));
int randY = RandomRange(texturizeSource.height / 2, texturizeSource.height / 2 + (RandomRange(0f, 1f) < 0.5f ? texturizeSource.height / 3 : -source.height / 3));
for (int x = 0; x < source.width; x++)
{
for (int y = 0; y < source.height; y++)
{
int px = GetPX(x, y, dim);
Color srcPixel = sourcePixels[px];
float h, s, v;
Color.RGBToHSV(srcPixel, out h, out s, out v);
float vDiff = v - hsvAveragesN.z;
float diffTexBase = Mathf.Abs(v - hsvAveragesN.z);
if (vDiff > 0)
{
// Whites lower then less changed
vDiff *= WhitesIntensity.Evaluate(vDiff) * EqualizeWhites;
}
else
if (vDiff < 0)
{
// Blacks lower then less changed
vDiff *= ShadowsIntensity.Evaluate(1f - Mathf.Abs(vDiff)) * EqualizeBlacks;
}
float lerpV = Mathf.Abs(vDiff) / highestVDiff;
float tgtV = Mathf.LerpUnclamped(v, hsvAveragesN.z, lerpV);
Color tgtColor = Color.HSVToRGB(h, s, tgtV);
if (MaskingMode)
{
if (maskExport == EMaskExport.None)
{
Color offsetRefColor = texturizePixels[GetPXLoopSkipEdges(randX + x, randY + y, new Vector2(texturizeSource.width, texturizeSource.height))];
tgtColor = Color.Lerp(tgtColor, offsetRefColor, lerpV * 2f);
}
else if (maskExport == EMaskExport.Color)
{
tgtColor = Color.Lerp(Color.black, MaskingColor, lerpV * 2f);
}
else if (maskExport == EMaskExport.Grayscale)
{
tgtColor = Color.Lerp(Color.black, Color.white, lerpV * 2f);
}
}
else if (EqualizeTexture > 0f)
{
Color offsetRefColor = texturizePixels[GetPXLoopSkipEdges(randX + x, randY + y, new Vector2(texturizeSource.width, texturizeSource.height))];
tgtColor = Color.Lerp(tgtColor, offsetRefColor, lerpV * 2f * EqualizeTexture);
}
tgtColor.a = srcPixel.a;
newPixels[px] = Color32.LerpUnclamped(sourcePixels[px], tgtColor, Equalize);
}
}
maskExport = EMaskExport.None;
#endregion
// Finalizing changes
if (!preview) EditorUtility.DisplayProgressBar("Equalizing Texture...", "Applying Equalization to Texture... ", 3.85f / 5f);
target.SetPixels32(newPixels);
target.Apply(false, false);
if (!preview)
EditorUtility.ClearProgressBar();
}
}
}