16Bit framebuffer and entity ID -> Color conversion

Hi,

for selecting the visible entities in my program I do a hidden drawing with false colors, where each color corresponds to an entity ID, then I read the pixels back and reconstrut the entity ID from the color.
This is easy in 24/32 bpp graphics contexts where I have 8 bit for each component and thus I can use values from 0-255 for each component.

In 16bpp (5 bit for red, 6 for green and 5 for blue), what is the best approach to do this ID -> Color conversion?

I tried drawing color values from 0 to 255 for each component and reading them back from the framebuffer and saw that the 255 intensities of each component are mapped to 32 chunks (for red and blue) and 64 chunks (for green) of variable length.

For Red and Blue (32 intervals):

222, 222, 222, 231, 231, 231, 231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 247, 247, 247, 247, 247, 247, 247, 247, 255, 255, 255, 255, 255,
189, 189, 198, 198, 198, 198, 198, 198, 198, 198, 206, 206, 206, 206, 206, 206, 206, 206, 214, 214, 214, 214, 214, 214, 214, 214, 222, 222, 222, 222, 222, 222,
156, 165, 165, 165, 165, 165, 165, 165, 165, 173, 173, 173, 173, 173, 173, 173, 173, 181, 181, 181, 181, 181, 181, 181, 181, 181, 189, 189, 189, 189, 189, 189,
132, 132, 132, 132, 132, 132, 132, 132, 140, 140, 140, 140, 140, 140, 140, 140, 148, 148, 148, 148, 148, 148, 148, 148, 148, 156, 156, 156, 156, 156, 156, 156,
99, 99, 99, 99, 99, 99, 99, 107, 107, 107, 107, 107, 107, 107, 107, 107, 115, 115, 115, 115, 115, 115, 115, 115, 123, 123, 123, 123, 123, 123, 123, 123,
66, 66, 66, 66, 66, 66, 74, 74, 74, 74, 74, 74, 74, 74, 74, 82, 82, 82, 82, 82, 82, 82, 82, 90, 90, 90, 90, 90, 90, 90, 90, 99,
33, 33, 33, 33, 33, 33, 41, 41, 41, 41, 41, 41, 41, 41, 49, 49, 49, 49, 49, 49, 49, 49, 57, 57, 57, 57, 57, 57, 57, 57, 66, 66,
0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 33, 33, 33,

For Green (64 intervals):

223, 227, 227, 227, 227, 231, 231, 231, 231, 235, 235, 235, 235, 239, 239, 239, 239, 243, 243, 243, 243, 247, 247, 247, 247, 251, 251, 251, 251, 255, 255, 255,
190, 195, 195, 195, 195, 199, 199, 199, 199, 203, 203, 203, 203, 207, 207, 207, 207, 211, 211, 211, 211, 215, 215, 215, 215, 219, 219, 219, 219, 223, 223, 223,
162, 162, 162, 162, 166, 166, 166, 166, 170, 170, 170, 170, 170, 174, 174, 174, 174, 178, 178, 178, 178, 182, 182, 182, 182, 186, 186, 186, 186, 190, 190, 190,
130, 130, 130, 130, 134, 134, 134, 134, 138, 138, 138, 138, 142, 142, 142, 142, 146, 146, 146, 146, 150, 150, 150, 150, 154, 154, 154, 154, 158, 158, 158, 158,
97, 97, 97, 97, 101, 101, 101, 101, 105, 105, 105, 105, 109, 109, 109, 109, 113, 113, 113, 113, 117, 117, 117, 117, 121, 121, 121, 121, 125, 125, 125, 125,
65, 65, 65, 69, 69, 69, 69, 73, 73, 73, 73, 77, 77, 77, 77, 81, 81, 81, 81, 85, 85, 85, 85, 85, 89, 89, 89, 89, 93, 93, 93, 93,
32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 44, 44, 44, 44, 48, 48, 48, 48, 52, 52, 52, 52, 56, 56, 56, 56, 60, 60, 60, 60, 65,
0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 16, 16, 16, 16, 20, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32,

With these values I can build a conversion map from my entity IDs to color values.

Question is: Is the way OpenGL converts the intensities of colors in 16Bpp color mode system independent?
Can I expect to have the above values on all 16Bpp machines or not?

If not, should I create this conversion map on the fly by writing all 255 intensities and reading them back?

You can perhaps use the GL_COLOR_TABLE token from the [b]glColorTable[/b] function ?

Or use one additional pass, after to have recopy the content of the framebuffer into a texture just after your initial pass, with a 1D map with 256 entries (or 65K if you have to use 16 bits entity ID indices instead only 8 bits entity ID indices) for to map your 8 bits (or 16 bits) entity ID inputs into trues colors outputs, and handle indirectly the conversion via this colormap conversion table with something like this into the fragment shader ?


uniform sampler2D indexedTexture; 
uniform sampler1D conversionTable;  

void main() 
{         
    vec2 pos = gl_TexCoord[0].xy;         
    vec4 falseColor = texture2D(indexedTexture, pos);         
    float index = falseColor.r;         
    vec4 indexedColor = texture1D(conversionTable, index);         
    gl_FragColor = indexedColor;       
}

You have certainly to modify the “float index = falseColor.r;” line if you want to use a more elabored entity ID format than a basic 8 bits indexed/paletted pixel format

If you want directly convert the “false color/entity ID” into a true color without the need of a second pass, replace this part


vec2 pos = gl_TexCoord[0].xy;         
vec4 falseColor = texture2D(indexedTexture, pos);         
float index = falseColor.r;

by somehing like this


float index = gl_color.r;

(where the entity ID is stored into the gl_color.r global variable generated by your “hidden drawing with false colors algorithm”)

=> you don’t have in this case to declare/use the indexedTexture variable/texture and to recopy the original framebuffer generated by your “hidden drawing with false colors algorithm” into this indexedTexture texture before because the conversion is now directly handle at the fragment level without the need of a second pass
(this is really very very more fast)

==> this can be implemented using this very short, simple and fast fragment shader :slight_smile:


uniform sampler1D conversionTable;  

void main() 
{    
    gl_FragColor = texture1D(conversionTable, gl_color.r);      
}

(you can use a 2D conversion table if your “hidden drawing with false colors algorithm” generate entity ID indices that are more big than the maximum witdh of a 1D texture on you platform … or cannot to be easily “compacted” into the gl_color.r global variable)
[this is not the case for 8 bits entity ID indices, but very certainly the case with 16 bits indices that need to be converted using one “big” 1D texture colormap conversion with a width of 65535 …]