From 3436054112a3c71b840f0257dfa4424aa5b4d131 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 28 Sep 2026 19:45:04 +0200 Subject: [PATCH] Draw the color picker from gradient textures The picker drew its square and bars one pixel at a time, about 10,000 fills a frame. It now stretches four gradient strips, made once, over them instead. Co-Authored-By: Claude Opus 5.5 --- .../ui/components/inputs/ColorPicker.java | 63 ++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/saturnclient/ui/components/inputs/ColorPicker.java b/src/main/java/org/saturnclient/ui/components/inputs/ColorPicker.java index 8c7f701..84e4fa0 100644 --- a/src/main/java/org/saturnclient/ui/components/inputs/ColorPicker.java +++ b/src/main/java/org/saturnclient/ui/components/inputs/ColorPicker.java @@ -1,7 +1,10 @@ package org.saturnclient.ui.components.inputs; import java.awt.Color; +import java.awt.image.BufferedImage; +import org.saturnclient.common.provider.Providers; +import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.config.Theme; import org.saturnclient.config.property.ColorProperty; import org.saturnclient.ui.Element; @@ -27,6 +30,18 @@ public class ColorPicker extends Element { private static final int SQUARE_Y = OPACITY_Y + SLIDER_HEIGHT + GAP; private static final int HUE_Y = SQUARE_Y + SIZE + GAP; + // Gradient strips, made once and stretched over each part, so a frame is a + // few draws instead of one per pixel. Tinting the white ones colors them. + private static final int STRIP = 256; + /** White fading out to the right: saturation, over the hue */ + private static final IdentifierRef SATURATION = IdentifierRef.ofSaturn("textures/gui/color_picker/saturation"); + /** Black fading in downwards: brightness, over the saturation */ + private static final IdentifierRef BRIGHTNESS = IdentifierRef.ofSaturn("textures/gui/color_picker/brightness"); + /** White fading in to the right, tinted with the color */ + private static final IdentifierRef OPACITY = IdentifierRef.ofSaturn("textures/gui/color_picker/opacity"); + private static final IdentifierRef HUE = IdentifierRef.ofSaturn("textures/gui/color_picker/hue"); + private static boolean stripsRegistered = false; + private final ColorProperty prop; private float hue; @@ -46,6 +61,8 @@ public class ColorPicker extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { + registerStrips(); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, Theme.withAlpha(0.97f, Theme.BACKGROUND.value), Theme.withAlpha(0.14f, Theme.FOREGROUND.value)); @@ -55,22 +72,16 @@ public class ColorPicker extends Element { } private void renderOpacity(RenderScope renderScope) { - int rgb = prop.value & 0xFFFFFF; - for (int x = 0; x < SIZE; x++) { - int alpha = (int) (x / (float) SIZE * 255) & 0xFF; - renderScope.fill(PADDING + x, OPACITY_Y, PADDING + x + 1, OPACITY_Y + SLIDER_HEIGHT, (alpha << 24) | rgb); - } + renderScope.drawTexture(OPACITY, PADDING, OPACITY_Y, 0, 0, SIZE, SLIDER_HEIGHT, + 0xFF000000 | prop.value); drawMarker(renderScope, PADDING + (int) (opacity * SIZE), OPACITY_Y); } private void renderSquare(RenderScope renderScope) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - int color = Color.HSBtoRGB(hue, x / (float) SIZE, 1f - y / (float) SIZE); - renderScope.fill(PADDING + x, SQUARE_Y + y, PADDING + x + 1, SQUARE_Y + y + 1, 0xFF000000 | color); - } - } + renderScope.fill(PADDING, SQUARE_Y, PADDING + SIZE, SQUARE_Y + SIZE, 0xFF000000 | Color.HSBtoRGB(hue, 1f, 1f)); + renderScope.drawTexture(SATURATION, PADDING, SQUARE_Y, 0, 0, SIZE, SIZE, 0xFFFFFFFF); + renderScope.drawTexture(BRIGHTNESS, PADDING, SQUARE_Y, 0, 0, SIZE, SIZE, 0xFFFFFFFF); int selX = PADDING + (int) (saturation * SIZE) - 4; int selY = SQUARE_Y + (int) ((1f - brightness) * SIZE) - 4; @@ -79,14 +90,36 @@ public class ColorPicker extends Element { } private void renderHue(RenderScope renderScope) { - for (int x = 0; x < SIZE; x++) { - int color = Color.HSBtoRGB(x / (float) SIZE, 1f, 1f); - renderScope.fill(PADDING + x, HUE_Y, PADDING + x + 1, HUE_Y + SLIDER_HEIGHT, 0xFF000000 | color); - } + renderScope.drawTexture(HUE, PADDING, HUE_Y, 0, 0, SIZE, SLIDER_HEIGHT, 0xFFFFFFFF); drawMarker(renderScope, PADDING + (int) (hue * SIZE), HUE_Y); } + private static void registerStrips() { + if (stripsRegistered) { + return; + } + + BufferedImage saturation = new BufferedImage(STRIP, 1, BufferedImage.TYPE_INT_ARGB); + BufferedImage brightness = new BufferedImage(1, STRIP, BufferedImage.TYPE_INT_ARGB); + BufferedImage opacity = new BufferedImage(STRIP, 1, BufferedImage.TYPE_INT_ARGB); + BufferedImage hue = new BufferedImage(STRIP, 1, BufferedImage.TYPE_INT_ARGB); + + for (int i = 0; i < STRIP; i++) { + int alpha = i * 255 / (STRIP - 1); + saturation.setRGB(i, 0, ((255 - alpha) << 24) | 0xFFFFFF); + brightness.setRGB(0, i, alpha << 24); + opacity.setRGB(i, 0, (alpha << 24) | 0xFFFFFF); + hue.setRGB(i, 0, 0xFF000000 | Color.HSBtoRGB(i / (float) STRIP, 1f, 1f)); + } + + Providers.saturn.registerBufferedImageTexture(SATURATION, saturation); + Providers.saturn.registerBufferedImageTexture(BRIGHTNESS, brightness); + Providers.saturn.registerBufferedImageTexture(OPACITY, opacity); + Providers.saturn.registerBufferedImageTexture(HUE, hue); + stripsRegistered = true; + } + private static void drawMarker(RenderScope renderScope, int x, int sliderY) { renderScope.fill(x - 2, sliderY - 2, x + 2, sliderY + SLIDER_HEIGHT + 2, 0xFFFFFFFF); renderScope.fill(x - 1, sliderY - 1, x + 1, sliderY + SLIDER_HEIGHT + 1, 0xFF000000);