Search code examples
c++rgbhsv

Cycle R,G,B vales as HUE?


I am using SFML and it has a color function that takes values in RGB. example.. (255,0,0). I would like to be able to cycle these numbers though a loop so that the displayed colour cycles though the hue...

So if I am using (76,204,63) the function will adjust those 3 numbers. So I need the function to intake rgb convert to HSV and then return rgb.

Any ideas how I would go about this?

the sfml code I wish to use is...

_sprite.setColor(76,204,63); This will set the sprite to a colour... I ma trying to work out how once that is done with those numbers to cycle the colour though the hue.


Solution

  • With a bit googling I've found this answer and converted the code to C++ with SFML in mind. I'm casting around pretty badly, so feel free to make it better. I guess it should even be possible to replace the 3x3 array.

    sf::Uint8 clampAndConvert(float v)
    {
        if(v < 0)
            return 0;
        if( v > 255)
            return 255;
        return static_cast<sf::Uint8>(v);
    }
    
    sf::Color RGBRotate(sf::Color old, float degrees)
    {
        float cosA = cos(degrees*3.14159265f/180);
        float sinA = sin(degrees*3.14159265f/180);
        float rot = 1.f/3.f * (1.0f - cosA) + sqrt(1.f/3.f) * sinA;
    
        float rx = old.r * (cosA + (1.0f - cosA) / 3.0f) + old.g * rot + old.b * rot;
        float gx = old.r * rot + old.g * (cosA + 1.f/3.f*(1.0f - cosA)) + old.b * rot;
        float bx = old.r * rot + old.g * rot + old.b * cosA + 1.f/3.f * (1.0f - cosA);
    
        return sf::Color(clampAndConvert(rx), clampAndConvert(gx), clampAndConvert(bx), old.a);
    }
    

    Edit: Removed unnecessary casts.

    Edit: Got rid of the matrix.

    Edit: As I've noticed the code doesn't really work as wanted, but here's a hardcoded solution that works perfectly, just isn't that compact and nice.

    #include <SFML/Graphics.hpp>
    
    int main()
    {
        sf::RenderWindow Screen (sf::VideoMode (800, 600, 32), "Game", sf::Style::Close);
        Screen.setFramerateLimit(60);
    
        sf::RectangleShape rect(sf::Vector2f(350.f, 350.f));
        rect.setPosition(150, 150);
    
        int dr = 0;
        int dg = 0;
        int db = 0;
    
        sf::Uint8 r = 255, g = 0,  b = 0;
    
        while (Screen.isOpen())
        {
            sf::Event Event;
            while (Screen.pollEvent (Event))
            {
                if (Event.type == sf::Event::Closed)
                    Screen.close();
            }
    
            r += dr;
            g += dg;
            b += db;
    
            if(r == 255 && g == 0 && b == 0)
            {
                dr = 0; dg = 1; db = 0;
            }
    
            if(r == 255 && g == 255 && b == 0)
            {
                dr = -1; dg = 0; db = 0;
            }
    
            if(r == 0 && g == 255 && b == 0)
            {
                dr = 0; dg = 0; db = 1;
            }
    
            if(r == 0 && g == 255 && b == 255)
            {
                dr = 0; dg = -1; db = 0;
            }
    
            if(r == 0 && g == 0 && b == 255)
            {
                dr = 1; dg = 0; db = 0;
            }
    
            if(r == 255 && g == 0 && b == 255)
            {
                dr = 0; dg = 0; db = -1;
            }
    
            rect.setFillColor(sf::Color(r, g, b));
    
            Screen.clear();
            Screen.draw(rect);
            Screen.display();
        }
    
        return 0;
    }