#### Archived

This topic is now archived and is closed to further replies.

# 02.05 - Resolution and Color Depth

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

## Recommended Posts

BYTE *lpBuffer;

Assuming that each pixel occupies one byte of memory, we can perform simple operations such as altering a given pixel’s value. First though, it should be noted that pixels are mapped to memory row-by-row. So, for a 640x480 memory buffer, here’s some examples:
// Change the first pixel color to ‘1’
lpBuffer[0] = 1;

// Change the seventeenth pixel color to ‘1’
lpBuffer[16] = 1;

// Change the fourth pixel on the eighth row to ‘1’
int x = 3;  // fourth column
int y = 7;  // eighth row
lpBuffer[ (640 * y) + x] = 1;

As you can see by the last example, you can calculate the position of any pixel in the buffer so long as you know the width of a row. Before we look at other pixel sizes, let’s learn how to form proper color values. Color Composition As you are most likely aware, video cards are capable of storing images comprised of different amounts of colors. Here''s the common list:
• *16 colors (4-bits)
• *256 colors (8-bits)
• 32,768 colors (15-bit High Color)
• 65,536 colors (16-bit High Color)
• 16,777,216 colors (24-bit True Color)
• 16,777,216 colors (32-bit True Color - only 24 bits are used for the color!)
(NOTE: The first two are special...see section 4 below) Of course, the number of colors you are capable of having depends on the type of video card you have. One deciding factor: video RAM -- the more colors available, the more RAM is needed to store screens of pixels. Also, not all cards support all color modes...some don''t have 15-bit and/or 24-bit color modes. Using the list above, we can tell how many bytes are needed to store a pixel at each color-depth. Let''s work backwards from 32-bit color... 24 and 32-bit Color We specify a color by choosing the amount of Red, Green and Blue in it. If you take 24-bit color for instance, 8 bits are used for each of the three components. The higher the intensity, the brighter the color component. Since we have 8 bits for each, that gives us 256 possible reds, greens and blues. The proper order to consider them in is RGB (Red, Green, Blue). In other words, black would be (0, 0, 0), white would be (255, 255, 255), green would be (0, 255, 0), and so on. By mixing together different combinations of colors, you can create any color in the spectrum -- using (255, 255, 0) would give you yellow, for instance (red+green). We put the values of each component together to form a single value; 0x000000(0) = black, 0xFFFFFF(16,777,215) = white, 0x00FF00(65,280) = green. 32-Bit color is kind of misleading because only 24 bits are used for the color (just like 24-bit color). The other 8 bits can be used for Alpha or transparency information, or not at all. Common notation for this mode is ARGB or XRGB; the first byte for alpha (or X - nothing). Here''s black (0, 0, 0, 0), white (0, 255, 255, 255) and green (0, 0, 255, 0) -- the last three bytes are the same as with 24-bit color. Throw them all together and you have: 0x00000000(0) = black, 0x00FFFFFF(16,777,215) = white, 0x0000FF00(65,280) = green (I''ve left the first unused byte zeroed out). 15 and 16-bit Color 15-Bit color isn''t all that popular due to the fact that the extra bit is wasted (a pixel here needs two bytes minus one of the bits; pixel sizes are always on byte-boundaries). Nonetheless, my video card actually supports it, so it does exist. Each color component (RGB) gets 5 bits, with the other bit (the first one) not used, giving us 32 possible red, green and blue values (intensities). Actually, you can use it for something like transparency or a flag of some kind if you want. The examples here would be: 0x0000(0) = black, 0x7FFF(32,767) = white, 0x03E0(992) = green. 16-Bit color takes that extra bit and includes it with the Green component, giving us 32 possible red and blue intensity values, and 64 green intensities. You should be able to put colors together for 16-bit by now...this time 0x07E0(2,016) would be green, and 0xFFFF(65,5535) would be white. 4 and 8-bit Color Modes Oh boy, here we go. You may already be aware of the fact that these modes are funny. Let''s dismiss 4-bit color right away because it’s obsolete. If memory serves, 4 bits were used to denote one of 16 possible colors, and the other 4 bits in the byte were used for attributes such as reverse video, blink, etc. Don''t quote me on this though. I''m not really sure if you can have a straight-up 8-bit color mode, but I can tell you what this mode usually stands for: Palletized Mode. In this mode, each pixel does in fact have an 8-bit value, but this value doesn''t actually describe the color -- it is an index to a table called the palette that holds the real color value for the pixel. Each entry in this palette holds a regular 24-bit color, and since there are 8-bits to a palette index, there can be a total of 256 different entries in the palette. What this means to you is that all of the pixels on the screen must use the same 256 possible colors, and although you can (in most cases) set these 256 colors to be whatever you want, all of the pixels that you need displayed at once have to share this palette. This 8-bit palletized mode has its good points and bad points. On the good side of the coin, if you make any changes to the palette while pixels are on the screen, they will instantly change to the new color(s). You''ve probably seen this over and over again in classic games, where either everything purple changes to yellow or blinks, or areas of the display go wild with fast-cycling colors. A lot of simple animation tricks are also achieved by utilizing the palette... there are too many possibilities to even begin to mention. The other side of the coin is that this mode is more difficult to work with because you have a palette to manage, and if you''re writing a windowed-game you have to share some of these palette entries with everyone else that''s on the screen. The bottom line here is that although 8-bit color might be going out of style, we might visit it nonetheless in our game projects, either to round-out our learning, or to take advantage of some of this mode''s capabilities in emulating classic games. Simplify Things If you find yourself needing to compose a color from each of it''s components, you are best off creating macros to simplify their creation. Here''s a couple:
#define RGB16((r << 11) | (g << 5) | b)

