Error in color fading function

0

I found this old color fading function in my snippets folder and would like to implement it to one of my projects. It can be used to fade one color to another. It's a very long one-liner:

D3DCOLOR GetFadedColor(D3DCOLOR from, D3DCOLOR to, float factor)
{
    return (factor<0.0f)?from:((factor>1.0f)?to:((((from>>24)>(to>>24))?((from>>24)-(D3DCOLOR)(factor*(float)((from>>24)-(to>>24)))):((from>>24)+(D3DCOLOR)(factor*(float)((to>>24)-(from>>24))))<<24)|((((from<<8)>>24)>((to<<8)>>24))?(((from<<8)>>24)-(D3DCOLOR)(factor*(float)(((from<<8)>>24)-((to<<8)>>24)))):(((from<<8)>>24)+(D3DCOLOR)(factor*(float)(((to<<8)>>24)-((from<<8)>>24))))<<16)|((((from<<16)>>24)>((to<<16)>>24))?(((from<<16)>>24)-(D3DCOLOR)(factor*(float)(((from<<16)>>24)-((to<<16)>>24)))):(((from<<16)>>24)+(D3DCOLOR)(factor*(float)(((to<<16)>>24)-((from<<16)>>24))))<<8)|((((from<<24)>>24)>((to<<24)>>24))?(((from<<24)>>24)-(D3DCOLOR)(factor*(float)(((from<<24)>>24)-((to<<24)>>24)))):(((from<<24)>>24)+(D3DCOLOR)(factor*(float)(((to<<24)>>24)-((from<<24)>>24)))))));
}

D3DCOLOR is just a DWORD (unsigned long). A color can for example be 0xAARRGGBB (A-alpha, R-red, G-green, B-blue), but works with other compositions aswell.

Obviously it's a total mess, but this is exactly what I need.

The problem is that it doesn't work as intended:

GetFadedColor(0x00000000, 0xff33cccc, 0.3f)
// = 0x4c0f3d3d - working as intended
GetFadedColor(0xff33cccc, 0x00000000, 0.3f)
// = 0x000000bf - pretty wrong
GetFadedColor(0xff00ff00, 0x00ff00ff, 0.3f)
// = 0x004c00ff - second color value is correct, everything else wrong

I actually don't know how it works and don't remember where I have it from, so I'm asking here for help. Either help me find the error or find an alternative function that does exactly this.

c
colors
code-snippets
asked on Stack Overflow May 29, 2013 by typ1232 • edited May 29, 2013 by typ1232

1 Answer

1

What you should to now is first you should spend maybe 5 minutes to write down some really basic tests with the cases where you know what you expect. You don't even need to use any test framework, because to get rolling you could just use assert:

// basicTests.c
#include <assert.h>

int getFadedColor_basicTests()
{
    assert(GetFadedColor(0x00000000, 0xff33cccc, 0.3f) == 0x4c0f3d3d  && "30% from black to light blue should be greenish");
    assert(GetFadedColor(0xff33cccc, 0x00000000, 0.3f) == something   && "30% from one color to another should be...");

    // if you're not sure what the exact value should be, you should write a helper function
    // that returns true/false for if each of the four components of the actual color
    // are in a sensible expected range
    ...
}


int main()
{
    getFadedColor_basicTests();
    return 0;
}

Once you're happy with how much coverage you get with tests, be it just 3 asserts total, or maybe 50 asserts if you feel like it, you should start reformatting the one-liner, breaking the line, adding meaningful indentation and comments. Start refactoring, extract out common expressions, add comments on what they do or should do, all while running the tests in between changes and adding tests as you devise new ones.

EDIT:

Isn't it just supposed to linearly extrapolate each of the components separately?

int fade(int from_, int to_, float factor)
{   
    unsigned char *from = (unsigned char*)&from_;
    unsigned char *to = (unsigned char*)&to_;
    int result_;
    unsigned char *result = (unsigned char*)&result_;

    for (int i = 0 ; i < 4; ++i)
    {
        result[i] = factor * ((int)to[i] - (int)from[i]) + from[i];
    }   

    return result_;
}
answered on Stack Overflow May 29, 2013 by Adrian Panasiuk • edited May 29, 2013 by Adrian Panasiuk

User contributions licensed under CC BY-SA 3.0