Jump to content
  • Advertisement
Sign in to follow this  
VanillaSnake21

24bit to 16 bit PLEASE help

This topic is 4491 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 * 4

for(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!

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!