#define RGB32((a << 24) | (r << 16) | (g << 8) | b)

We shift colors over by a certain number of bits so that they represent the proper value. For instance, the 16-bit macro does this: RRRRRGGGGGGBBBBB, and the 32-bit AAAAAAAARRRRRRRRGGGGGGGGBBBBBBB (A doesn''t matter unless you are using it for something). In Closing… Wow, this has been quite the article! I realize that there’s a lot of information here to digest. The important thing to keep in mind is that there will be occasions where you need to manually alter pixel colors in a buffer of some kind, and you’ll need to ensure that you’re traversing the buffer’s memory properly, and that you’re assigning the proper type of color value. Feel free to reply to this topic with your comments and questions.

##### Share on other sites
I know I may be jumping a bit ahead...but in the ARGB mode (ie, 32bit), what *exactly* is Alpha? You mentioned it is used for Alpha, or transparency, or nothing. For example:
#00FFFFFF is white, and #00000000 is black, but what is #FFFFFFFF, or #FF000000? Does that mean totally transparent white & totally transparent black?? (In which, any range of 00-FF of the first byte will somehow determine how transparent something is, w/ 00 at not & FF at completely transparent?)

---
~khal

##### Share on other sites
Alpha is transparency (in reality, translucency). It goes like this:

0x00FF0000 is a fully opaque red.
0x80FF0000 is a 50% translucent red.

(In reality, alpha value semantics are implementation dependent. With some libraries, 00 is fully opaque and FF is transparent, while in others 00 is transparent, and FF is fully opaque).

Alpha only matters when you're copying a surface over another, so alpha can be used to calculate which color should really be shown, combining the underliyng color whith the color being drawn and its alpha value.

Edited by - pazu on April 9, 2001 10:50:42 AM

##### Share on other sites
Actually, the alpha component of the color is totally useless. Think of it as ''left-over'' bits of memory -- they''re not needed for creating the color.

Of course, wherever you have free bits lying around, they tend to get used for other things. Pazu shows us what the most popular use for these bits are; the translucency of the pixel (in other words, how much you can see ''through'' it). This has nothing to do with the color of a pixel, but rather is a characteristic of the pixel.

Just keep in mind that whatever you assign to these bits, nothing is actually going to happen. If you want something to happen as a result of the alpha component value of a pixel, you have to write it out yourself...

...or, some graphics component or library that you''re using dictates what the alpha component is used for.

Teej

##### Share on other sites
Despite the fact I have a degree in Computer Science there are certain areas of the topic that take a bit of understanding, all this colour modes stuff is one of them.

Understanding 24 and 32 bit colour depth I have no problem with. I understand that there are 64 intensities of Green on 16 bit colour, but what I don''t see is why 7E (half of FF if my hex maths is correct), I would have thought
red = F000
Green = 0FF0
Blue = 000F

To me this would make sence when
white = FFFF
Black = 0000

I am still trying to get my head round 4 and 8 bit and 15 bit modes.
I have never programmed graphics in DOS, it would obviously have helped if I had.

##### Share on other sites
OK, obsolete color modes... .

Well, 4-bit color has gone the way of the dinosaur. Never use it again, and forget you ever heard of it. But, since that''s hardly a descriptive answer, here''s one. 4 bits translates into 16 total colors. Those 16 colors were designated, just like 8-color systems were designated before them (wow, now that WAS a long time ago)

8-bit color is a bit deceiving of a name, as it refers to a palette of 24-bit colors that are addressed by an 8-bit number. The colors in each spot in the palette can be shifted in and out, which allowed for some really trippy color effects in some older games. Palettized color is rarely used today except for remakes of old classic games, and games that really don''t require many different colors.

