Thread: HSL Color Picker(for widgets/interfaces)

Results 1 to 10 of 10
  1. #1 HSL Color Picker(for widgets/interfaces) 
    nice


    Join Date
    Jul 2014
    Posts
    740
    Thanks given
    382
    Thanks received
    562
    Rep Power
    4239
    Needed this for my editor but figured I'd implement it in game too for widgets/interfaces, surprisingly enough it only took about 5mins to do so(obviously cause i already had an rgb color picker so i just needed to change a few things)
    Anyway the Runescape client uses 16 bit HSL(Hue, Saturation, Lightness) where 6 bits are used for hue, 3 for saturation and 7 for lightness. NOTE: HSL is not the same as HSB(for some reason quite a few people think they're the same thing)

    For anyone that still doesn't understand what this picker does: it's a color picker for rs colors (with an 24 bit RGB color picker for example u would often lose some info/detail when converting to runescapes 16 bit HSL)

    The code to generate the HSL -> RGB table is already in the client but i'll add it just in case:
    Code:
        public static void generatePalette(double brightness) {
            int index = 0;
            for (int y = 0; y < 512; y++) {
                double hue = ((double) (y / 8) / 64.0) + 0.0078125;
                double lightness = ((double) (y & 0x7) / 8.0) + 0.0625;
                for (int x = 0; x < 128; x++) {
                    double intensity = (double) x / 128.0;
                    double red = intensity;
                    double green = intensity;
                    double blue = intensity;
    
                    if (lightness != 0.0) {
                        double a;
    
                        if (intensity < 0.5) {
                            a = intensity * (1.0 + lightness);
                        } else {
                            a = (intensity + lightness) - (intensity * lightness);
                        }
    
                        double b = (2.0 * intensity) - a;
    
                        double fRed = hue + (1.0 / 3.0);
                        double fBlue = hue - (1.0 / 3.0);
    
                        if (fRed > 1.0) fRed--;
                        if (fBlue < 0.0) fBlue++;
    
                        red = getValue(fRed, a, b);
                        green = getValue(hue, a, b);
                        blue = getValue(fBlue, a, b);
                    }
    
                    table[index++] = generatePalette(((int) (red * 256.0) << 16) | ((int) (green * 256.0) << 8) | (int) (blue * 256.0), brightness);
                }
            }
        }
    Alright, now how do we get the hsl value given the 3 components(h, s, l)?
    This is very simple, remember that 6 bits are used for hue, 3 for saturation and 7 for lightness
    we simply 'extract' those values and add them together:
    Code:
        public static int getHsl(int hue, int saturation, int lightness) {
            return hue << 10 | saturation << 7 | lightness;
        }
    if ur confused by the bitwise OR(|) operator look it up
    it can also be rewritten as:
    Code:
    return (hue << 10) + (saturation << 7) + lightness;
    Code for the picker:
    Code:
    public class WidgetHSLColorPicker {
        private final int width;
        private final int height;
        private final int hueWidth;
        private final int pCircleDiameter;
        private final int hCircleDiameter;
        private int currentHue;
        private int currentSaturation;
        private int currentLightness;
        private int pickedColor;
        private int lastColorX;
        private int lastColorY;
        private int lastHueY;
        private final int pCircleRadius;
        private final int hCircleRadius;
    
        public WidgetHSLColorPicker(int width, int height, int hueWidth, int pickedCircleDiameter, int hueCircleDiameter) {
            this.width = width;
            this.height = height;
            this.hueWidth = hueWidth;
            this.pCircleDiameter = pickedCircleDiameter;
            this.hCircleDiameter = hueCircleDiameter;
            this.pickedColor = -1;
            this.pCircleRadius = pCircleDiameter / 2;
            this.hCircleRadius = hCircleDiameter / 2;
        }
    
        public void render(int x, int y) {
            Raster.drawHSLColorPicker(x, y, width, height, hueWidth, currentHue);
            handleBounds();
            Raster.drawCircle(x + lastColorX - (pCircleDiameter / 2f), y + lastColorY - (pCircleDiameter / 2f), pCircleDiameter, pCircleDiameter, 0xFFFFFF, 255, false);
            Raster.drawCircle(x + width + (hueWidth / 2f) - hCircleRadius, y + lastHueY - (hCircleDiameter / 2f), hCircleDiameter, hCircleDiameter, 0xFFFFFF, 255, false);
        }
    
    
        public void handlePick(int x, int y) {
            if (x <= width) {
                currentSaturation = (int) MathUtils.map(x, 0, width, 0, 7);
                currentLightness = (int) (127 - MathUtils.map(y, 0, height - 1, 0, 127));
                lastColorX = x;
                lastColorY = y;
            } else {
                currentHue = (int) (63 - MathUtils.map(y, 0, height - 1, 0, 63));
                lastHueY = y;
            }
            pickedColor = Palette.getHsl(currentHue, currentSaturation, currentLightness);
        }
    
        private void handleBounds() {
            // color picker(saturation, lightness)
            if (lastColorX >= width - pCircleRadius) {
                lastColorX = width - pCircleRadius - 1;
            }
            if (lastColorX <= pCircleRadius) {
                lastColorX = pCircleRadius + 1;
            }
    
            if (lastColorY >= height - pCircleRadius) {
                lastColorY = height - pCircleRadius - 1;
            }
    
            if (lastColorY <= pCircleRadius) {
                lastColorY = pCircleRadius + 1;
            }
    
            // hue picker
    
            if (lastHueY >= height - hCircleRadius) {
                lastHueY = height - hCircleRadius - 1;
            }
            if (lastHueY <= hCircleRadius) {
                lastHueY = hCircleRadius + 1;
            }
        }
    
        public int getPickedColor() {
            return pickedColor;
        }
    
        public void setPickedColor(int pickedColor) {
            this.pickedColor = pickedColor;
        }
    }
    Code:
        public static void drawHSLColorPicker(int x, int y, int w, int h, int hueWidth, int hue) {
            if (x < clipLeft) {
                w -= clipLeft - x;
                x = clipLeft;
            }
            if (y < clipTop) {
                h -= clipTop - y;
                y = clipTop;
            }
            if (x + w > clipRight)
                w = clipRight - x;
            if (y + h > clipBottom)
                h = clipBottom - y;
    
            createSL(x, y, w, h, hue);
            createHue(x + w, y, hueWidth, h);
            drawStroke(x, y, w + hueWidth, h, 0, 1);
        }
    Code:
        private static void createHue(int x, int y, int hueWidth, int hueHeight) {
            for (int pX = x; pX < x + hueWidth; pX++) {
                for (int pY = y; pY < y + hueHeight; pY++) {
                    int hue = (int) (63 - MathUtils.map(pY, y, y + hueHeight, 0, 63));
                    raster[pX + pY * Raster.width] = Palette.getRgbForHsl(hue, 7, 80); // feel free to add a variable for lightness
                }
            }
        }
    
        private static void createSL(int x, int y, int pickerWidth, int pickerHeight, int hue) {
            for (int pX = x; pX < x + pickerWidth; pX++) {
                for (int pY = y; pY < y + pickerHeight; pY++) {
                    int saturation = (int) MathUtils.map(pX, x, x + pickerWidth, 0, 7);
                    int lightness = (int) (127 - MathUtils.map(pY, y, y + pickerHeight, 0, 127));
                    raster[pX + pY * Raster.width] = Palette.getRgbForHsl(hue, saturation, lightness);
                }
            }
        }
    Code:
        public static void addHSLPicker(int id, int width, int height, int hueWidth, int pickedCircleDiameter, int hueCircleDiameter, String tooltip) {
            RSInterface widget = addInterface(id);
            widget.hslPicker = new WidgetHSLColorPicker(width, height, hueWidth, pickedCircleDiameter, hueCircleDiameter);
            widget.width = width + hueWidth;
            widget.height = height;
            widget.type = TYPE_HSL_PICKER;
            widget.atActionType = 7;
            widget.tooltip = tooltip;
        }
    
        public static final int TYPE_HSL_PICKER = 118;
    
        //smh should use getters but just for the sake of consistency...
        public WidgetHSLColorPicker hslPicker;
    Code:
        public static int getRgbForHsl(int hue, int saturation, int lightness) {
            int hsl = getHsl(hue, saturation, lightness);
            return table[hsl];
        }
    Code:
        public static float map(float value, float iStart, float iStop, float oStart, float oStop) {
            return oStart + (oStop - oStart) * ((value - iStart) / (iStop - iStart));
        }
    Usage example:
    Code:
    addHSLPicker(id, 150, 150, 30, 10, 10, "Some Picker");
    Example:

    Attached image
    Last edited by Suic; 08-17-2021 at 02:43 PM. Reason: forgot example
    Attached image
    Reply With Quote  
     


  2. #2  
    'Slutty McFur'

    Owain's Avatar
    Join Date
    Sep 2014
    Age
    26
    Posts
    2,894
    Thanks given
    2,360
    Thanks received
    2,200
    Rep Power
    5000
    thnx sooick very cool


    Spoiler for wat:
    Attached image
    Attached image

    Attached image


    Reply With Quote  
     

  3. Thankful user:


  4. #3  
    Registered Member
    Join Date
    May 2021
    Posts
    23
    Thanks given
    4
    Thanks received
    2
    Rep Power
    11
    Quality stuff will be useful for many peoples thanks
    Reply With Quote  
     

  5. #4  
    Community Veteran

    Dust R I P's Avatar
    Join Date
    Jan 2008
    Posts
    2,599
    Thanks given
    197
    Thanks received
    221
    Rep Power
    586
    I thought 317 used its own color palette? Or is that only for 3d models?
    Reply With Quote  
     

  6. #5  
    nice


    Join Date
    Jul 2014
    Posts
    740
    Thanks given
    382
    Thanks received
    562
    Rep Power
    4239
    Quote Originally Posted by Dust R I P View Post
    I thought 317 used its own color palette? Or is that only for 3d models?
    317 does use it's own color palette, and this is exactly what this thread is about, it generates the color picker using that palette
    and yes it's only used for models
    Attached image
    Reply With Quote  
     

  7. Thankful user:


  8. #6  
    WVWVWVWVWVWVWVW

    _jordan's Avatar
    Join Date
    Nov 2012
    Posts
    3,046
    Thanks given
    111
    Thanks received
    1,848
    Rep Power
    5000
    Nice job SOOOIUICK
    Attached image
    Attached image
    Reply With Quote  
     

  9. Thankful user:


  10. #7  
    Endeavor

    Mikey`'s Avatar
    Join Date
    Dec 2007
    Posts
    4,434
    Thanks given
    715
    Thanks received
    1,435
    Rep Power
    1202
    Thanks, saved me some time. I wrote something for setting selected x/y to the correct coordinates for a certain color. I had some trouble finding a HSL->RGB conversion but it's in openosrs for anyone who needs that.

    Spoiler for :

    Code:
    public void setCoordinatesToColor(int hue, int saturation, int lightness) {
            for (int x = 0; x < width; x++) {
                int computedSaturation = getSaturation(x);
                if (computedSaturation == saturation) {
                    lastColorX = x;
                    currentSaturation = saturation;
                    break;
                }
            }
    
            for (int y = 0; y < height; y++) {
                int computedLightness = getLightness(y);
                if (computedLightness == lightness) {
                    lastColorY = y;
                    currentLightness = lightness;
                    break;
                }
            }
    
            for (int y = 0; y < height; y++) {
                int computedHue = getHue(y);
                if (computedHue == hue) {
                    lastHueY = y;
                    currentHue = hue;
                    break;
                }
            }
    
            pickedColor = Rasterizer.getHsl(currentHue, currentSaturation, currentLightness);
        }
    
        private int getHue(int y) {
            return (int) (63 - Misc.map(y, 0, height - 1, 0, 63));
        }
    
        private int getLightness(int y) {
            return (int) (127 - Misc.map(y, 0, height - 1, 0, 127));
        }
    
        private int getSaturation(int x) {
            return (int) Misc.map(x, 0, width, 0, 7);
        }
    Reply With Quote  
     

  11. #8  
    nice


    Join Date
    Jul 2014
    Posts
    740
    Thanks given
    382
    Thanks received
    562
    Rep Power
    4239
    Quote Originally Posted by Mikey` View Post
    Thanks, saved me some time. I wrote something for setting selected x/y to the correct coordinates for a certain color. I had some trouble finding a HSL->RGB conversion but it's in openosrs for anyone who needs that.

    Spoiler for :

    Code:
    public void setCoordinatesToColor(int hue, int saturation, int lightness) {
            for (int x = 0; x < width; x++) {
                int computedSaturation = getSaturation(x);
                if (computedSaturation == saturation) {
                    lastColorX = x;
                    currentSaturation = saturation;
                    break;
                }
            }
    
            for (int y = 0; y < height; y++) {
                int computedLightness = getLightness(y);
                if (computedLightness == lightness) {
                    lastColorY = y;
                    currentLightness = lightness;
                    break;
                }
            }
    
            for (int y = 0; y < height; y++) {
                int computedHue = getHue(y);
                if (computedHue == hue) {
                    lastHueY = y;
                    currentHue = hue;
                    break;
                }
            }
    
            pickedColor = Rasterizer.getHsl(currentHue, currentSaturation, currentLightness);
        }
    
        private int getHue(int y) {
            return (int) (63 - Misc.map(y, 0, height - 1, 0, 63));
        }
    
        private int getLightness(int y) {
            return (int) (127 - Misc.map(y, 0, height - 1, 0, 127));
        }
    
        private int getSaturation(int x) {
            return (int) Misc.map(x, 0, width, 0, 7);
        }
    Im glad, but why are you iterating x to width, y to height(and multiple times..) to find x, y, hueY? it can be directly computed very easily:
    Code:
        public void setPositionFromHSL(int h, int s, int l) {
            int hueY = Math.round(MathUtils.map(63 - h, 0, 63, 0, height - 1));
            int colorX = Math.round(MathUtils.map(s, 0, 7, 0, width));
            int colorY = Math.round(MathUtils.map(127 - l, 0, 127, 0, height - 1));
            
            currentHue = Math.round(63 - MathUtils.map(hueY, 0, height - 1, 0, 63));
            currentSaturation = Math.round(MathUtils.map(colorX, 0, width, 0, 7));
            currentLightness = Math.round(127 - MathUtils.map(colorY, 0, height - 1, 0, 127));
            
            pickedColor = Palette.getHsl(currentHue, currentSaturation, currentLightness);
            lastHueY = hueY;
            lastColorX = colorX;
            lastColorY = colorY;
        }
    as for hsl -> rgb conversion, what you linked isn't really ideal and is gonna result in quite a noticeable color difference, example(left is the original colors, right is the converted colors with the method from OpenOSRS):
    Attached image
    A much better and equally as simple method is to find the 'closest' color in the palette, i've talked about it in another post not too long ago
    Using the method i described yields a much better(accurate) result:
    Attached image
    Attached image
    Reply With Quote  
     

  12. Thankful user:


  13. #9  
    Banned
    Join Date
    Sep 2021
    Age
    31
    Posts
    19
    Thanks given
    0
    Thanks received
    1
    Rep Power
    0
    Good job on it will be definently useful
    Reply With Quote  
     

  14. #10  
    Registered Member
    Teemuzz's Avatar
    Join Date
    Oct 2009
    Posts
    2,755
    Thanks given
    1,212
    Thanks received
    422
    Rep Power
    934
    nvm
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. RS2 Color Picker (For Recolors)
    By XScapeRsps in forum Tools
    Replies: 2
    Last Post: 11-15-2020, 11:54 PM
  2. Color picker by Kevin & InzInz
    By cube in forum Requests
    Replies: 4
    Last Post: 01-29-2009, 01:35 AM
  3. Packet 6 - Draw NPC model onto widget/interface [508]
    By veer in forum RS 503+ Client & Server
    Replies: 13
    Last Post: 09-01-2008, 09:21 PM
  4. Packet 64 - Draw Player model onto widget/interface [508]
    By veer in forum RS 503+ Client & Server
    Replies: 1
    Last Post: 09-01-2008, 08:02 PM
  5. Runescape color picker.
    By Quint in forum Tools
    Replies: 20
    Last Post: 07-18-2008, 01:40 PM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •