2

I'm having a lot of trouble converting unique integers (index numbers) into unique float colours that are interpretable by an RGB565 OpenGL surface. When I assign unique colours, more often than not they are drawn as slightly different values due to loss of precision, so when I read the colour with glReadPixels and try to convert it back into a float for comparison, they are not equal.

I posted a similar question here OpenGL ES 2.0 solid colour & colour value precision issue but failed to implement the answer I was given, can anyone give me specifics (code and explanation) for this?

Community
  • 1
  • 1
STT
  • 35
  • 7

1 Answers1

1

If you only need 605 unique values, then 10 bits of precision (up to 1024 values) should be enough.

RGB565 has 16 bits of precision, so you can use the 6 extra bits of precision as a form of error-correction by spacing the values out so that if there is a small adjustment of the values through rounding or dithering or whatever, you can set it to the closest valid value.

So, assign 3 of your 10 bits to R, 4 to G and 3 to B.

For example red and blue have a range of 0-31, but you only need 8 possible values (3 bits), so you only store the values 2, 6, 10, 14, 18, 22, 26, 30. When scaled up to 8 bits, these values will be 16, 48, 80, 112, 144, 176, 208, 240. Then when you reconstruct the index, any value in the range of 0-31 is interpreted as a 0, 32-63 is a 1, 64-95 is a 2 and so on (this can be done with a simple bit-shift). That way small errors of +/- a small amount won't matter.

void assignID(int regionnumber)
{
    int UBR=31; //Upper boundary for blue and red
    int UG=63; //Upper boundary for green

    // split regionnumber into 3/4/3 bits:
    int R = (regionnumber >> 7) & 7;
    int G = (regionnumber >> 3) & 15;
    int B = regionnumber & 7;

    // space out the values by multiplying by 4 and adding 2:
    R = R * 4 + 2;
    G = G * 4 + 2;
    B = B * 4 + 2;

    // combine into an RGB565 value if you need it:
    int RGB565 = (R << 11) | (G << 5) | B;

    // assign the colors
    regions[regionnumber].mColorID[0] = ((float)R)/UBR;
    regions[regionnumber].mColorID[1] = ((float)G)/UG; // careful, there was a bug here
    regions[regionnumber].mColorID[2] = ((float)B)/UBR;
}

Then at the other end, when you read a value from the screen, convert the RGB values back to integers with 3, 4 and 3 bits each and reconstruct the region:

int R = (b[0] & 0xFF) >> 5;
int G = (b[1] & 0xFF) >> 4;
int B = (b[2] & 0xFF) >> 5;

int regionnumber = (R << 7) | (G << 3) | B;
samgak
  • 23,944
  • 4
  • 60
  • 82
  • It works! Thank you so much for this you're a life saver. I have read your explanation and understand the aim of the code, but don't fully understand how it matches up with the code. I'm about as new to graphical development as you can be at this stage, can you recommend anything I should read so that I can get my head around bit manipulation and other key concepts? – STT Jul 05 '15 at 07:24
  • 1
    Glad to hear it works, here's a short tutorial I found on the net that explains bit manipulation concepts, including the specific example of RGB565: http://sol.gfxile.net/boolean.html This page of bit hacks is pretty frequently referenced on SO: http://graphics.stanford.edu/~seander/bithacks.html – samgak Jul 05 '15 at 10:06