Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

For each vertex I use two floats as position and four unsigned bytes as color. I want to store all of them in one table, so I tried casting those four unsigned bytes to one float, but I am unable to do that correctly...

All in all, my tests came to one point:

    GLfloat vertices[] = { 1.0f, 0.5f, 0, 1.0f, 0, 0 };
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float),
        vertices);

// VER1 - draws red triangle
//  unsigned char colors[] = { 0xff, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
//          0xff };
//  glEnableVertexAttribArray(1);
//  glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(GLubyte),
//          colors);

// VER2 - draws greenish triangle (not "pure" green)
//  float f = 255 << 24 | 255; //Hex:0xff0000ff
//  float colors2[] = { f, f, f };
//  glEnableVertexAttribArray(1);
//  glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(GLubyte),
//          colors2);

// VER3 - draws red triangle
int i = 255 << 24 | 255; //Hex:0xff0000ff
int colors3[] = { i, i, i };
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(GLubyte),
        colors3);

glDrawArrays(GL_TRIANGLES, 0, 3);

Above code is used to draw one simple red triangle. My question is - why do versions 1 and 3 work correctly, while version 2 draws some greenish triangle? Hex values are one I read by marking variable during debug. They are equal for version 2 and 3 - so what causes the difference?

Edit: Question is already answered, I just want to add some more information, to clarify my motives for eventual future readers.

I am aware, that when copied to graphics memory, all values will be eventually stored as floats (even 4 unsigned bytes). "Packing" 4 colors into one float is used by me just to decrease memory usage by color values in my VertexBufferObject class, where all vertex values are stored in one float array. Thanks to this approach, color information for each vertex (RGBA) is stored into single float value, instead of four. Memory usage is significantly lower, at small cost of one additional reinterpret_cast at color creation/change

share|improve this question
add comment

4 Answers

up vote 1 down vote accepted
float f = 255 << 24 | 255

This code converts the integer value 0xff0000ff into a float-representation of the value, which uses a completely different (and complex) memory layout. Since you are using GL_UNSIGNED_BYTE, OpenGL is unable to interpret it correctly, so... you're getting gibberish.

If you really want to pack into a float array (seems silly to me), use reinterpret_cast.

share|improve this answer
    
Yes, you are right, I just understood that... Why do you think that is silly thought? I want to store all vertices information in one array and that way I will be using 50% less memory (compared to storing RGBA as 4 floats), is that wrong approach? –  Kog Nov 22 '12 at 14:15
1  
@Kog: It's silly because you're not storing a float. You told OpenGL that you were passing 4 unsigned integers. That's what passing a size of 4 and a type of GL_UNSIGNED_BYTE means. So you should be creating an array of GLubytes, not ints or floats. –  Nicol Bolas Nov 22 '12 at 20:29
    
Generally you are right, however I am currently working on VertexBufferObject class, and I want to store all vertex information in one array (array of structures approach), instead of couple of them. I will edit my question, to explain that to future readers –  Kog Nov 23 '12 at 8:52
    
Then perhaps ccxvii's answer will interest you - you really don't need any casts to do it. –  Liosan Nov 23 '12 at 9:30
add comment

Interleaved arrays allows you to store them in one chunk of contiguous memory, by just adjusting the pointer offsets.

struct {
  float xy[2];
  unsigned char rgba[4];
} vertices = { ... };

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 12, vertices.xy);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 12, vertices.rgba);

Or you you can use a union to convert an RGBA quartet to a float with the same bit representation...

float pack_color(unsigned char rgba[4])
{
    union { float f; unsigned char rgba[4]; } u;
    u.rgba[0] = rgba[0];
    u.rgba[1] = rgba[1];
    u.rgba[2] = rgba[2];
    u.rgba[3] = rgba[3];
    return u.f;
}
share|improve this answer
add comment

You cannot break a float into four bytes that make sense individually. Floats conform to a certain format, namely 1 sign bit, 8 exponent bits and 23 mantisa bits.

    S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMMMM

breaking it up into 4 bytes yields this

   [SEEE EEEE] 
   [EMMM MMMM]
   [MMMM MMMM]
   [MMMM MMMM]

Once you print a binary value of 1.0f, 1.1f, 1.453f and 2.735f you will see why mangling floats and doubles have no practical value; if you want floats use them as floats - else use integers ;)

share|improve this answer
add comment

Let's read some documentation (GL may have a reputation for being easy but that doesn't mean that you get to skip reading documentation).

http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml

size

Specifies the number of components per generic vertex attribute

type

Specifies the data type of each component in the array

OK, so you're using 4 components and your "type" param is GL_UNSIGNED_BYTE, which means that the data you use for your "pointer" param will be interpreted as 4 unsigned bytes.

In other words, glVertexAttribPointer will not do any type conversion for you (GLvoid * as the data type of the pointer param should be sufficient hint of that). You tell it what type you're using for your data via it's parameters, and GL will interpret your data as if it was that type, and nothing else.

share|improve this answer
    
Hi, thank you for taking your time answering this question. Of course I understood that glVertexAttribPointer isn't doing any conversions for me, otherwise I wouldn't try to fit four bytes into one float. Problem was, that I believed that both int and float values "consisted" (in ver 2 and 3) of the same bits in memory, while they did not - they only had the same numerical values, that were stored differently. I just misunderstood what hex value shown in editor meant. Now I just understood that as I was preparing example to show what I meant ;) –  Kog Nov 22 '12 at 14:11
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.