15-bit color designates 5 bits each for red, green, and blue. Don''t think of it in terms of hex in this way, because it only makes it harder. You''ve almost got to think of it in binary.

Take the 16-bit number - 0111010011001001

Now, in hex, that''s \$74C9, which doesn''t translate well into which bits are R, which are G, and which are B. Separated by binary into colors, we have 0 - unused, 11101 - red, 00110 - green, and 01001 - blue. Then, if you want to translate that into a different base, that''s fine. Thinking in decimal numbers (which we use most of the time), there is a range of 0-31 red, 0-31 green, and 0-31 blue. The color which I designated earlier is 29 red, 6 green, and 9 blue.

The only difference between 15 and 16-bit color is that the extra bit is given to green. Thus, the 16 bit number I showed above would be broken up like so in 16-bit color:

01110 - red; 100110 - green; 01001 - blue;
15 red (range 0-31); 38 green (range 0-63); 9 blue (range 0-31)

In this way, it''s similar to 24-bit color, except with less sensitivity in changes to colors, since each color range in 24-bit is 0-255.

##### Share on other sites
OK some quick points for you:

FF (255) divided by 2 is 7F (127)

64 shades of green = 3F (63) therefore assuming 565 colour mode:

red = F800
green = 07E0
blue = 001F

not :

4 bit mode is simple (to me anyway):

  Bit number value using binary:8|4|2|1-+-+-+-| | | +--- Blue| | +----- Green| +------- Red+--------- Hi-intensity

Do not quote me on the above colour locations, but they are correct as far I as remember for Dos colours. Basically for yellow you would use 2+4+8 (just using 6 would result in brown)

The following is a table of DOS colours from memory:

0 Black
1 Blue
2 Green
3 Cyan
4 Red
5 Purple
6 Brown
7 Light grey
8 Dark grey
9 Light blue
10 Light Green
11 Light Cyan
12 Light Red
13 Light Purple
14 Yellow
15 White

8 bit modes are what is sometimes refered to as an indexed colour system, this means that every pixel on the screen is a pointer to a 768 (256 * 3) byte table, since a pixel can contain a value between 0 and 255 this mode also allows some fancy effects to be made, like colour fades / animation (where a range of colours are set aside to rotate around themselves and thus provide a zoetrope (sp) or flicker book style of animation).

15 bit modes are simular to 16 bit mode, except you only use 5 bits for the green componant:

red = 7C00
green = 03E0
blue = 001F

If I have any holes in the above then someone else can freely fill them in as I do not know them at the moment as I''m nearly asleep.

Hmmm, Computer Systems Fundamentals was a bore, wrote a game instead of the course work and still passed the thing....

When I find my code in tons of trouble,
Friends and colleages come to me,
Speaking words of wisdom:
"Write in C."

##### Share on other sites
Wow, you remembered the whole table from memory? LOL, I could only remember the colors for 8-color mode. I don't remember the order, though, just remember Black(000), White(111), Yellow(110), Blue(001), Red(100), Green(010), Cyan(011), Magenta(101).

Edited by - Piotyr on April 10, 2001 6:54:17 PM

Edited by - Piotyr on April 10, 2001 7:29:28 PM

##### Share on other sites
If you can remember the order of the colors on the number keys of the Commodore 64, I''ll truly be impressed

All you have to do when thinking about color composition is
1. Figure out how many bits make up the color

2. Mentally (or on paper) figure out the bit spread:
3. 15: X RRRRR GGGGG BBBBB

4. 16: RRRRR GGGGGG BBBBB

5. 24: RRRRRRRR GGGGGGGG BBBBBBBB

6. 32: XXXXXXXX RRRRRRRR GGGGGGGG BBBBBBBB

7. (the X''s are not used for color)

