Conversion of Color4F to Color3B

Hi Devs…

I am using Color4F::RED or something other say, basically a 4F, which i use for a method call in drawnode
now i am using the same color to use in a place which requires Color3B
as they have the same construct and i require the id sent by the parameter in the call

thats why i want to convert the Color4F to Color3B

I thought, this would do

Color3B(color), where color is a 4F one
but i dont know why it’s not working
it shows black color only in the label
I’ve also tried to get individual color from it
but still doesn’t work

however when i use Color3B(10,30,40) (say)
it works fine
so, its sure that the code works fine…
but i guess the conversion is not able to happen.

can anyone help me… ??
@slackmoehrle… !!

Color4F for red is something like this:

auto red = Color4F(1.0f, 0.0f, 0.0f, 1);

Somewhat dated but still applies: http://www.opengl.org/discussion_boards/showthread.php/132502-Color-tables

no no… :smile:

i didn’t wanted the color table…
there’s a constructor for converting the Color4F to Color3B right… ??

something like this

Color3B(const Color4F & color)

or like the other side round conversion

Color4F(const Color3B & color)

i wanted to know… why they are not working.

can you test in demo code, whether they are working or not please… ??
Thanks… :smile:

oh, ok, I understand, let me try them

What are the values of the init list, when calling the constructor?

Color3B::Color3B(const Color4F& color)
: r(color.r * 255.0f)
, g(color.g * 255.0f)
, b(color.b * 255.0f)
{}

yes,

inside an enum
i have an id, and someother things, Color4F::RED (say)

for 3 items

and if id 1 is selected, i want to display the color in the ID 1
unfortunately i need to convert either 3B to 4F or 4F to 3B, my code is like that

but the constructors are not working…
yes, i am using the same init list…
or when converting from 3B to 4F, it’s counterpart constructor
but they doesn’t display color, they display only black
@iQD

Just tested and works as expected:

Color3B redB(Color4F::RED);
Color4F redF(redB);

Final color is still red.

This works too:

auto white = Color4F(Color4B(100, 50, 130, 255));

Note I just picked random values, so not your red

Breakpoint the constructers and look, if the values are the expected ones.

 enum SurfaceType { ICE, GRASS, GRAVEL, LAST };
    struct SurfInfo
    {
        float coeff;
        std::string label;
        std::string sprite;
        cocos2d::Color4F color;
    };

    static SurfInfo SURF_INFO[LAST];  
    MenuLayer() :
          _topMenu(nullptr),
          _topMenuOffsetX(0.0),
          _forceLayer(nullptr),
          _forceSlider(nullptr)
    {}

inside the cpp file

    MenuLayer::SurfInfo MenuLayer::SURF_INFO[MenuLayer::LAST] = 
{
    { 0.1, "ICE",    "ice.png",    Color4F::WHITE },
    { 0.5, "GRASS",  "grass.png",  Color4F::GREEN },
    { 1.0, "GRAVEL", "gravel.png", Color4F::RED   }
}

auto setSurfFromTag = [=](int tag) -> void
    {
        surf->setString(SURF_INFO[tag].label);
        surf->setFontFillColor(Color3B(SURF_INFO[tag].color));
        cb(tag);
    };

it’s not able to convert, the color displayed is still black

is there any fault in the code… ??

You can only tint a LabelTTF by using an atlas.

