Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What am I missing / doing wrong for my rainbow Color Picker to not saturate correctly?

I am trying to create a Color Picker similar to that of MS Paint. Unfortunately, I can't figure out the algorithm for saturation. Whenever I try to implement saturation, it simply will not saturate correctly. I have to be missing some understanding of the saturation effect in the algorithm.

enter image description here

This is what my current algorithm creates. Anytime I try to perform a saturated effect going down on the Y axis, it just makes everything after the first line completely red or black.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML;
using SFML.Graphics;
using SFML.Window;

namespace Source
{
   public ColorWheel()
    {
        for (int y = 0; y < 255; y++)
        {
            for (int z = 0; z < 6; z++)
            {
                for (int x = 0; x < 255; x++)
                {
                    uint ux = (uint)x;
                    uint uy = (uint)y;
                    uint uz = (uint)z;
                    ux = ux + (uz * 255);
                    image.SetPixel(ux, uy, color);

                    //Red 255 - Green 0-254
                    if (z == 0)
                    {
                        color.G += 1;
                    }
                    //Green 255 - Red 255-0
                    else if (z == 1)
                    {
                        color.R -= 1;
                    }
                    //Green 255 - Blue 0-255
                    else if (z == 2)
                    {
                        color.B += 1;
                    }
                    //Blue 255 - Green 255-0
                    else if (z == 3)
                    {
                        color.G -= 1;

                    }
                    //Blue 255 - Red 0-255
                    else if (z == 4)
                    {
                        color.R += 1;
                    }
                    //Red 255 - Blue 255-0
                    else if (z == 5)
                    {
                        color.B -= 1;
                    }

        Texture texture = new Texture(image);
        sprite.Texture = texture;
    }

    public void Update(double dt)
    {
    }

    public void Render(RenderWindow rWindow)
    {
        rWindow.Draw(sprite);
    }

}

}

like image 781
uFootball8 Avatar asked Oct 20 '22 18:10

uFootball8


2 Answers

I found this quite an interesting challenge. Took me a while, but I think I figured it out. The tricky part apparently is realizing that while on line 1, colors go between 255 and 0, each consecutive line has fewer colors (as they slowly blend to white).

Thus on say, line 10, you've got 255 pixels, and 245 colors available to fill them. Anyway, here's the code:

for (int y = 0; y < 255; y++)
        {
            color = new Color((255), y, y);
            for (int z = 0; z < 6; z++)
            {
                for (int x = 0; x < 255; x++)
                {
                    float colorDif = (255 / ((float)255 - y));
                    uint ux = (uint)x;
                    uint uy = (uint)y;
                    uint uz = (uint)z;
                    ux = ux + (uz * 255);
                    image.SetPixel(ux, uy, color);

                    if (x >= lastX + colorDif)
                    {
                        //Red 255 - Green 0-254
                        if (z == 0)
                        {
                            if (color.G < (255))
                                color.G += 1;
                        }
                        //Green 255 - Red 255-0
                        else if (z == 1)
                        {
                            if (color.R > y)
                                color.R -= 1;
                        }
                        //Green 255 - Blue 0-255
                        else if (z == 2)
                        {
                            if (color.B < (255))
                                color.B += 1;
                        }
                        //Blue 255 - Green 255-0
                        else if (z == 3)
                        {
                            if (color.G > y)
                                color.G -= 1;
                        }
                        //Blue 255 - Red 0-255
                        else if (z == 4)
                        {
                            if (color.R < (255))
                                color.R += 1;
                        }
                        //Red 255 - Blue 255-0
                        else if (z == 5)
                        {
                            if (color.B > y)
                                color.B -= 1;
                        }
                        lastX += colorDif;
                    }
                }
                lastX = 0;
            }
        }

It seemed to work pretty well for me, but if there's any issues, lemme know and I'll take another look at it. Hope it helps!

EDIT: and a little further explaining, just in case. What this achieves, is to make the colors go from full color to white (which is what changing saturation will do). But just in case that isn't what you meant, there's another two variations which should work just as well.

If you want it all to blend to black, all you need to change is the minimum color from y to 0 and the maximum color from 255 to 255-y.

You can also blend to gray, in which case you'll need both max as 255-y, min as y and colorDif = (255 / ((float)255 - 2 * y)); (note the 2 *). With gray however you'll only get 127 lines of color, instead of 255. If this doesn't make sense, I can try explaining further :P

like image 95
Steven Mills Avatar answered Nov 15 '22 07:11

Steven Mills


Thank you Steven Mills.

And here is another way to do it, the code I came up with which uses HSL.

Here is the answer. Please use this as you see fit, freely, as I am glad to post a working class that will create a Color Picker for anyone using C# and SFML.net- but also providing the logic for anyone who wishes to create a Color Picker for C# only.

The solution is simple: http://richnewman.wordpress.com/about/code-listings-and-diagrams/hslcolor-class/

1) Add the HSLColor class from the above link.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using SFML;
using SFML.Graphics;
using SFML.Window;

namespace Source
{
class ColorWheel : IGameObject
{
    Image image = new Image(240, 220);
    HSLColor hslColor = new HSLColor();
    System.Drawing.Color systemColor = new System.Drawing.Color();
    Color pixelcolor = new Color();
    public Sprite sprite = new Sprite();

    public ColorWheel()
    {
        pixelcolor = Color.Red;
        hslColor.SetRGB(pixelcolor.R, pixelcolor.G, pixelcolor.B);

        for (int y = 0; y < 220; y++)
        {
            //pixelcolor = Color.Red;
            //hslColor.SetRGB(pixelcolor.R, pixelcolor.G, pixelcolor.B);
            hslColor.Hue = 0;
                for (int x = 0; x < 240; x++)
                {
                    systemColor = hslColor;
                    pixelcolor.R = systemColor.R;
                    pixelcolor.G = systemColor.G;
                    pixelcolor.B = systemColor.B;
                    image.SetPixel((uint)x, (uint)y, pixelcolor);
                    hslColor.Hue += 1;
                }
                hslColor.Saturation -= (y * 0.01);

        }

        Texture texture = new Texture(image);
        sprite.Texture = texture;
    }


    public void Update(double dt)
    {
    }

    public void Render(RenderWindow rWindow)
    {
        rWindow.Draw(sprite);
    }

}
}

And here is the resulting image, which you are freely allowed to use for anything you want. You do not even need to use the ColorWheel class, but simply use this image and get the pixel at the mouse position to dye your gameobjects as you see fit.

enter image description here

To change the brightness (which would be on the slider) use hslColor.Luminosity in the equation, and it would probably be best to use the ColorWheel class instead of the image, unless you feel confident adjusting the image brightness based on a double integer attached to the slider. A good Color Picker GUI which includes both the image, mouse cursor, and slider with just a few lines of code would be TGUI. Obviously you would want to replace the default image with the ColorWheel class if you were using it, or the ColorWheel image I just provided.

All free to be used by anyone as they see fit.

like image 40
uFootball8 Avatar answered Nov 15 '22 06:11

uFootball8