From 21386d370388952563cb67a2e7094470d264fe46 Mon Sep 17 00:00:00 2001 From: Speiger Date: Sun, 9 Jun 2024 22:11:57 +0200 Subject: [PATCH] Implemented Color Formats --- .../src/coreengine/math/misc/ColorSpaces.java | 147 ++++++++++++++++++ .../src/coreengine/math/misc/ColorUtils.java | 14 +- .../coreengine/math/misc/EasingFunctions.java | 2 +- .../src/coreengine/math/misc/IEasing.java | 16 ++ .../textures/custom/DynamicTexture.java | 6 +- .../textures/custom/IDynamicTexture.java | 7 +- 6 files changed, 172 insertions(+), 20 deletions(-) create mode 100644 src/main/java/speiger/src/coreengine/math/misc/ColorSpaces.java diff --git a/src/main/java/speiger/src/coreengine/math/misc/ColorSpaces.java b/src/main/java/speiger/src/coreengine/math/misc/ColorSpaces.java new file mode 100644 index 0000000..0a96621 --- /dev/null +++ b/src/main/java/speiger/src/coreengine/math/misc/ColorSpaces.java @@ -0,0 +1,147 @@ +package speiger.src.coreengine.math.misc; + +import speiger.src.coreengine.math.MathUtils; + +public enum ColorSpaces { + ARGB { + @Override + public int color(int r, int g, int b, int a) { return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF); } + @Override + public int r(int color) { return color >> 16 & 0xFF; } + @Override + public int g(int color) { return color >> 8 & 0xFF; } + @Override + public int b(int color) { return color & 0xFF; } + @Override + public int a(int color) { return color >> 24; } + @Override + public int setR(int color, int r) { return color & ~ColorUtils.R | ((r & 0xFF) << 16); } + @Override + public int setG(int color, int g) { return color & ~ColorUtils.G | ((g & 0xFF) << 8); } + @Override + public int setB(int color, int b) { return color & ~ColorUtils.B | (b & 0xFF); } + @Override + public int setA(int color, int a) { return color & ~ColorUtils.A | ((a & 0xFF) << 24); } + @Override + public int fromARGB(int color) { return color; } + @Override + public int toARGB(int color) { return color; } + }, + ABGR { + @Override + public int color(int r, int g, int b, int a) { return (a & 0xFF) << 24 | (b & 0xFF) << 16 | (g & 0xFF) << 8 | (r & 0xFF); } + @Override + public int r(int color) { return color & 0xFF; } + @Override + public int g(int color) { return color >> 8 & 0xFF; } + @Override + public int b(int color) { return color >> 16 & 0xFF; } + @Override + public int a(int color) { return color >> 24 & 0xFF; } + @Override + public int setR(int color, int r) { return color & ~ColorUtils.B | (r & 0xFF); } + @Override + public int setG(int color, int g) { return color & ~ColorUtils.G | ((g & 0xFF) << 8); } + @Override + public int setB(int color, int b) { return color & ~ColorUtils.R | ((b & 0xFF) << 16); } + @Override + public int setA(int color, int a) { return color & ~ColorUtils.A | ((a & 0xFF) << 24); } + @Override + public int fromARGB(int color) { return color & 0xFF00FF00 | (color & 0xFF0000) >> 16 | (color & 0xFF) << 16; } + @Override + public int toARGB(int color) { return color & 0xFF00FF00 | (color & 0xFF0000) >> 16 | (color & 0xFF) << 16; } + }; + + public int color(float r, float g, float b) { return color((int)(r * 255F + 0.5F), (int)(g * 255F + 0.5F), (int)(b * 255F + 0.5F)); } + public int color(float r, float g, float b, float a) { return color((int)(r * 255F + 0.5F), (int)(g * 255F + 0.5F), (int)(b * 255F + 0.5F), (int)(a * 255F + 0.5F));} + public int color(int r, int g, int b) { return color(r, g, b, 255); } + public abstract int color(int r, int g, int b, int a); + public abstract int r(int color); + public abstract int g(int color); + public abstract int b(int color); + public abstract int a(int color); + public float rf(int color) { return r(color) / 255F; } + public float gf(int color) { return g(color) / 255F; } + public float bf(int color) { return b(color) / 255F; } + public float af(int color) { return a(color) / 255F; } + public abstract int setR(int color, int r); + public abstract int setG(int color, int g); + public abstract int setB(int color, int b); + public abstract int setA(int color, int a); + public int setRF(int color, float r) { return setR(color, (int)(r * 255F + 0.5F)); } + public int setGF(int color, float g) { return setG(color, (int)(g * 255F + 0.5F)); } + public int setBF(int color, float b) { return setB(color, (int)(b * 255F + 0.5F)); } + public int setAF(int color, float a) { return setA(color, (int)(a * 255F + 0.5F)); } + public abstract int toARGB(int color); + public abstract int fromARGB(int color); + + public int darker(int color) { return darker(color, 0.7F); } + public int darker(int color, float factor) { + int r = Math.max(0, (int)(r(color) * factor)); + int g = Math.max(0, (int)(g(color) * factor)); + int b = Math.max(0, (int)(b(color) * factor)); + return (a(color) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF); + } + + public int brighter(int color) { return brighter(color, 0.7F); } + public int brighter(int color, float factor) { + int r = r(color); + int g = g(color); + int b = b(color); + int i = (int)(1.0 / (1.0 - factor)); + if(r == 0 && g == 0 && b == 0) { return color(i & 0xFF, i & 0xFF, i & 0xFF, a(color)); } + if(r > 0 && r < i) r = i; + if(g > 0 && g < i) g = i; + if(b > 0 && b < i) b = i; + return color(Math.min(255, (int)(r / factor)), Math.min(255, (int)(g / factor)), Math.min(255, (int)(b / factor)), a(color) << 24); + } + + public int fromHue(float hue, float saturation, float brightness) { + if(saturation == 0) { + int result = (int)(brightness * 255F + 0.5F); + return color(result, result, result); + } + float h = (hue - MathUtils.floor(hue)) * 6F; + float f = h - MathUtils.floor(h); + float p = brightness * (1F - saturation); + float q = brightness * (1F - saturation * f); + float t = brightness * (1F - (saturation * (1F - f))); + switch((int)h) { + case 0: return color(brightness, t, p); + case 1: return color(q, brightness, p); + case 2: return color(p, brightness, t); + case 3: return color(p, q, brightness); + case 4: return color(t, p, brightness); + case 5: return color(brightness, p, q); + default: return color(0, 0, 0); + } + } + + public float[] toHue(int color) { + int r = r(color); + int g = g(color); + int b = b(color); + int cmax = (r > g) ? r : g; + if(b > cmax) cmax = b; + int cmin = (r < g) ? r : g; + if(b < cmin) cmin = b; + float length = cmax - cmin; + + float[] result = new float[3]; + result[1] = cmax == 0 ? 0F : length / cmax; + result[2] = cmax * ColorUtils.DEVIDER; + float hue = 0F; + if(result[1] != 0F) { + float redc = (cmax - r) / length; + float greenc = (cmax - g) / length; + float bluec = (cmax - b) / length; + if(r == cmax) hue = bluec - greenc; + else if(g == cmax) hue = 2F + redc - bluec; + else hue = 4F + greenc - redc; + hue /= 6F; + if(hue < 0) hue += 1F; + } + result[0] = hue; + return result; + } +} diff --git a/src/main/java/speiger/src/coreengine/math/misc/ColorUtils.java b/src/main/java/speiger/src/coreengine/math/misc/ColorUtils.java index f9eeefa..c2932c7 100644 --- a/src/main/java/speiger/src/coreengine/math/misc/ColorUtils.java +++ b/src/main/java/speiger/src/coreengine/math/misc/ColorUtils.java @@ -49,7 +49,7 @@ public class ColorUtils { public static void write(int color, boolean alpha, ByteBuffer buffer) { buffer.put((byte)((color >> 16) & 0xFF)).put((byte)((color >> 8) & 0xFF)).put((byte)(color & 0xFF)); - if(alpha) { buffer.put((byte)((color >> 24) & 0xFF)); } + if(alpha) buffer.put((byte)((color >> 24) & 0xFF)); } public static void write(int index, int color, boolean alpha, ByteBuffer buffer) { @@ -57,16 +57,6 @@ public class ColorUtils { if(alpha) buffer.put(index + 3, (byte)((color >> 24) & 0xFF)); } - public static void writeFloat(int color, boolean alpha, ByteBuffer buffer) { - buffer.putFloat(((color >> 16) & 0xFF) * DEVIDER).putFloat(((color >> 8) & 0xFF) * DEVIDER).putFloat((color & 0xFF) * DEVIDER); - if(alpha) buffer.putFloat(((color >> 24) & 0xFF) * DEVIDER); - } - - public static void writeFloat(int index, int color, boolean alpha, ByteBuffer buffer) { - buffer.putFloat(index, ((color >> 16) & 0xFF) * DEVIDER).putFloat(index + 1, ((color >> 8) & 0xFF) * DEVIDER).putFloat(index + 2, (color & 0xFF) * DEVIDER); - if(alpha) buffer.putFloat(index + 3, ((color >> 24) & 0xFF) * DEVIDER); - } - public static void write(int color, boolean alpha, FloatBuffer buffer) { buffer.put(((color >> 16) & 0xFF) * DEVIDER).put(((color >> 8) & 0xFF) * DEVIDER).put((color & 0xFF) * DEVIDER); if(alpha) buffer.put(((color >> 24) & 0xFF) * DEVIDER); @@ -86,8 +76,6 @@ public class ColorUtils { public static int read(ByteBuffer buffer, boolean alpha) { return alpha ? rgb(buffer.get(), buffer.get(), buffer.get()) : rgb(buffer.get(), buffer.get(), buffer.get(), buffer.get()); } public static int read(ByteBuffer buffer, int index, boolean alpha) { return alpha ? rgb(buffer.get(index), buffer.get(index + 1), buffer.get(index + 2)) : rgb(buffer.get(index), buffer.get(index + 1), buffer.get(index + 2), buffer.get(index + 3)); } - public static int readFloat(ByteBuffer buffer, boolean alpha) { return alpha ? rgb(buffer.getFloat(), buffer.getFloat(), buffer.getFloat()) : rgb(buffer.getFloat(), buffer.getFloat(), buffer.getFloat(), buffer.getFloat()); } - public static int readFloat(ByteBuffer buffer, int index, boolean alpha) { return alpha ? rgb(buffer.getFloat(index), buffer.getFloat(index + 1), buffer.getFloat(index + 2)) : rgb(buffer.getFloat(index), buffer.getFloat(index + 1), buffer.getFloat(index + 2), buffer.getFloat(index + 3)); } public static int read(FloatBuffer buffer, boolean alpha) { return alpha ? rgb(buffer.get(), buffer.get(), buffer.get()) : rgb(buffer.get(), buffer.get(), buffer.get(), buffer.get()); } public static int read(FloatBuffer buffer, int index, boolean alpha) { return alpha ? rgb(buffer.get(index), buffer.get(index + 1), buffer.get(index + 2)) : rgb(buffer.get(index), buffer.get(index + 1), buffer.get(index + 2), buffer.get(index + 3)); } public static boolean needsDarkColor(int rgba) { return getBrightness(rgba) >= 130; } diff --git a/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java b/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java index 3ac5d8b..67f2e17 100644 --- a/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java +++ b/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java @@ -51,7 +51,7 @@ public class EasingFunctions { } public static double easeInOutExpo(double progress) { - return progress <= 0.5D ? Math.pow(2D, (20D * progress) - 10D) * 0.5D : (2D - Math.pow(2D, (-20D * progress) + 10D)) * 0.5D; + return progress <= 0.5D ? Math.pow(2D, (20D * progress) - 10D) * 0.5D : (2D - Math.pow(2D, (-20D * progress) + 10D)) * 0.5D; } diff --git a/src/main/java/speiger/src/coreengine/math/misc/IEasing.java b/src/main/java/speiger/src/coreengine/math/misc/IEasing.java index fa480d4..d265a6b 100644 --- a/src/main/java/speiger/src/coreengine/math/misc/IEasing.java +++ b/src/main/java/speiger/src/coreengine/math/misc/IEasing.java @@ -3,6 +3,22 @@ package speiger.src.coreengine.math.misc; import speiger.src.coreengine.math.MathUtils; public interface IEasing { + public static final IEasing SINE_IN = EasingFunctions::easeInSine; + public static final IEasing SINE_OUT = EasingFunctions::easeOutSine; + public static final IEasing SINE_IN_OUT = EasingFunctions::easeInOutSine; + + public static final IEasing SQRT_IN = EasingFunctions::easeInSqrt; + public static final IEasing SQRT_OUT = EasingFunctions::easeOutSqrt; + public static final IEasing SQRT_IN_OUT = EasingFunctions::easeInOutSqrt; + + public static final IEasing QUAD_IN = EasingFunctions::easeInQuad; + public static final IEasing QUAD_OUT = EasingFunctions::easeOutQuad; + public static final IEasing QUAD_IN_OUT = EasingFunctions::easeInOutQuad; + + public static final IEasing EXPO_IN = EasingFunctions::easeInExpo; + public static final IEasing EXPO_OUT = EasingFunctions::easeOutExpo; + public static final IEasing EXPO_IN_OUT = EasingFunctions::easeInOutExpo; + public double ease(double progress); public default double ease(double progress, double max) { diff --git a/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java b/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java index 9f059fc..8c0efd2 100644 --- a/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java +++ b/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java @@ -89,7 +89,7 @@ public class DynamicTexture extends BaseTexture implements IDynamicTexture { protected void ensureValid(int x, int y) { if(x < 0 || y < 0) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"]"); - if(x >= width || y >= height) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"], width=["+width+"], height=["+height+"]"); + if(x >= width || y >= height) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"], width=["+width+"], height=["+height+"]"); } @Override @@ -116,7 +116,7 @@ public class DynamicTexture extends BaseTexture implements IDynamicTexture { @Override public void set(int index, int data) { - MemoryUtil.memPutInt(index * 4L, Integer.rotateLeft(data, 8)); + MemoryUtil.memPutInt(index * 4L, data); dirty(index); } @@ -147,7 +147,7 @@ public class DynamicTexture extends BaseTexture implements IDynamicTexture { @Override public int get(int index) { ensureValid(index); - return Integer.rotateRight(MemoryUtil.memGetInt(index * 4L), 8); + return MemoryUtil.memGetInt(index * 4L); } @Override diff --git a/src/main/java/speiger/src/coreengine/rendering/textures/custom/IDynamicTexture.java b/src/main/java/speiger/src/coreengine/rendering/textures/custom/IDynamicTexture.java index 68f689a..b63bc9e 100644 --- a/src/main/java/speiger/src/coreengine/rendering/textures/custom/IDynamicTexture.java +++ b/src/main/java/speiger/src/coreengine/rendering/textures/custom/IDynamicTexture.java @@ -1,5 +1,6 @@ package speiger.src.coreengine.rendering.textures.custom; +import speiger.src.coreengine.math.misc.ColorSpaces; import speiger.src.coreengine.rendering.textures.base.ITexture; public interface IDynamicTexture extends ITexture { @@ -12,8 +13,8 @@ public interface IDynamicTexture extends ITexture { public void set(int index, int data); public default void set(int x, int y, int data) { set((y * width()) + x, data); } - public default void set(int index, int red, int green, int blue, int alpha) { set(index, ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF)); } - public default void set(int x, int y, int red, int green, int blue, int alpha) { set((y * width()) + x, ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF)); } + public default void set(int index, int red, int green, int blue, int alpha) { set(index, ColorSpaces.ABGR.color(red, green, blue, alpha)); } + public default void set(int x, int y, int red, int green, int blue, int alpha) { set((y * width()) + x, ColorSpaces.ABGR.color(red, green, blue, alpha)); } public void setR(int index, int red); public default void setR(int x, int y, int red) { setR((y * width()) + x, red); } @@ -28,7 +29,7 @@ public interface IDynamicTexture extends ITexture { public default void setA(int x, int y, int alpha) { setA((y * width()) + x, alpha); } public void fill(int x, int y, int width, int height, int data); - public default void fill(int x, int y, int width, int height, int red, int green, int blue, int alpha) { fill(x, y, width, height, ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF)); } + public default void fill(int x, int y, int width, int height, int red, int green, int blue, int alpha) { fill(x, y, width, height, ColorSpaces.ABGR.color(red, green, blue, alpha)); } public int get(int index); public default int get(int x, int y) { return get((y * width()) + x); }