Add support for sbyte and short in IColor<T>

This commit is contained in:
Jeremy Pritts committed 2022-11-04 16:02:42 -04:00
1 parent 89b76dafd3
commit dc1ecc5d46
2 files changed
+132 -7

No files matched your search

@@ -11,10 +11,20 @@
{
return Unsafe.As<TFrom, TTo>(ref value);
}
else if (typeof(TFrom) == typeof(sbyte))
{
byte converted = ChangeSign(Unsafe.As<TFrom, sbyte>(ref value));
return ConvertUInt8<TTo>(converted);
}
else if(typeof(TFrom) == typeof(byte))
{
return ConvertUInt8<TTo>(Unsafe.As<TFrom, byte>(ref value));
}
else if (typeof(TFrom) == typeof(short))
{
ushort converted = ChangeSign(Unsafe.As<TFrom, short>(ref value));
return ConvertUInt16<TTo>(converted);
}
else if (typeof(TFrom) == typeof(ushort))
{
return ConvertUInt16<TTo>(Unsafe.As<TFrom, ushort>(ref value));
@@ -40,13 +50,23 @@
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertUInt8<TTo>(byte value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(byte))
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(value);
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
return Unsafe.As<byte, TTo>(ref value);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ConvertUInt8ToUInt16(value));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = unchecked((ushort)((uint)value << 8));
ushort converted = ConvertUInt8ToUInt16(value);
return Unsafe.As<ushort, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(Half))
@@ -68,16 +88,29 @@
{
return ThrowOrReturnDefault<TTo>();
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
static ushort ConvertUInt8ToUInt16(byte value) => unchecked((ushort)((uint)value << 8));
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertUInt16<TTo>(ushort value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(byte))
if (typeof(TTo) == typeof(sbyte))
{
byte converted = unchecked((byte)((uint)value >> 8));
sbyte converted = ChangeSign(ConvertUInt16ToUInt8(value));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ConvertUInt16ToUInt8(value);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(value);
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
return Unsafe.As<ushort, TTo>(ref value);
@@ -101,16 +134,29 @@
{
return ThrowOrReturnDefault<TTo>();
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
static byte ConvertUInt16ToUInt8(ushort value) => unchecked((byte)((uint)value >> 8));
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertHalf<TTo>(Half value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(byte))
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ClampUInt8((float)value * byte.MaxValue));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ClampUInt8((float)value * byte.MaxValue);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ClampUInt16((float)value * ushort.MaxValue));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ClampUInt16((float)value * ushort.MaxValue);
@@ -139,11 +185,21 @@
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertSingle<TTo>(float value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(byte))
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ClampUInt8(value * byte.MaxValue));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ClampUInt8(value * byte.MaxValue);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ClampUInt16(value * ushort.MaxValue));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ClampUInt16(value * ushort.MaxValue);
@@ -172,11 +228,21 @@
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertDouble<TTo>(double value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(byte))
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ClampUInt8(value * byte.MaxValue));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ClampUInt8(value * byte.MaxValue);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ClampUInt16(value * ushort.MaxValue));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ClampUInt16(value * ushort.MaxValue);
@@ -235,5 +301,45 @@
{
return ushort.MaxValue < x ? ushort.MaxValue : (x > ushort.MinValue ? (ushort)x : ushort.MinValue);
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static byte ChangeSign(sbyte x)
{
unchecked
{
const uint SignBit = 0x80;
return (byte)((uint)x ^ SignBit);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static sbyte ChangeSign(byte x)
{
unchecked
{
const uint SignBit = 0x80;
return (sbyte)(x ^ SignBit);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static ushort ChangeSign(short x)
{
unchecked
{
const uint SignBit = 0x8000;
return (ushort)((uint)x ^ SignBit);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static short ChangeSign(ushort x)
{
unchecked
{
const uint SignBit = 0x8000;
return (short)(x ^ SignBit);
}
}
}
}
+19
View File
@@ -1,5 +1,24 @@
namespace AssetRipper.TextureDecoder.Rgb
{
/// <summary>
/// An <see langword="interface"/> for handling color formats with up to 4 channels.
/// </summary>
/// <remarks>
/// When used as a generic type constraint, the methods and properties get devirtualized by the JIT compiler.
/// This prevents boxing when the implementing type is a <see langword="struct"/>.
/// </remarks>
/// <typeparam name="T">
/// Supported types are:
/// <list type="bullet">
/// <item><see cref="sbyte"/></item>
/// <item><see cref="byte"/></item>
/// <item><see cref="short"/></item>
/// <item><see cref="ushort"/></item>
/// <item><see cref="Half"/></item>
/// <item><see cref="float"/></item>
/// <item><see cref="double"/></item>
/// </list>
/// </typeparam>
public interface IColor<T> where T : unmanaged
{
/// <summary>