3

How to specify a color with hue, saturation and brightness in libGDX instead of r,g,b,a values. I noticed that the Color constructor only accepts rgba, at least autocompletion offered only rgba. Is this even possible? I wanted to create a gradient ranging from hue=0 to hue=255.

potato
  • 4,479
  • 7
  • 42
  • 99

2 Answers2

6

I don't think this is built into Libgdx, unless it's been added since I last checked. I made a utility method for it. This treats hue, saturation, and value as values from 0 to 1. (so pre-divide by 255 if that's the scale you're using). For hue, it circles round from red to yellow to green to cyan to blue to magenta and back to red. Or maybe in the opposite direction, forgot. I adapted the algorithm from Android's color class.

public static Color setColor (Color target, float hue, float saturation, float value){
        saturation = MathUtils.clamp(saturation, 0.0f, 1.0f);
        hue %= 1f;
        if (hue < 0f) {
            hue++;
        }
        value = MathUtils.clamp(value, 0.0f, 1.0f);

        float red = 0.0f;
        float green = 0.0f;
        float blue = 0.0f;

        final float hf = (hue - (int) hue) * 6.0f;
        final int ihf = (int) hf;
        final float f = hf - ihf;
        final float pv = value * (1.0f - saturation);
        final float qv = value * (1.0f - saturation * f);
        final float tv = value * (1.0f - saturation * (1.0f - f));

        switch (ihf) {
            case 0:         // Red is the dominant color
                red = value;
                green = tv;
                blue = pv;
                break;
            case 1:         // Green is the dominant color
                red = qv;
                green = value;
                blue = pv;
                break;
            case 2:
                red = pv;
                green = value;
                blue = tv;
                break;
            case 3:         // Blue is the dominant color
                red = pv;
                green = qv;
                blue = value;
                break;
            case 4:
                red = tv;
                green = pv;
                blue = value;
                break;
            case 5:         // Red is the dominant color
                red = value;
                green = pv;
                blue = qv;
                break;
        }

        return target.set(red, green, blue, target.a);
    }
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
0

This is the version I have been using. All values are based on a 0...1 range, so you need to divide the hue by 255f. It is a port of this vec3 hsv2rgb(vec3 c) method by sam hocevar for glsl.

public static Color fromHSV(final float hue, final float saturation, final float value) {
    //vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    final float
        Kx=1f,
        Ky=2f/3f,
        Kz=1f/3f,
        Kw=3f;
    //vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    final float
        px=Math.abs(fract(hue+Kx)*6f-Kw),
        py=Math.abs(fract(hue+Ky)*6f-Kw),
        pz=Math.abs(fract(hue+Kz)*6f-Kw);
    //return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    return new Color(
        value*mix(Kx,clamp(px-Kx,0f,1f),saturation),
        value*mix(Kx,clamp(py-Kx,0f,1f),saturation),
        value*mix(Kx,clamp(pz-Kz,0f,1f),saturation),
        1f
    );
}
public static float fract(final float x) {
    return x-(int)x;
}
public static float mix(final float x, final float y, final float a) {
    return x*(1f-a)+y*a;
}
public static float clamp(final float x, final float minVal, final float maxVal) {
    return Math.min(Math.max(x,minVal),maxVal);
}

You can also reuse the Color using Color.set(float r, float g, float b, float a).

public static Color fromHSV(final Color target, final float hue, final float saturation, final float value) {
    //vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    final float
        Kx=1f,
        Ky=2f/3f,
        Kz=1f/3f,
        Kw=3f;
    //vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    final float
        px=Math.abs(fract(hue+Kx)*6f-Kw),
        py=Math.abs(fract(hue+Ky)*6f-Kw),
        pz=Math.abs(fract(hue+Kz)*6f-Kw);
    //return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    return target.set(
        value*mix(Kx,clamp(px-Kx,0f,1f),saturation),
        value*mix(Kx,clamp(py-Kx,0f,1f),saturation),
        value*mix(Kx,clamp(pz-Kz,0f,1f),saturation),
        target.a
    );
}
public static float fract(final float x) {
    return x-(int)x;
}
public static float mix(final float x, final float y, final float a) {
    return x*(1f-a)+y*a;
}
public static float clamp(final float x, final float minVal, final float maxVal) {
    return Math.min(Math.max(x,minVal),maxVal);
}
Quadslab
  • 294
  • 3
  • 9