Some color format work and indexed colors.
This commit is contained in:
parent
e070aa097f
commit
6182db049e
@ -271,8 +271,8 @@ namespace Nerd_STF.Graphics
|
|||||||
// Inlined version of AsRgb().AsHsv()
|
// Inlined version of AsRgb().AsHsv()
|
||||||
double diffK = 1 - k;
|
double diffK = 1 - k;
|
||||||
double r = (1 - c) * diffK, g = (1 - m) * diffK, b = (1 - y) * diffK;
|
double r = (1 - c) * diffK, g = (1 - m) * diffK, b = (1 - y) * diffK;
|
||||||
double[] items = new double[] { r, g, b };
|
double[] group = new double[] { r, g, b };
|
||||||
double cMax = MathE.Max(items), cMin = MathE.Min(items), delta = cMax - cMin;
|
double cMax = MathE.Max(group), cMin = MathE.Min(group), delta = cMax - cMin;
|
||||||
Angle h;
|
Angle h;
|
||||||
|
|
||||||
if (delta == 0) h = Angle.Zero;
|
if (delta == 0) h = Angle.Zero;
|
||||||
@ -343,7 +343,7 @@ namespace Nerd_STF.Graphics
|
|||||||
|
|
||||||
public static ColorCMYK operator +(ColorCMYK a, ColorCMYK b) => new ColorCMYK(a.c + b.c, a.m + b.m, a.y + b.y, a.k + b.k, 1 - (1 - a.a) * (1 - b.a));
|
public static ColorCMYK operator +(ColorCMYK a, ColorCMYK b) => new ColorCMYK(a.c + b.c, a.m + b.m, a.y + b.y, a.k + b.k, 1 - (1 - a.a) * (1 - b.a));
|
||||||
public static ColorCMYK operator *(ColorCMYK a, ColorCMYK b) => new ColorCMYK(a.c * b.c, a.m * b.m, a.y * b.y, a.k * b.k, a.a * b.a);
|
public static ColorCMYK operator *(ColorCMYK a, ColorCMYK b) => new ColorCMYK(a.c * b.c, a.m * b.m, a.y * b.y, a.k * b.k, a.a * b.a);
|
||||||
public static ColorCMYK operator *(ColorCMYK a, double b) => new ColorCMYK(a.c * b, a.m * b, a.y * b, a.k * b, a.a);
|
public static ColorCMYK operator *(ColorCMYK a, double b) => new ColorCMYK(a.c, a.m, a.y, b == 0 ? 1 : MathE.Clamp(a.k / b, 0, 1), a.a);
|
||||||
public static bool operator ==(ColorCMYK a, IColor b) => a.Equals(b.AsCmyk());
|
public static bool operator ==(ColorCMYK a, IColor b) => a.Equals(b.AsCmyk());
|
||||||
public static bool operator !=(ColorCMYK a, IColor b) => !a.Equals(b.AsCmyk());
|
public static bool operator !=(ColorCMYK a, IColor b) => !a.Equals(b.AsCmyk());
|
||||||
public static bool operator ==(ColorCMYK a, ColorCMYK b) => a.Equals(b);
|
public static bool operator ==(ColorCMYK a, ColorCMYK b) => a.Equals(b);
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
Cyan,
|
Cyan,
|
||||||
Magenta,
|
Magenta,
|
||||||
Yellow,
|
Yellow,
|
||||||
Key
|
Key,
|
||||||
|
Index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
158
Nerd_STF/Graphics/ColorPalette.cs
Normal file
158
Nerd_STF/Graphics/ColorPalette.cs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
using Nerd_STF.Graphics.Formats;
|
||||||
|
using Nerd_STF.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Nerd_STF.Graphics
|
||||||
|
{
|
||||||
|
// TODO: Should this be a ref struct?
|
||||||
|
public class ColorPalette<TColor> : IEnumerable<TColor>, IEquatable<ColorPalette<TColor>>
|
||||||
|
where TColor : struct, IColor<TColor>
|
||||||
|
{
|
||||||
|
public int BitDepth { get; private set; }
|
||||||
|
public int Length => colors.Length;
|
||||||
|
|
||||||
|
private TColor[] colors;
|
||||||
|
private IndexedColor<TColor>[] indexedColors;
|
||||||
|
|
||||||
|
#pragma warning disable CS8618
|
||||||
|
private ColorPalette() { }
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
public ColorPalette(int colors)
|
||||||
|
{
|
||||||
|
int size = GetSizeFor(colors, out int bits);
|
||||||
|
this.colors = new TColor[size];
|
||||||
|
indexedColors = new IndexedColor<TColor>[size];
|
||||||
|
for (int i = 0; i < size; i++) indexedColors[i] = new IndexedColor<TColor>(this, i);
|
||||||
|
BitDepth = bits;
|
||||||
|
}
|
||||||
|
public ColorPalette(ReadOnlySpan<TColor> colors)
|
||||||
|
{
|
||||||
|
int size = GetSizeFor(colors.Length, out int bits);
|
||||||
|
this.colors = new TColor[size];
|
||||||
|
colors.CopyTo(this.colors);
|
||||||
|
indexedColors = new IndexedColor<TColor>[size];
|
||||||
|
for (int i = 0; i < size; i++) indexedColors[i] = new IndexedColor<TColor>(this, i);
|
||||||
|
BitDepth = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ColorPalette<TColor> FromBitDepth(int bits)
|
||||||
|
{
|
||||||
|
int size = 1 << bits;
|
||||||
|
ColorPalette<TColor> palette = new ColorPalette<TColor>()
|
||||||
|
{
|
||||||
|
BitDepth = bits,
|
||||||
|
colors = new TColor[size],
|
||||||
|
indexedColors = new IndexedColor<TColor>[size]
|
||||||
|
};
|
||||||
|
for (int i = 0; i < size; i++) palette.indexedColors[i] = new IndexedColor<TColor>(palette, i);
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexedColor<TColor> this[int index] => indexedColors[index];
|
||||||
|
public ref TColor Color(int index) => ref colors[index];
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < colors.Length; i++)
|
||||||
|
{
|
||||||
|
colors[i] = default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool Contains(TColor color)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Length; i++)
|
||||||
|
{
|
||||||
|
if (colors[i].Equals(color)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public bool Contains(Predicate<TColor> predicate)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Length; i++)
|
||||||
|
{
|
||||||
|
if (predicate(colors[i])) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public void CopyTo(Span<TColor> destination) => CopyTo(0, destination, 0, Length);
|
||||||
|
public void CopyTo(int sourceIndex, Span<TColor> destination, int destIndex, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
destination[destIndex + i] = colors[sourceIndex + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Expand(int newSize)
|
||||||
|
{
|
||||||
|
int newLength = GetSizeFor(newSize, out int bits);
|
||||||
|
if (newLength <= Length) return; // Contraction not currently supported.
|
||||||
|
TColor[] newColors = new TColor[newLength];
|
||||||
|
IndexedColor<TColor>[] newIndexedColors = new IndexedColor<TColor>[newLength];
|
||||||
|
Array.Copy(colors, newColors, colors.Length);
|
||||||
|
Array.Copy(indexedColors, newIndexedColors, indexedColors.Length);
|
||||||
|
for (int i = Length; i < newLength; i++) newIndexedColors[i] = new IndexedColor<TColor>(this, i);
|
||||||
|
colors = newColors;
|
||||||
|
indexedColors = newIndexedColors;
|
||||||
|
BitDepth = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public bool ReferenceEquals(ColorPalette<TColor>? other)
|
||||||
|
#else
|
||||||
|
public bool ReferenceEquals(ColorPalette<TColor> other)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return ReferenceEquals(this, other);
|
||||||
|
}
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public bool Equals(ColorPalette<TColor>? other)
|
||||||
|
#else
|
||||||
|
public bool Equals(ColorPalette<TColor> other)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (other is null) return false;
|
||||||
|
else if (Length != other.Length) return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < Length; i++)
|
||||||
|
{
|
||||||
|
if (!colors[i].Equals(other.colors[i])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public override bool Equals(object? other)
|
||||||
|
#else
|
||||||
|
public override bool Equals(object other)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (other is null) return false;
|
||||||
|
else if (other is ColorPalette<TColor> otherColor) return Equals(otherColor);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
|
public override string ToString() => $"{BitDepth} BPP Palette: {typeof(TColor).Name}[{Length}]";
|
||||||
|
|
||||||
|
public IEnumerator<TColor> GetEnumerator()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < colors.Length; i++) yield return colors[i];
|
||||||
|
}
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
private static int GetSizeFor(int colors, out int bitDepth)
|
||||||
|
{
|
||||||
|
int maxSize = 1;
|
||||||
|
bitDepth = 0;
|
||||||
|
colors--;
|
||||||
|
while (colors > 0)
|
||||||
|
{
|
||||||
|
maxSize <<= 1;
|
||||||
|
colors >>= 1;
|
||||||
|
bitDepth++;
|
||||||
|
}
|
||||||
|
return maxSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -287,7 +287,8 @@ namespace Nerd_STF.Graphics
|
|||||||
public ColorHSV AsHsv()
|
public ColorHSV AsHsv()
|
||||||
{
|
{
|
||||||
// Thanks https://www.rapidtables.com/convert/color/rgb-to-hsv.html
|
// Thanks https://www.rapidtables.com/convert/color/rgb-to-hsv.html
|
||||||
double cMax = MathE.Max(this), cMin = MathE.Min(this), delta = cMax - cMin;
|
double[] group = new double[] { r, g, b };
|
||||||
|
double cMax = MathE.Max(group), cMin = MathE.Min(group), delta = cMax - cMin;
|
||||||
Angle h;
|
Angle h;
|
||||||
|
|
||||||
if (delta == 0) h = Angle.Zero;
|
if (delta == 0) h = Angle.Zero;
|
||||||
@ -302,7 +303,7 @@ namespace Nerd_STF.Graphics
|
|||||||
public ColorCMYK AsCmyk()
|
public ColorCMYK AsCmyk()
|
||||||
{
|
{
|
||||||
// Thanks https://www.rapidtables.com/convert/color/rgb-to-cmyk.html
|
// Thanks https://www.rapidtables.com/convert/color/rgb-to-cmyk.html
|
||||||
double diffK = MathE.Max(this), invDiffK = 1 / diffK;
|
double diffK = MathE.Max(new double[] { r, g, b }), invDiffK = 1 / diffK;
|
||||||
return new ColorCMYK((diffK - r) * invDiffK,
|
return new ColorCMYK((diffK - r) * invDiffK,
|
||||||
(diffK - g) * invDiffK,
|
(diffK - g) * invDiffK,
|
||||||
(diffK - b) * invDiffK,
|
(diffK - b) * invDiffK,
|
||||||
|
|||||||
53
Nerd_STF/Graphics/Formats/IColorFormat.cs
Normal file
53
Nerd_STF/Graphics/Formats/IColorFormat.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Nerd_STF.Graphics.Formats
|
||||||
|
{
|
||||||
|
public interface IColorFormat
|
||||||
|
{
|
||||||
|
int ChannelCount { get; }
|
||||||
|
int BitLength { get; }
|
||||||
|
Dictionary<ColorChannel, int> BitsPerChannel { get; }
|
||||||
|
byte[] GetBitfield(ColorChannel channel);
|
||||||
|
|
||||||
|
byte[] GetBits();
|
||||||
|
IColor GetColor();
|
||||||
|
|
||||||
|
// TODO: Bitwriter?
|
||||||
|
// write to stream
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IColorFormat<TSelf, TColor> : IColorFormat,
|
||||||
|
IEquatable<TSelf>
|
||||||
|
where TSelf : IColorFormat<TSelf, TColor>
|
||||||
|
where TColor : struct, IColor<TColor>
|
||||||
|
{
|
||||||
|
#if CS11_OR_GREATER
|
||||||
|
new static abstract int BitLength { get; }
|
||||||
|
int IColorFormat.BitLength => TSelf.BitLength;
|
||||||
|
|
||||||
|
new static abstract Dictionary<ColorChannel, int> BitsPerChannel { get; }
|
||||||
|
Dictionary<ColorChannel, int> IColorFormat.BitsPerChannel => TSelf.BitsPerChannel;
|
||||||
|
|
||||||
|
new static abstract byte[] GetBitfield(ColorChannel channel);
|
||||||
|
byte[] IColorFormat.GetBitfield(ColorChannel channel) => TSelf.GetBitfield(channel);
|
||||||
|
|
||||||
|
static abstract TSelf FromColor(IColor color);
|
||||||
|
static abstract TSelf FromColor(TColor color);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
new TColor GetColor();
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
IColor IColorFormat.GetColor() => GetColor();
|
||||||
|
#endif
|
||||||
|
void SetColor(TColor color);
|
||||||
|
|
||||||
|
#if CS11_OR_GREATER
|
||||||
|
static abstract TSelf operator +(TSelf a, TSelf b);
|
||||||
|
static abstract TSelf operator *(TSelf a, TSelf b);
|
||||||
|
|
||||||
|
static abstract bool operator ==(TSelf a, TSelf b);
|
||||||
|
static abstract bool operator !=(TSelf a, TSelf b);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
80
Nerd_STF/Graphics/Formats/IndexedColor.cs
Normal file
80
Nerd_STF/Graphics/Formats/IndexedColor.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using Nerd_STF.Helpers;
|
||||||
|
using Nerd_STF.Mathematics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Nerd_STF.Graphics.Formats
|
||||||
|
{
|
||||||
|
public class IndexedColor<TColor> : IColorFormat, IEquatable<IndexedColor<TColor>>
|
||||||
|
where TColor : struct, IColor<TColor>
|
||||||
|
{
|
||||||
|
public int BitLength => palette.BitDepth;
|
||||||
|
public int Index { get; }
|
||||||
|
|
||||||
|
int IColorFormat.ChannelCount => 1;
|
||||||
|
Dictionary<ColorChannel, int> IColorFormat.BitsPerChannel => new Dictionary<ColorChannel, int>()
|
||||||
|
{
|
||||||
|
{ ColorChannel.Index, palette.BitDepth }
|
||||||
|
};
|
||||||
|
byte[] IColorFormat.GetBitfield(ColorChannel channel)
|
||||||
|
{
|
||||||
|
byte[] buf = new byte[MathE.Ceiling(palette.BitDepth / 8.0)];
|
||||||
|
if (channel != ColorChannel.Index) return buf; // All zeroes.
|
||||||
|
int wholes = palette.BitDepth / 8, parts = palette.BitDepth % 8;
|
||||||
|
for (int i = 0; i < wholes; i++) buf[i] = 0xFF;
|
||||||
|
for (int i = 0; i < parts; i++) buf[wholes] = (byte)((buf[wholes] << 1) + 1);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ColorPalette<TColor> palette;
|
||||||
|
|
||||||
|
public IndexedColor(ColorPalette<TColor> palette, int index)
|
||||||
|
{
|
||||||
|
this.palette = palette;
|
||||||
|
Index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorPalette<TColor> GetPalette() => palette;
|
||||||
|
|
||||||
|
public ref TColor Color() => ref palette.Color(Index);
|
||||||
|
IColor IColorFormat.GetColor() => Color();
|
||||||
|
public byte[] GetBits()
|
||||||
|
{
|
||||||
|
byte[] buf = new byte[MathE.Ceiling(palette.BitDepth / 8.0)];
|
||||||
|
int bitIndex = 0, byteIndex = 0, remaining = Index;
|
||||||
|
while (remaining > 0)
|
||||||
|
{
|
||||||
|
buf[byteIndex] |= (byte)((remaining & 1) << bitIndex);
|
||||||
|
remaining >>= 1;
|
||||||
|
bitIndex++;
|
||||||
|
if (bitIndex == 8)
|
||||||
|
{
|
||||||
|
bitIndex = 0;
|
||||||
|
byteIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReferenceEquals(IndexedColor<TColor> other) => ReferenceEquals(this, other);
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public bool Equals(IndexedColor<TColor>? other)
|
||||||
|
#else
|
||||||
|
public bool Equals(IndexedColor<TColor> other)
|
||||||
|
#endif
|
||||||
|
=> !(other is null) && Color().Equals(other.Color());
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public override bool Equals(object? other)
|
||||||
|
#else
|
||||||
|
public override bool Equals(object other)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (other is null) return false;
|
||||||
|
else if (other is IndexedColor<TColor> otherIndexed) return Equals(otherIndexed);
|
||||||
|
else if (other is TColor otherColor) return Color().Equals(otherColor);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
|
public override string ToString() => $"#0x{Index:X}: {Color()}";
|
||||||
|
}
|
||||||
|
}
|
||||||
141
Nerd_STF/Graphics/Formats/R8G8B8A8.cs
Normal file
141
Nerd_STF/Graphics/Formats/R8G8B8A8.cs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
using Nerd_STF.Mathematics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Nerd_STF.Graphics.Formats
|
||||||
|
{
|
||||||
|
public class R8G8B8A8 : IColorFormat<R8G8B8A8, ColorRGB>
|
||||||
|
{
|
||||||
|
public static int ChannelCount => 4;
|
||||||
|
public static int BitLength => 32;
|
||||||
|
public static Dictionary<ColorChannel, int> BitsPerChannel { get; } = new Dictionary<ColorChannel, int>()
|
||||||
|
{
|
||||||
|
{ ColorChannel.Red, 8 },
|
||||||
|
{ ColorChannel.Green, 8 },
|
||||||
|
{ ColorChannel.Blue, 8 },
|
||||||
|
{ ColorChannel.Alpha, 8 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int IColorFormat.ChannelCount => ChannelCount;
|
||||||
|
int IColorFormat.BitLength => BitLength;
|
||||||
|
Dictionary<ColorChannel, int> IColorFormat.BitsPerChannel => BitsPerChannel;
|
||||||
|
|
||||||
|
public byte R
|
||||||
|
{
|
||||||
|
get => r;
|
||||||
|
set => r = value;
|
||||||
|
}
|
||||||
|
public byte G
|
||||||
|
{
|
||||||
|
get => g;
|
||||||
|
set => g = value;
|
||||||
|
}
|
||||||
|
public byte B
|
||||||
|
{
|
||||||
|
get => b;
|
||||||
|
set => b = value;
|
||||||
|
}
|
||||||
|
public byte A
|
||||||
|
{
|
||||||
|
get => a;
|
||||||
|
set => a = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte r, g, b, a;
|
||||||
|
|
||||||
|
public R8G8B8A8(ColorRGB color)
|
||||||
|
{
|
||||||
|
r = (byte)MathE.Clamp(color.r * 255, 0, 255);
|
||||||
|
g = (byte)MathE.Clamp(color.g * 255, 0, 255);
|
||||||
|
b = (byte)MathE.Clamp(color.b * 255, 0, 255);
|
||||||
|
a = (byte)MathE.Clamp(color.a * 255, 0, 255);
|
||||||
|
}
|
||||||
|
public R8G8B8A8(byte r, byte g, byte b, byte a)
|
||||||
|
{
|
||||||
|
this.r = r;
|
||||||
|
this.g = g;
|
||||||
|
this.b = b;
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
public static R8G8B8A8 FromColor(IColor color) => new R8G8B8A8(color.AsRgb());
|
||||||
|
public static R8G8B8A8 FromColor(ColorRGB color) => new R8G8B8A8(color);
|
||||||
|
|
||||||
|
public static byte[] GetBitfield(ColorChannel channel)
|
||||||
|
{
|
||||||
|
byte[] buf = new byte[4];
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case ColorChannel.Red: buf[0] = 0xFF; break;
|
||||||
|
case ColorChannel.Green: buf[1] = 0xFF; break;
|
||||||
|
case ColorChannel.Blue: buf[2] = 0xFF; break;
|
||||||
|
case ColorChannel.Alpha: buf[3] = 0xFF; break;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
byte[] IColorFormat.GetBitfield(ColorChannel channel) => GetBitfield(channel);
|
||||||
|
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public bool Equals(R8G8B8A8? other) =>
|
||||||
|
#else
|
||||||
|
public bool Equals(R8G8B8A8 other) =>
|
||||||
|
#endif
|
||||||
|
!(other is null) && r == other.r && g == other.g && b == other.b && a == other.a;
|
||||||
|
#if CS8_OR_GREATER
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
#else
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (obj is null) return false;
|
||||||
|
else if (obj is R8G8B8A8 formatObj) return Equals(formatObj);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
|
public override string ToString() => $"{{ r={r}, g={g}, b={b}, a={a} }}";
|
||||||
|
|
||||||
|
public byte[] GetBits() => new byte[] { r, g, b, a };
|
||||||
|
|
||||||
|
public ColorRGB GetColor()
|
||||||
|
{
|
||||||
|
const double inv255 = 0.00392156862745; // Constant for 1/255
|
||||||
|
return new ColorRGB(r * inv255,
|
||||||
|
g * inv255,
|
||||||
|
b * inv255,
|
||||||
|
a * inv255);
|
||||||
|
}
|
||||||
|
IColor IColorFormat.GetColor() => GetColor();
|
||||||
|
public void SetColor(ColorRGB color)
|
||||||
|
{
|
||||||
|
r = (byte)MathE.Clamp(color.r * 255, 0, 255);
|
||||||
|
g = (byte)MathE.Clamp(color.g * 255, 0, 255);
|
||||||
|
b = (byte)MathE.Clamp(color.b * 255, 0, 255);
|
||||||
|
a = (byte)MathE.Clamp(color.a * 255, 0, 255);
|
||||||
|
}
|
||||||
|
public void SetColor(byte r, byte g, byte b, byte a)
|
||||||
|
{
|
||||||
|
this.r = (byte)MathE.Clamp(r * 255, 0, 255);
|
||||||
|
this.g = (byte)MathE.Clamp(g * 255, 0, 255);
|
||||||
|
this.b = (byte)MathE.Clamp(b * 255, 0, 255);
|
||||||
|
this.a = (byte)MathE.Clamp(a * 255, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R8G8B8A8 operator +(R8G8B8A8 a, R8G8B8A8 b)
|
||||||
|
{
|
||||||
|
return new R8G8B8A8((byte)MathE.Clamp(a.r + b.r, 0, 255),
|
||||||
|
(byte)MathE.Clamp(a.g + b.g, 0, 255),
|
||||||
|
(byte)MathE.Clamp(a.b + b.b, 0, 255),
|
||||||
|
(byte)MathE.Clamp(a.a + b.a, 0, 255));
|
||||||
|
}
|
||||||
|
public static R8G8B8A8 operator *(R8G8B8A8 a, R8G8B8A8 b)
|
||||||
|
{
|
||||||
|
const double inv255 = 0.00392156862745; // Constant for 1/255
|
||||||
|
return new R8G8B8A8((byte)MathE.Clamp(a.r * b.r * inv255, 0, 255),
|
||||||
|
(byte)MathE.Clamp(a.g * b.g * inv255, 0, 255),
|
||||||
|
(byte)MathE.Clamp(a.b * b.b * inv255, 0, 255),
|
||||||
|
(byte)MathE.Clamp(a.a * b.a * inv255, 0, 255));
|
||||||
|
}
|
||||||
|
public static bool operator ==(R8G8B8A8 a, R8G8B8A8 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(R8G8B8A8 a, R8G8B8A8 b) => !a.Equals(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ namespace Nerd_STF.Graphics
|
|||||||
public interface IColorOperators<TSelf> where TSelf : IColorOperators<TSelf>
|
public interface IColorOperators<TSelf> where TSelf : IColorOperators<TSelf>
|
||||||
{
|
{
|
||||||
static abstract TSelf operator +(TSelf a, TSelf b);
|
static abstract TSelf operator +(TSelf a, TSelf b);
|
||||||
|
static abstract TSelf operator *(TSelf a, TSelf b);
|
||||||
static abstract TSelf operator *(TSelf a, double b);
|
static abstract TSelf operator *(TSelf a, double b);
|
||||||
static abstract bool operator ==(TSelf a, IColor b);
|
static abstract bool operator ==(TSelf a, IColor b);
|
||||||
static abstract bool operator !=(TSelf a, IColor b);
|
static abstract bool operator !=(TSelf a, IColor b);
|
||||||
|
|||||||
@ -111,7 +111,7 @@ namespace Nerd_STF
|
|||||||
public static implicit operator ListTuple<T>((T, T, T, T, T) tuple) => new ListTuple<T>(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5);
|
public static implicit operator ListTuple<T>((T, T, T, T, T) tuple) => new ListTuple<T>(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5);
|
||||||
public static implicit operator ListTuple<T>((T, T, T, T, T, T) tuple) => new ListTuple<T>(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6);
|
public static implicit operator ListTuple<T>((T, T, T, T, T, T) tuple) => new ListTuple<T>(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6);
|
||||||
public static implicit operator ListTuple<T>((T, T, T, T, T, T, T) tuple) => new ListTuple<T>(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7);
|
public static implicit operator ListTuple<T>((T, T, T, T, T, T, T) tuple) => new ListTuple<T>(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7);
|
||||||
public static implicit operator ListTuple<T>(T[] array) => new ListTuple<T>(array)
|
public static implicit operator ListTuple<T>(T[] array) => new ListTuple<T>(array);
|
||||||
|
|
||||||
public struct Enumerator : IEnumerator<T>
|
public struct Enumerator : IEnumerator<T>
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user