24bit to 16 bit PLEASE help

Started by
19 comments, last by VanillaSnake21 18 years ago
Hi, I am going through the book by Ander LeMothe on Windows Programming in DirectX, and in one of its programs where he tells us how to load a 16 bit bitmap there is a part which i totally don't get and he doesn't explain it In the demo there is a part of the code that converts a 24bit bitmap into a 16 bit bitmap, but how he got to it I am absolutely clueless, here it is ///////////////////////////////////////////////////////////////////// / process each line and copy it into the primary buffer for (int index_y = 0; index_y < SCREEN_HEIGHT; index_y++) { for (int index_x = 0; index_x < SCREEN_WIDTH; index_x++) { // get BGR values, note the scaling down of the channels, so that they // fit into the 5.6.5 format /////////////////////////////////////////////////////////////////////////////// WHAT IS THIS? WHERE DOES HE GET THE + 0, +1, +2 and all the multiplication, and shifting? UCHAR blue = (bitmap.buffer[index_y*SCREEN_WIDTH*3 + index_x*3 + 0])>> 3, green = (bitmap.buffer[index_y*SCREEN_WIDTH*3 + index_x*3 + 1]) >> 3, red = (bitmap.buffer[index_y*SCREEN_WIDTH*3 + index_x*3 + 2]) >> 3; /////////////////////////////////////////////////////////////////////////////// // this builds a 16 bit color value in 5.6.5 format (green dominant mode) USHORT pixel = _RGB16BIT565(red,green,blue); // write the pixel primary_buffer[index_x + (index_y*ddsd.lPitch >> 1)] = pixel; } // end for index_x } // end for index_y Please help, ofcourse I can just copy the code and not worry how it works, but I really wan't to uderstand it, so that I can write a game myslelf. Thank You

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

Advertisement
Well, it's 3 bytes per pixel.

It might be more clear written like this:


unsigned char* pixel = &bitmap.buffer[ (y * SCREEN_WIDTH + x) * 3];

unsigned char blue = pixel[0];
unsigned char green = pixel[1];
unsigned char red = pixel[2];

then he right shifts the values:

blue >>= 3;
green >>= 3;
red >>= 3;

this means that blue, green, and red each have 5 bits of data in them (8 - 3 = 5), so you can left-shift and OR these colors into one 16-bit value:

(note: should green only be shifted right by 2 bits, giving it 6 bits of data?)

unsigned short new_pixel = _RGB16BIT565(red,green,blue);


edit: ha! I am winnar!!lelevnty
Assuming that the bitmap.buffer is an array which is filled like so:

{ blue, green, red, blue, green, red, etc... }

if you factor the 3 out of the index_y*SCREEN_WIDTH*3 + index_x*3 you get

3 * (index_y * SCREEN_WIDTH + index_x)

now the (index_y * SCREEN_WIDTH + index_x) gets the index value from a coordinate, essentially turning a 2d coordinate into a 1d coordinate.

Since the array is filled like such (see above), the coefficient 3 is necessary to get the actual location of the BGR value.

The +0, +1, and +2 go along with the coef. because the value of bitmap at index+0 is the BLUE value, +1 is the GREEN, +2 RED:

{ blue, green, red, blue, green, red, etc... }

The shift right by 3 essentially divides each value by 8. This is necessary to transform to 16 bit because a 24 bit bitmap stores RGB values as 8 bits each (r, g, b are all 8-bit integers). However, 16-bit bitmaps store RGB values as 5 or 6 bits each (r=5bit integer, g = 6 bit int, b = 5 bit int).

An 8-bit integer has a max value of 256
A 5-bit integer has a max value of 32

256 divided by 32 is 8, so there you go!

Hope you understood all that, reply if you need more clarification.

-edit: DANG! BEATEN BY RDRAGON1!!!!!!!111111
A JPEG is worth a thousand and twenty four DWORD's. ;)
Note: Due to vacationing my website will not be updated till late-August. Of course I still have internet, but who wants to program during a vacation?
more efficient:


unsigned int row_count = SCREEN_HEIGHT;unsigned int col_count;unsigned char const* src_pixel = &src_buffer[0];unsigned short* dst_pixel = &dst_buffer[0];while( row_count-- ){   col_count = SCREEN_WIDTH;   while( col_count-- )   {      //convert 24-bit to 16-bit      unsigned char blue  = src_pixel[0] >> 3;      unsigned char green = src_pixel[1] >> 2;      unsigned char red   = src_pixel[2] >> 3;      //store as  [blue:5][green:6][red:5]      *dst_pixel = (blue << 11) | (green << 5) | red;      ++dst_pixel;      src_pixel += 3;   }}


This is untested, I just whipped it up - but it looks okay... The order of blue/green/red in the destination might be wrong... The order in the source might be wrong too.
Thought I'd add my 2 cents to this. I spent days trying to get Lamothe's code to work with different bitmaps. His engine is very inter-dependant, even if the code you use for converting bitmaps is correct, you'll run into problems with other initialization code. My recommendation after experiencing this nightmare:

1) Stick with the resolution format he uses in one of his projects and use that for ALL of your artwork and project settings.

2) Learn Direct3D so you can use DirectX extensions and take advantage of LoadSurfaceFromFile() etc.

