02.05 - Resolution and Color Depth

Started by
21 comments, last by Teej 21 years, 1 month ago
Size Matters Let’s start by filling in some of the gaps that were left in Section 02.03 The Basic Windows Application. When discussing the process of registering a window class and creating a window for our application, I neglected to provide any details on what information Windows actually requires from us. You’ve surely noticed that there are two types of applications running under Windows – those that occupy a window on the desktop, and those that decide to take over the entire screen. As well, you have the ability to alter the resolution of your desktop and the number of displayable colors. Depending on how you want to display your game, you have some of these options available to you as well. In case you weren’t aware, screen resolution describes the number of pixels in width and height for the display. Common choices are 640x480 (640 pixels across, 480 pixels down – also known as VGA), 800x600, 1024x768 and 1280x1024. Color depth determines the amount of simultaneous colors available on the display. Common values are 8, 16, 24 and 32-bit color (more on this later in the article). Now, let’s look at one of your first decisions in creating a windows application – windowed or full-screen. Windowed Applications Applications choosing to run in windowed-mode supply the OS with their desired window’s width and height, background color and the desired position on the desktop for the new window (amongst other things). Some other options include the application’s icon, attributes such as the ability to resize the window, menu, scrollbars, etc. What you don’t get to choose is the screen resolution or the color depth. You see, all windows on the desktop have to live with whatever settings the user has already configured for the OS. When you think about it though, the ‘screen resolution’ for a windowed application is not really applicable; choosing the width and height of your window accomplishes the same thing (provided the user’s setting are sufficient). Color depth is an entirely different matter. This becomes important because your game needs to know how many bits are currently being used to compose a pixel’s color, and use the correct calculation. Your game is going to either have to be able to handle all of the popular choices, or restrict the user from running your game unless they adhere to your color depth recommendation. As well, if you allow the user to resize your window, be prepared to handle a ‘resolution change on the fly’. Face it, a windowed-game can be a real pain. Full-Screen Applications First, we let the OS know that we’re creating a special kind of window (a popup window) that has no extra frills, and then we direct the OS to have our window occupy the entire display surface. Since we’re the only thing visible at this point, we’re free to change the screen resolution and color depth to whatever the user’s hardware can support. If the focus leaves our application, that is to say, the user switches to another application, their resolution and color depth are restored until they rejoin us. Certainly you’ve seen this behavior in action when ‘ALT-TABbing’ in and out of a full-screen application. Design Choices and Our Game Regardless of what choices you make on how your game is going to look, you’re going to need to know the dimensions of your screen (or client area if windowed) and the color (bit) depth. These two parameters are important because we’re going to be manipulating memory – memory that represents a display surface. We need to be able to locate the piece of memory inside of the buffer that coincides with a particular pixel’s color. The next article will get you proficient in doing just that, but for now let’s look at the effect of resolution and color (bit) depth on display memory. Display Memory Think of the display surface as a two-dimensional array of pixels, with co-ordinates (0,0) indicating the top-left corner of the screen, and (x-1, y-1) being the bottom right corner. Therefore, if we have a screen resolution of 640x480, we have 307,200 pixels visible on the screen. Since the only attribute for a pixel is its color, what needs to be stored in memory is the current color of all 307,200 screen pixels. So, how much memory do we need to store an entire screen of pixel information? Well, that depends on how much memory each pixel requires. For example, if your pixels are two bytes wide (16-bit color), you’d require 307,200 x 2 bytes (= 614,400) of memory in order to store one full screen of pixel data. The likely scenario is that you’ll have a pointer to the beginning of a memory buffer, and will use this pointer to access the actual memory:

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.
Advertisement
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
---~khal
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.

Teej will talk about this later, I think.

Edited by - pazu on April 9, 2001 10:50:42 AM
Ja ne, Pazu mailto: pazu@animegaiden.com.brClose the world, open the neXt
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
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.
**Knowledge is Power**
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.
PiotyrSoftware Engineer by day, Game developer by nightThe early bird may get the worm, but the second mouse gets the cheese.
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 :

red = F000 (15 shades)
Green = 0FF0 (255 shades)
Blue = 000F (15 shades)

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."
When I find my code in tons of trouble,Friends and colleages come to me,Speaking words of wisdom:"Write in C."My Web Site
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
PiotyrSoftware Engineer by day, Game developer by nightThe early bird may get the worm, but the second mouse gets the cheese.
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)

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

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

  • 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

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

    This topic is closed to new replies.

    Advertisement