8. Count the number of bits for each color; that''s the maximum intensity (e.g. 5 bits = 32 color intensities (0-31)

9. Take your color (as a decimal number) and convert it back to bits

10. Plop ''em all back in...there''s your color

Since everyone loves manual pixel color manipulation so much, I''ll be sure to put you through some ''fun'' exercises

Teej

##### Share on other sites
Ok first off Hi everyone, now that that is out of the way, How are you coming up with the hex numbers for the color values and why? I have always referenced color in a 255,255,0 fashion so all the hex stuff is confusing.

I don''t mean just the math, I mean how are you getting one value for a color instead of the 3 RGB values.

Hope it''s not too silly a question and thanks in advance.

Oh yeah Great Job Teej!!!

##### Share on other sites
Anon: As I''ve stated above, we do start by figuring out how much red, green and blue we''d like in a pixel. Depending on the color mode that you are working with, there''s a maximum value allowed for each of these color components. If we are talking about a simple 8.8.8 RGB pattern, then yes, we just take each value and dump it into memory. If however we''re using another mode (e.g. 5.6.5), you need to think in terms of bits and not bytes. Of course, we don''t do this stuff manually...here''s an example of a macro that takes RGB values and creates a single value for us:

#define RGB16((r << 11) | (g << 5) | b)

Here, we assume 5 bits for red, 6 bits for green and 5 bits for blue. Since 5 bits can store 32 possible values, that''s the range you''re allowed for that color. So here''s our layout:

RED: 0-31
GREEN: 0-63
BLUE: 0-31

Drop your choices into the macro and the computer will handle all of the bit merging needed to make the final color value.

Teej

##### Share on other sites
Better late than never. . .

Ok, there's a lot of stuff I'd liek some explanations about.

I never used this kind of hex code in my courses (0x00FF00)
So I'd liek to know how it is used, when why and whatnot.
Same thing with BYTE.
Is this some DirectX only type? Why is it all caps (unlike other types)? Where does it come from??? Did I miss a typedef or what?

the SIMPLIFY THINGS section to me is kinda absurd because I never used macros in C/C++. . . doesn't simplify much I'll tell you that

Then , there's those << and | operators.
I know << is for switching, butI only been introduced to this concept in an old assembly class and am in the fog as to what it does here. The pipe | is the bitwise operator IIRC but I fail to get it's meaning purpose and goal in the code.

#define RGB16((r << 11) | (g<< 5)| b)

BTW, this site is slooooooooow.

Edited by - Diabolus on May 7, 2001 9:40:26 PM

Edited by - Diabolus on May 8, 2001 12:42:47 PM

##### Share on other sites
ok, this is just how i resolved 0x07E0 would be the appropriate value of 15bit GREEN
since u cannot work on subsets of bytes(8bits) here , you should work on the bit-basis, like teej and the others said:

15bit color means u have 3 times 5 bits that represent RED, GREEN, BLUE

5 bits means u can have 32 values (0-31) because 2^5 = 32

we want to have a green with maximum intensity which would look like this:

00000 11111 00000
red green blue

but this is only in binary, how do we get it into 07E0 hex?
this goes back to the general question why base16 (hex) is such a common base when it comes to bits and bytes.

4 bits can have 16 (0-15)values: 1111 = 15 = F (hex)

so any group of four bits can be converted to exactly one digit in hex.

to convert the 15bits to hex we simply regroup them to groups of 4 starting on the RIGHT:

old: 00000 11111 00000
new: 000 0011 1110 0000

note that we still have the same binary number as before, just another groupung.

now we can convert each group into hex easily:

bin: 000 0011 1110 0000
hex: 0 3 E 0

each group in detail:

000 = 0
0011 = 3
1110 = E
0000 = 0

GREEN = 0x03E0

red would be:

11111 00000 00000

new grouping:

bin: 111 1100 0000 0000
hex: 7 C 0 0

RED = 0x07E0

(111 is regarded as 0111 = 7hex)

hope this helps?

concerning the macros i think i have to go read my c-books

awesome job, teej

cyas

marlowe

Edited by - marlowe on May 22, 2001 1:03:46 PM

##### Share on other sites
marlowe: You''re very close to understanding what the macros do...for everyone interested, here goes:

The operators >> and << are bit-shifters. Just as the way they ''point'', that''s the direction bits get shifted, and the number you give represents the number of bits to shift over. Here''s that macro again:

#define RGB16 ( (r << 11) + (g << 5) + b)

In english, it reads "Take the value of r and shift it 11 bits over. Take the value of g, shift it 5 bits over and add it to the result of the r-shift. Finally, add the value of b."

It helps for this macro to think in terms of bits. Since r and b can get any value between 0 (0 0000) and 31 (1 1111), and g can be any value between 0 (00 0000) and 63 (11 1111), we can take their binary representations and literally ''shove'' them over to the left.

First, let''s use the letters r,g,b in an example.

Here''s what the final value should look like:

rrrrrggggggbbbbb

Notice how you can create this value by taking each component and lining up the bits like so:

rrrrr00000000000
00000gggggg00000
00000000000bbbbb

What the macro is designed to do is exactly what you see here. If we take r''s 5 bits and shift them over 11 times to the left, they fall into the correct place for our final 16-bit value. Likewise, shifting g over 5 places lines it up properly, and b only needs to be added in -- no shifting is necessary.

Pretend that we wanted to create the following value:

aaabbccccdddeeee

What rules do we need to apply to create this value? Since values start from the right-hand side like so:

0000 0000 0000 0aaa
0000 0000 0000 00bb
0000 0000 0000 cccc
0000 0000 0000 0ddd
0000 0000 0000 eeee

...you can easily visualize how far each value needs to be moved to get to its proper place:

a << 13
b << 11
c << 7
d << 4
e

...and here''s the resulting macro:

#define EXAMPLE( (a<<13) + (b<<11) + (c<<7) + (d<<4) + e)

It''s important that the values used in the macro actually fit in the number of bits allowed. For instance, our RGB16 macro will give improper results if r>31, g>63 or b>31. If we wanted to, we could have checked these values in the macro like so:

#define RGB16 ( ((r%32)<<11) + ((g%64)<<5) + (b%32) )

The modulo operator gives the remainder of a division, and works well for ranges such as this. And in case you''re not well-versed with using ''%'', here''s a quick table to convince you:

1 % 5 = 1 (0, remainder 1)
2 % 5 = 2 (0, remainder 2)
3 % 5 = 3 (0, remainder 3)
4 % 5 = 4 (0, remainder 4)
5 % 5 = 0 (1, remainder 0)
6 % 5 = 1 (1, remainder 1)
7 % 5 = 2 (1, remainder 2)
8 % 5 = 3 (1, remainder 3)
9 % 5 = 4 (1, remainder 4)
10 % 5 = 0 (2, remainder 0)
11 % 5 = 1 (2, remainder 1)

What this pattern shows is that for any number you give it (first column), you''ll always get 0 to n-1 for the divisor you choose (second column).

Here''s another very useful example:

rand() returns a pseudo-random number between 0 and 32,767. If you wanted say a number between 0 and 31, you could use:

rand() % 32

Just as with the table above, this will give categorize all possible values into the range 0-31, which is what you want.

There ya go.

Teej

##### Share on other sites
Hey - great tutorial teej... I think Im finally starting to understand stuff.

Just one query - is there any particular reason for the extra bit being given to green in 16bit color mode? (as opposed to red or blue I mean)... just seems a bit random.

thanx.

##### Share on other sites
The order of the color on the C64 number keys is:

1 Black
2 White
3 Red
4 Cyan
5 Green
6 Blue
8 Yellow

Impressed??

Anyway.. Nice tutorial..

(To be honest i had to look on my good ol'' Commodore to remember what color the number 4 key was....)

##### Share on other sites
I have a question about something near the beginning of the article. I don''t understand how in 640x480 resolution there are only 307x200 pixels on the screen. Please help me understand this.

##### Share on other sites
I think you''ve just misread what Teej has said.
If the dimesions of the screen are 640x480 then there are 307,200 visible pixels on the screen not 307x200

##### Share on other sites
Oops...my bad. My computer clock is off and it wasn't 9:30. It was more like 2:30 in the morning, and I was really tired. Sorry about that.

Edited by - Minion on June 12, 2001 9:04:44 PM

##### Share on other sites
So far this tutorial has been great! Impressive read. Just wish I had more time to devote to it NOW...

Anyway, I''ve got a semi-related question, about the various bitwise operators...

Teej, you''ve used a couple macros here to assemble color components into a single hex value, ie:
#define RGB16((r << 11) | (g << 5) | b)

But, say you wanted to deconstruct a hex value into it''s corresponding color components? Would something like this work, or am I in crack heaven?

#define R16((c & 0xFF0000) >> 11) // to get the Red component of a 16-bit pixel value ''c''
#define G16((c & 0x00FF00) >> 5) // to get the Grn component
etc.

??

(Just trying to get a better understanding of bitwise functions and bitmasks..

Thanks!

##### Share on other sites
AHHHHHHHHHHHHHHHHHHH!!!

I am so confused by this section.I feel like such a dunce because it seems everyone else is getting it right off the bat.First of all why would you do this??I mean denoting the color of a pixel ,pixel by pixel seems to be very tedious.

The road to hell is paved in good intentions

##### Share on other sites
quote:
Original post by Magnatz
Hey - great tutorial teej... I think Im finally starting to understand stuff.

Just one query - is there any particular reason for the extra bit being given to green in 16bit color mode? (as opposed to red or blue I mean)... just seems a bit random.

thanx.

The reason that the extra bit is given to green is because human eyes are more sensitive to the green wavelengths in the color spectrum than red and blue wavelengths. Therefore it makes sense to add more variation to the color that we will notice the most.

[edited by - gavin_burt on July 26, 2002 12:16:02 PM]