If you go the 2nd route, I recommend Beginning Game Programming by Jonathan Harbour.
Another 2 cents:

There are two 16 bit modes out there, 565bit and 555bit. Never ever rely on the fact that one of them is more often in use than the other. Always cater for the possibility of both.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Original post by geekalert
now the (index_y * SCREEN_WIDTH + index_x) gets the index value from a coordinate, essentially turning a 2d coordinate into a 1d coordinate.

Since the array is filled like such (see above), the coefficient 3 is necessary to get the actual location of the BGR value.


OK, thanks for clearing up the part about the addition ( +0, +1, +2), I understand that the array is in { b , g , r ...} order, but what do you mean "to get the index value from a coordinate, turning it into 1D?" You mean turning it into a point? And also from the previous post, RDragon1 said that 3 is the size of 1 pixel in 24bit mode, I also get that, but why do we need to multiply everything by 3? Also, will it be the same if for the first color, I don't add 0, and just leave it as it is, or will it make a difference? Thank you guys for responding, I couldn't find this info anywhere.

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

A bitmap is two dimensional usually, right? Yeah. But what if we store it in an array thats only one-dimensional? Like whoa, dude! Whaddawe do!?

Well, we just take each line, and append it to another:

Original bitmap (just an example with arbitrary values) is two-d:

1, 4, 6, 7, 2, 3
1, 4, 3, 3, 9, 8
3, 4, 6, 6, 1, 1
2, 3, 8, 7, 4, 3

So we need to store that bitmap in memory. Do we do the naive:

bitmap[6][4];for(int x = 0; x < 6; x++){for(int y = 0; y < 6; y++){bitmap[x][y] = whatever;}}


Of course not! We want to be real programmers using 1D arrays, not little girly men!

bitmap[24]; // 24 = 6 * 4for(int x = 0; x < 6; x++){for(int y = 0; y < 4; y++){new_array_bitmap[x + y*SCREEN_WIDTH] = original_2d_girly_bitmap[x][y];}}


Now you see what the x+(y*SCREEN_WIDTH) does? Probably not ;). So I'll throw in a picture for clarity:



I hope that helps you understand what x+(y*SCREENWIDTH) does.

As for the multiplied by 3... thats one of those "its so easy its hard" ones. Wait for my next post for a reply!
A JPEG is worth a thousand and twenty four DWORD's. ;)
Note: Due to vacationing my website will not be updated till late-August. Of course I still have internet, but who wants to program during a vacation?
Continued from my last post...

A coefficient of 3, huh? Well, I'll try my best to explain this one!

Let's look at an arbitrary array (correction, a MACHO array).

int random[] = { 9, 8, 6, 3, 4, 6 };

So, you wanna access the 3rd element of this array? No problem!

int third_element = random[2];

OMYGODITSATWO! Why isn't it a three? Well, remember that arrays in C++ start with index 0 (zero) (nil) (null) (etc.). Why? Well, thats because

C++ rox0rs!


Warning C++ may kick @$$

Now, for another problem (don't worry, these examples will make sense in the end). What if you had a structure called TwoInt, and they stored two integers?

struct TwoInt {
   int value_one;
   int value_two;
};

How would we store multiple TwoInt's in memory?
Let's look at the first way, the girly way:

TwoInt array[8];


Then you would do whatever it is you do with arrays. (but not THAT!)

But do you wanna be known as a girly man? Of course not!

Be a real programmer! Use PACKED DATA TYPES!

What's a packed data type/array? Well, instead of using those newfangled object oriented SOB's (just kidding, I love double-O), you could use a PACKED ARRAY!

Let's look at an example Packed Array:

We will structure it like so:
{ value_one, value_two, value_one, value_two, etc.. }
{ 0, 7, 4, 5, 2, 3, 6, 4, 2, 4, 6, 8, 4, 4, 6, 8 }

so array[0] is actually the value_one of the implicit TwoInt structure.
and array[1] is the value_two.

So, how do we get the value_one of.. say, the 5th implicit TwoInt?

Naive:

array[4];

Why is the above code wrong? Is it because I typed a 4 instead of 5? Think VanillaSnake, Think!

No! It's because array[4] actually points to the value_one of the 3rd TwoInt!
But what if we multiplied 4 by two?

array[8];

There you go! We've got the value_one of the 5th TwoInt!!!

This example can be applied to your BGR structures - think about it! You have three values, blue, red, and green, stored as a packed array.

Multiply the index value by 3, and you get the true index of the nth BGR structure.

Whew! Hope that explains everything! Reply with a Q if additional clarity is needed!

P.S. Please excuse me for mimicking the speaking style of "Decline of Video Gaming XMAS". Those are pretty funny tho!
A JPEG is worth a thousand and twenty four DWORD's. ;)
Note: Due to vacationing my website will not be updated till late-August. Of course I still have internet, but who wants to program during a vacation?
Quote:Original post by VanillaSnake21Also, will it be the same if for the first color, I don't add 0, and just leave it as it is, or will it make a difference?


A +0 or no +0 wouldn't make a difference. Purists like us just put the +0 in there, because we're... well.... purists.

A JPEG is worth a thousand and twenty four DWORD's. ;)
Note: Due to vacationing my website will not be updated till late-August. Of course I still have internet, but who wants to program during a vacation?

This topic is closed to new replies.

Advertisement