wuxianshengcong/Library/PackageCache/com.unity.2d.aseprite@1.1.6/Editor/Tasks/PixelBlends.cs

674 lines
20 KiB
C#
Raw Permalink Normal View History

2025-01-02 14:49:00 +08:00
using UnityEngine;
using Unity.Burst;
namespace UnityEditor.U2D.Aseprite
{
[BurstCompile]
internal static class PixelBlends
{
[BurstCompile]
public static void Normal(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
var inAlpha = inColor.a / 255f;
outColor = new Color32
{
a = (byte)(inColor.a + prevOutColor.a * (1f - inAlpha))
};
var prevAlpha = (prevOutColor.a * (1f - inAlpha)) / 255f;
var premultiplyAlpha = outColor.a > 0 ? 255f / outColor.a : 1f;
outColor.r = (byte)((inColor.r * inAlpha + prevOutColor.r * prevAlpha) * premultiplyAlpha);
outColor.g = (byte)((inColor.g * inAlpha + prevOutColor.g * prevAlpha) * premultiplyAlpha);
outColor.b = (byte)((inColor.b * inAlpha + prevOutColor.b * prevAlpha) * premultiplyAlpha);
}
[BurstCompile]
public static void Darken(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var darken = new Color32
{
r = inColor.r < prevOutColor.r ? inColor.r : prevOutColor.r,
g = inColor.g < prevOutColor.g ? inColor.g : prevOutColor.g,
b = inColor.b < prevOutColor.b ? inColor.b : prevOutColor.b,
a = inColor.a
};
Normal(in prevOutColor, in darken, out outColor);
}
[BurstCompile]
public static void Multiply(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var multiply = new Color32
{
r = MultiplyUnsignedByte(inColor.r, prevOutColor.r),
g = MultiplyUnsignedByte(inColor.g, prevOutColor.g),
b = MultiplyUnsignedByte(inColor.b, prevOutColor.b),
a = inColor.a
};
Normal(in prevOutColor, in multiply, out outColor);
}
[BurstCompile]
public static void ColorBurn(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var burn = new Color32
{
r = BurnChannel(prevOutColor.r, inColor.r),
g = BurnChannel(prevOutColor.g, inColor.g),
b = BurnChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in burn, out outColor);
}
[BurstCompile]
static byte BurnChannel(byte prevVal, byte inVal)
{
if (prevVal == 255)
return prevVal;
prevVal = (byte)(255 - prevVal);
if (prevVal >= inVal)
return 0;
var div = DivideUnsignedByte(prevVal, inVal);
return (byte)(255 - div);
}
[BurstCompile]
public static void Lighten(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var lighten = new Color32
{
r = inColor.r > prevOutColor.r ? inColor.r : prevOutColor.r,
g = inColor.g > prevOutColor.g ? inColor.g : prevOutColor.g,
b = inColor.b > prevOutColor.b ? inColor.b : prevOutColor.b,
a = inColor.a
};
Normal(in prevOutColor, in lighten, out outColor);
}
[BurstCompile]
public static void Screen(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var multiply = new Color32
{
r = MultiplyUnsignedByte(inColor.r, prevOutColor.r),
g = MultiplyUnsignedByte(inColor.g, prevOutColor.g),
b = MultiplyUnsignedByte(inColor.b, prevOutColor.b)
};
var screen = new Color32
{
r = (byte)((inColor.r + prevOutColor.r) - multiply.r),
g = (byte)((inColor.g + prevOutColor.g) - multiply.g),
b = (byte)((inColor.b + prevOutColor.b) - multiply.b),
a = inColor.a
};
Normal(in prevOutColor, in screen, out outColor);
}
[BurstCompile]
public static void ColorDodge(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var burn = new Color32
{
r = DodgeChannel(prevOutColor.r, inColor.r),
g = DodgeChannel(prevOutColor.g, inColor.g),
b = DodgeChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in burn, out outColor);
}
[BurstCompile]
static byte DodgeChannel(byte prevVal, byte inVal)
{
if (prevVal == 0)
return 0;
inVal = (byte)(255 - inVal);
if (prevVal >= inVal)
return 255;
var div = DivideUnsignedByte(prevVal, inVal);
return div;
}
[BurstCompile]
public static void Addition(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var addition = new Color32
{
r = (byte)Mathf.Min(inColor.r + prevOutColor.r, 255),
g = (byte)Mathf.Min(inColor.g + prevOutColor.g, 255),
b = (byte)Mathf.Min(inColor.b + prevOutColor.b, 255),
a = inColor.a
};
Normal(in prevOutColor, in addition, out outColor);
}
[BurstCompile]
public static void Overlay(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var overlay = new Color32
{
r = HardLightChannel(inColor.r, prevOutColor.r),
g = HardLightChannel(inColor.g, prevOutColor.g),
b = HardLightChannel(inColor.b, prevOutColor.b),
a = inColor.a
};
Normal(in prevOutColor, in overlay, out outColor);
}
[BurstCompile]
static byte HardLightChannel(byte valA, byte valB)
{
if (valB < 128)
return MultiplyUnsignedByte(valA, (byte)(valB << 1));
return ScreenUnsignedByte(valA, (byte)((valB << 1) - 255));
}
[BurstCompile]
public static void SoftLight(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var overlay = new Color32
{
r = SoftLightChannel(prevOutColor.r, inColor.r),
g = SoftLightChannel(prevOutColor.g, inColor.g),
b = SoftLightChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in overlay, out outColor);
}
[BurstCompile]
static byte SoftLightChannel(byte inA, byte inB)
{
var valA = inA / 255f;
var valB = inB / 255f;
float valC, final;
if (valA <= 0.25f)
valC = ((16 * valA - 12) * valA + 4) * valA;
else
valC = Mathf.Sqrt(valA);
if (valB <= 0.5f)
final = valA - (1f - 2f * valB) * valA * (1f - valA);
else
final = valA + (2f * valB - 1f) * (valC - valA);
return (byte)(final * 255f + 0.5f);
}
[BurstCompile]
public static void HardLight(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var overlay = new Color32
{
r = HardLightChannel(prevOutColor.r, inColor.r),
g = HardLightChannel(prevOutColor.g, inColor.g),
b = HardLightChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in overlay, out outColor);
}
[BurstCompile]
public static void Difference(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var difference = new Color32
{
r = DifferenceChannel(prevOutColor.r, inColor.r),
g = DifferenceChannel(prevOutColor.g, inColor.g),
b = DifferenceChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in difference, out outColor);
}
[BurstCompile]
static byte DifferenceChannel(byte valA, byte valB)
{
return (byte)Mathf.Abs(valA - valB);
}
[BurstCompile]
public static void Exclusion(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var exclusion = new Color32
{
r = ExclusionChannel(prevOutColor.r, inColor.r),
g = ExclusionChannel(prevOutColor.g, inColor.g),
b = ExclusionChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in exclusion, out outColor);
}
[BurstCompile]
static byte ExclusionChannel(byte valA, byte valB)
{
var valC = MultiplyUnsignedByte(valA, valB);
return (byte)(valA + valB - 2 * valC);
}
[BurstCompile]
public static void Subtract(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var subtract = new Color32
{
r = (byte)Mathf.Max(prevOutColor.r - inColor.r, 0),
g = (byte)Mathf.Max(prevOutColor.g - inColor.g, 0),
b = (byte)Mathf.Max(prevOutColor.b - inColor.b, 0),
a = inColor.a
};
Normal(in prevOutColor, in subtract, out outColor);
}
[BurstCompile]
public static void Divide(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var divide = new Color32
{
r = DivideChannel(prevOutColor.r, inColor.r),
g = DivideChannel(prevOutColor.g, inColor.g),
b = DivideChannel(prevOutColor.b, inColor.b),
a = inColor.a
};
Normal(in prevOutColor, in divide, out outColor);
}
[BurstCompile]
static byte DivideChannel(byte valA, byte valB)
{
if (valA == 0)
return 0;
else if (valA >= valB)
return 255;
else
return DivideUnsignedByte(valA, valB);
}
[BurstCompile]
public static void Hue(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var r = prevOutColor.r / 255f;
var g = prevOutColor.g / 255f;
var b = prevOutColor.b / 255f;
var s = GetSaturation(r, g, b);
var l = GetLuminosity(r, g, b);
r = inColor.r / 255f;
g = inColor.g / 255f;
b = inColor.b / 255f;
SetSaturation(ref r, ref g, ref b, s);
SetLuminosity(ref r, ref g, ref b, l);
var hue = new Color32()
{
r = (byte)Mathf.RoundToInt(r * 255f),
g = (byte)Mathf.RoundToInt(g * 255f),
b = (byte)Mathf.RoundToInt(b * 255f),
a = inColor.a
};
Normal(in prevOutColor, in hue, out outColor);
}
[BurstCompile]
public static void Saturation(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var r = inColor.r / 255f;
var g = inColor.g / 255f;
var b = inColor.b / 255f;
var s = GetSaturation(r, g, b);
r = prevOutColor.r / 255f;
g = prevOutColor.g / 255f;
b = prevOutColor.b / 255f;
var l = GetLuminosity(r, g, b);
SetSaturation(ref r, ref g, ref b, s);
SetLuminosity(ref r, ref g, ref b, l);
var saturation = new Color32()
{
r = (byte)Mathf.RoundToInt(r * 255f),
g = (byte)Mathf.RoundToInt(g * 255f),
b = (byte)Mathf.RoundToInt(b * 255f),
a = inColor.a
};
Normal(in prevOutColor, in saturation, out outColor);
}
[BurstCompile]
public static void ColorBlend(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var r = prevOutColor.r / 255f;
var g = prevOutColor.g / 255f;
var b = prevOutColor.b / 255f;
var l = GetLuminosity(r, g, b);
r = inColor.r / 255f;
g = inColor.g / 255f;
b = inColor.b / 255f;
SetLuminosity(ref r, ref g, ref b, l);
var color = new Color32()
{
r = (byte)Mathf.RoundToInt(r * 255f),
g = (byte)Mathf.RoundToInt(g * 255f),
b = (byte)Mathf.RoundToInt(b * 255f),
a = inColor.a
};
Normal(in prevOutColor, in color, out outColor);
}
[BurstCompile]
public static void Luminosity(in Color32 prevOutColor, in Color32 inColor, out Color32 outColor)
{
outColor = new Color32();
if (prevOutColor == Color.clear)
{
outColor = inColor;
return;
}
var r = inColor.r / 255f;
var g = inColor.g / 255f;
var b = inColor.b / 255f;
var l = GetLuminosity(r, g, b);
r = prevOutColor.r / 255f;
g = prevOutColor.g / 255f;
b = prevOutColor.b / 255f;
SetLuminosity(ref r, ref g, ref b, l);
var luminosity = new Color32()
{
r = (byte)Mathf.RoundToInt(r * 255f),
g = (byte)Mathf.RoundToInt(g * 255f),
b = (byte)Mathf.RoundToInt(b * 255f),
a = inColor.a
};
Normal(in prevOutColor, in luminosity, out outColor);
}
[BurstCompile]
static byte MultiplyUnsignedByte(byte valA, byte valB)
{
const uint oneHalf = 0x80;
const int gShift = 8;
var valC = (int)((valA * valB) + oneHalf);
return (byte)(((valC >> gShift) + valC) >> gShift);
}
[BurstCompile]
static byte ScreenUnsignedByte(byte valA, byte valB)
{
return (byte)(valB + valA - MultiplyUnsignedByte(valB, valA));
}
[BurstCompile]
static byte DivideUnsignedByte(byte valA, byte valB)
{
return (byte)((valA * 0xFF) / valB);
}
[BurstCompile]
static float GetSaturation(float r, float g, float b)
{
return Mathf.Max(r, Mathf.Max(g, b)) - Mathf.Min(r, Mathf.Min(g, b));
}
[BurstCompile]
static void SetSaturation(ref float r, ref float g, ref float b, float s)
{
ref var min = ref MinRef(ref r, ref MinRef(ref g, ref b));
ref var mid = ref MidRef(ref r, ref g, ref b);
ref var max = ref MaxRef(ref r, ref MaxRef(ref g, ref b));
if (max > min)
{
mid = ((mid - min) * s) / (max - min);
max = s;
}
else
mid = max = 0;
min = 0f;
}
[BurstCompile]
static ref float MaxRef(ref float a, ref float b)
{
if (a > b)
return ref a;
return ref b;
}
[BurstCompile]
static ref float MinRef(ref float a, ref float b)
{
if (a < b)
return ref a;
return ref b;
}
static ref float MidRef(ref float a, ref float b, ref float c)
{
if (a > b)
{
if (b > c)
{
return ref b;
}
if (a > c)
return ref c;
return ref a;
}
if (!(b > c))
return ref b;
if (c > a)
return ref c;
return ref a;
}
[BurstCompile]
static float GetLuminosity(float r, float g, float b)
{
return (0.3f * r) + (0.59f * g) + (0.11f * b);
}
[BurstCompile]
static void SetLuminosity(ref float r, ref float g, ref float b, float l)
{
var d = l - GetLuminosity(r, g, b);
r += d;
g += d;
b += d;
ClipColor(ref r, ref g, ref b);
}
[BurstCompile]
static void ClipColor(ref float r, ref float g, ref float b)
{
var l = GetLuminosity(r, g, b);
var n = Mathf.Min(r, Mathf.Min(g, b));
var x = Mathf.Max(r, Mathf.Max(g, b));
if (n < 0)
{
r = l + (((r - l) * l) / (l - n));
g = l + (((g - l) * l) / (l - n));
b = l + (((b - l) * l) / (l - n));
}
if (x > 1)
{
r = l + (((r - l) * (1 - l)) / (x - l));
g = l + (((g - l) * (1 - l)) / (x - l));
b = l + (((b - l) * (1 - l)) / (x - l));
}
}
}
}