void Label::updateColor()
{
    if (nullptr == _textureAtlas)
    {
        return;
    }

If you want to set the color of the text just use setColor(...).

Strange, cause by default the color of a LabelTTF is white. If I just print some LabelTTF, it prints the text in white.

yes… when i am not using the setColor()
the displayed color is white which is usual…

but when i try to pass the color4F then there’s a problem
it only displays black.

dont know what really happened.

i’ll post it back, if i found the solution.

Found the solution.

So, when i was passing, like this, it didn’t work

    MenuLayer::SurfInfo MenuLayer::SURF_INFO[MenuLayer::LAST] = 
{
    { 0.1, "ICE",    "ice.png",    Color4F::WHITE },
    { 0.5, "GRASS",  "grass.png",  Color4F::GREEN },
    { 1.0, "GRAVEL", "gravel.png", Color4F::RED   }
}

auto setSurfFromTag = [=](int tag) -> void
    {
        surf->setString(SURF_INFO[tag].label);
        surf->setFontFillColor(Color3B(SURF_INFO[tag].color));
        cb(tag);
    };

but i used the other syntax and it worked which is below

MenuLayer::SurfInfo MenuLayer::SURF_INFO[MenuLayer::LAST] = 
{
    { 0.1, "ICE",    "ice.png",    Color4F(255,255,255,255) },
    { 0.5, "GRASS",  "grass.png",  Color4F(0,255,0,255) },
    { 1.0, "GRAVEL", "gravel.png", Color4F(255,0,0,255)   }
};

auto setSurfFromTag = [=](int tag) -> void
    {
        surf->setString(SURF_INFO[tag].label);
        surf->setColor(Color3B(SURF_INFO[tag].color.r,SURF_INFO[tag].color.g,SURF_INFO[tag].color.b));
        cb(tag);
    };

it does work now, don’t know why so… !!
may be that doesn’t create the Color4F object by that syntax, so the constructors were not working

I dont have extensive knowledge of c++ but i guess, that’s the issue.
if anybody could explain me why…!! :smile:

that would be great.

Just Wanted to know

what is the difference between Color4F::RED and Color4F(255,0,0,255)
so when i passed Color4F::RED and tried to extract the RGB values, it didn’t worked.
but with the other one it worked, as i could understand, it didn’t created the object for the first syntax.

so tell me the difference first. !!

As I posted earlier:

You can only tint a LabelTTF by using an atlas.

Your original code uses surf->setFontFillColor(Color3B(SURF_INFO[tag].color)); but your working code uses surf->setColor(Color3B(SURF_INFO[tag].color.r,SURF_INFO[tag].color.g,SURF_INFO[tag].color.b));

setFontFillColor is not the same as setColor

Color4F is using floats in the range [0.0f … 1.0f]. Color4B is using byte values in the range [0 … 255].

setColor(Color3B(SURF_INFO[tag].color.r,SURF_INFO[tag].color.g,SURF_INFO[tag].color.b));

You are using byte values to a Color3B. Regardless, if you created a Color4F with values > 1.0f, the stored values won’t be clamped. You just created a Color3B with the values directly stored in the Color4F object.

By using surf->setFontFillColor(Color3B(SURF_INFO[tag].color)) and .color being a Color4f like Color4f::RED, the colors are converted to byte values in the appropriate range:

Color3B::Color3B(const Color4F& color)
: r(color.r * 255.0f)
, g(color.g * 255.0f)
, b(color.b * 255.0f)
{}

It was just not working, cause you used setFontFillColor instead of setColor, as setFontFillColor is only tiniting your font sprite, if you are using a sprite atlas.

Thanks for the detailed explanation @iQD

it really helped.
no… just to inform you
i had also tried with setColor before, but that was not working.

Yes, i saw the constructor, it’s converting the float values into bytes by multiplying them with 255
for a full rance of byte color scale
but, as i could understood from it.
when i declared like this…

  MenuLayer::SurfInfo MenuLayer::SURF_INFO[MenuLayer::LAST] = 
{
    { 0.1, "ICE",    "ice.png",    Color4F::WHITE },
    { 0.5, "GRASS",  "grass.png",  Color4F::GREEN },
    { 1.0, "GRAVEL", "gravel.png", Color4F::RED   }
}

it was something wrong with the initialization
as i heard from someone, that both are static vars, that’s why it didn’t created the object.

Anyway the problem is solved now.

Thanks for all your help… :smile: @slackmoehrle @iQD

Yeah, missed that one. It’s cause static objects don’t call the constructor, and Color4F::RED is implicitly static.
In fact the object is created, but initialized with 0, as in C++ all objects are initialized to 0. With RGB set to 0 you got a black color, cause Color3B has alpha set to 255.

May you should revise your code :wink: Using static objects and relying on constructors, which do conversions, is really a bad thing.
You would have had a hard time/crash on C :wink:

As more explained here:

static const int sci = 0; // sci is explicitly static
const int ci = 1; // ci is implicitly static

I never use static objects, cause they are a mess and you get side effects like in your code.

Which compiler and platform was this working?

What questions me, is the fact, that it compiles on your side.
E.g. using VC:

auto setSurfFromTag = [=](int tag) -> void

This would give you: error C3478: ‘SURF_INFO’ : an array cannot be captured by-value
I would have to change it to:

auto setSurfFromTag = [&](int tag) -> void

How do you call the lamba callback?