/usr/share/doc/libwmf0.2-7/caolan/dibs.html is in libwmf-doc 0.2.8.4-10.6.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | <BASE HREF="http://www.geocities.com/SiliconValley/2151/">
<!-- <SERVICE NAME="watermark"> -->
<SCRIPT LANGUAGE="javascript1.2" SRC="http://www.geocities.com/include/watermark/v2/lib.js"></SCRIPT>
<SCRIPT LANGUAGE="javascript1.2">
<!--
var args= new Array;
assignArrays("Computers & Technology", "Computers_and_Technology");
//-->
</SCRIPT>
<SCRIPT LANGUAGE="javascript1.2" SRC="http://www.geocities.com/include/watermark/v2/ns.js">
</SCRIPT>
<!-- </SERVICE> -->
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Microsoft FrontPage 2.0">
<title>Device-Independent Bitmaps and Palettes</title>
</head>
<body bgcolor="#FFFFFF">
<div align="center"><center>
<table border="0" width="100%" bgcolor="#00FFFF">
<tr>
<td><font color="#0000FF" size="4" face="Arial"><strong>Device-Independent
Bitmaps and Palettes</strong></font></td>
</tr>
</table>
</center></div>
<p><font size="2" face="Arial"><b>Introduction</b></font></p>
<p><font size="2" face="Arial">The purpose of this article is to
show how to create a Device-Independent Bitmap of a given format,
how to get a pointer to the memory bits that make up the image
and how to display it on screen regardless of the current display
mode.</font></p>
<p><font size="2" face="Arial"><strong>Pick a Flavor</strong></font></p>
<p><font size="2" face="Arial">When you create a DIB, you have to
specify the pixel format you want it in. In general there are two
"flavors":</font></p>
<ul>
<li><font size="2" face="Arial">Palette images</font></li>
<li><font size="2" face="Arial">RGB images</font></li>
</ul>
<p><font size="2" face="Arial">Palette images usually contain 256
colors. You supply a palette of 256 colors, and each pixel in the
image takes up one byte which is an index into the palette table.</font></p>
<p><font size="2" face="Arial">With RGB images you specify each
of the 3 RGB components for each pixel. RGB images are usually
16-bits or 24-bits per pixel.</font></p>
<p><font size="2" face="Arial"><strong>Setting up the Palette</strong></font></p>
<p><font size="2" face="Arial">If you want to display a 256 color
image then you'll need to set up a palette for it. We need this
palette information twice: once to create the bitmap, and again
to create a palette object we'll use when rendering to the
window. To keep things simple, I'm going to start out by
declaring a 256x3 array of bytes which we'll use later on. The
following code also initializes the entire palette to a smooth
gradiant from black to bright red:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Set up a palette
BYTE palette[256][3];
for (i=0; i<255; i++)
{
palette[i][0] = i; // red
palette[i][1] = 0; // green
palette[i][2] = 0; // blue
}</strong></font></pre>
<p><font size="2" face="Arial"><strong>Creating the Bitmap</strong></font></p>
<p><font size="2" face="Arial">There are several ways to create a
bitmap under Windows95, the most useful is probably with the <em>CreateDIBSection()</em>
function. <em>CreateDIBSection()</em> allows you to specify the
desired pixel format, and it returns both a handle to the bitmap
object and a pointer to the image memory.</font></p>
<p><font size="2" face="Arial">Before calling <em>CreateDIBSection()</em>
we must set up a BITMAPINFO structure for the desired pixel
format. The BITMAPINFO structure contains two fields: <em>bmiHeader</em>
(of type BITMAPINFOHEADER) and <em>bmiColors</em> (a one element
array of type RGBQUAD). The pixel format itself is stored in the
bmiHeader header field, while the bmiColors field is used to
store the first palette entry. Since this first example is for a
256-color bitmap, we need to allocate a structure containing
enough memory for the BITMAPINFO structure itself as well as an
extra 255 palette entries immediately after it (which we can then
access by indexing off the bmiColors field). The following code
will allocate the amount of memory we need:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Allocate enough memory for the BITMAPINFOHEADER and 256 RGBQUAD palette entries
LPBITMAPINFO lpbi;
lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))];</strong></font></pre>
<p><font size="2" face="Arial">Our next step is to initialize the
fields in the BITMAPINFOHEADER member <em>bmiHeader</em>.
BITMAPINFOHEADER contains the following fields:</font></p>
<ul>
<li><font size="2" face="Arial">biSize: the size of this
structure, set it to sizeof(BITMAPINFOHEADER).</font></li>
<li><font size="2" face="Arial">biWidth: the bitmap's width
in pixels.</font></li>
<li><font size="2" face="Arial">biHeight: the bitmap's height
in pixels.</font></li>
<li><font size="2" face="Arial">biPlanes: the number of
planes in the image. This should be set to 1 for both
palette and RGB bitmaps.</font></li>
<li><font size="2" face="Arial">biBitCount: the number of
bits per pixel. Set it to 8 for 256 color bitmaps, and 24
for 24-bit RGB bitmaps.</font></li>
<li><font size="2" face="Arial">biCompression: the type of
compression used. We don't want any compression, so set
it to BI_RGB for both bitmap flavors.</font></li>
<li><font size="2" face="Arial">biSizeImage: the size of the
image, in bytes. This is used for compressed bitmaps
where the image size is not a direct function of the
width and height of the image itself. Our bitmaps aren't
compressed, so we can set it to 0.</font></li>
<li><font size="2" face="Arial">biXPelsPerMeter and
biYPelsPerMeter: specifies the resolution of the bitmap.
We'll be displaying these on the screen, so set both
fields to 0.</font></li>
<li><font size="2" face="Arial">biClrUsed and biClrImportant:
these values are used to notify Windows of which colors
in the image are most important. I won't be covering this
topic in this article, so for now just set both to 0.</font></li>
</ul>
<p><font size="2" face="Arial">So the code to initialize the lpbi
structure should look something like this:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biWidth = width;
lpbi->bmiHeader.biHeight = height;
lpbi->bmiHeader.biPlanes = 1;
lpbi->bmiHeader.biBitCount = 8;
lpbi->bmiHeader.biCompression = BI_RGB;
lpbi->bmiHeader.biSizeImage = 0;
lpbi->bmiHeader.biXPelsPerMeter = 0;
lpbi->bmiHeader.biYPelsPerMeter = 0;
lpbi->bmiHeader.biClrUsed = 0;
lpbi->bmiHeader.biClrImportant = 0;</strong></font></pre>
<p><font size="2" face="Arial">The next step is to fill in the <em>bmiColors</em>
array. We do this by simply copying the values out of the palette
array we set up in the first step:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Set the bitmap palette
for (i=0; i<255; i++)
{
lpbi->bmiColors[i].rgbRed = palette[i][0];
lpbi->bmiColors[i].rgbGreen = palette[i][1];
lpbi->bmiColors[i].rgbBlue = palette[i][2];
lpbi->bmiColors[i].rgbReserved = 0;
}</strong></font></pre>
<p><font size="2" face="Arial">We are now ready to create the
bitmap. The <em>CreateDIBSection(</em>) function is declared as
follows:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>HBITMAP CreateDIBSection(HDC hdc,CONST BITMAPINFO *pbmi,UINT iUsage,VOID *ppvBits,HANDLE hSection,DWORD dwOffset)</strong></font></pre>
<p><font size="2" face="Arial">As you can see, the first
parameter is a device context. What we need here is the device
context for the screen, we can get it by calling <em>GetWindowDC(</em>)
and passing in NULL as the window handle. pbmi is a pointer to a
BITMAPINFO structure (ie our <em>lpbi</em> variable). iUsage is
an identifier that specifies the type of information we've filled
the palette with, so set it to RGB (do so for 24-bit images as
well). ppvBits should point to a variable of type LPBYTE, it will
be filled with a pointer to the bitmap's pixel memory. hSection
and dwOffset are used with file mapping objects, set them both to
0. The following code gets the screen dc, calls <em>CreateDIBSection()</em>
to create the bitmap then frees both the dc and the lpbi
structure we allocated:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>HDC hScreenDC = GetWindowDC(NULL);
hBitmap = CreateDIBSection(hScreenDC, lpbi, DIB_RGB_COLORS, (LPVOID *)&m_pBits, NULL, 0 );
ReleaseDC(NULL,hScreenDC);
delete [](BYTE *)lpbi;</strong></font></pre>
<p><font size="2" face="Arial">BTW, if you're using MFC then
you'll probably want to declare a variable of type CBitmap and
attach the bitmap handle to it with a call to the <em>Attach()</em>
member function.</font></p>
<p><font size="2" face="Arial"><strong>Creating a Palette Object</strong></font></p>
<p><font size="2" face="Arial">In order to display the bitmap on
screen we also need a palette object. The palette object is
created with a call to <em>CreatePalette()</em>, and we pass in a
pointer to a LOGPALETTE structure. LOGPALETTE contains the
following fields:</font></p>
<ul>
<li><font size="2" face="Arial">palVersion: indicates the
Windows version number. You should set this to 0x300.</font></li>
<li><font size="2" face="Arial">palNumEntries: the number of
indices in the palette. This should be set to 256.</font></li>
<li><font size="2" face="Arial">palPalEntry: an array of
PALETTEENTRY structures containing the palette
information.</font></li>
</ul>
<p><font size="2" face="Arial">The palPalEntry field contains a
single element of type PALETTEENTRY, so we need to do the same
trick we used when creating the bitmap to tack an extra 255
entries to the end of the LOGPALETTE structure. The following
code allocates the memory, fills it with the information from our
palette array and creates the palette object itself:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Create the palette object
LPLOGPALETTE lpLogPal;
lpLogPal = (LPLOGPALETTE)new BYTE[sizeof(LOGPALETTE) + 255*sizeof(PALETTEENTRY)];
lpLogPal->palVersion = 0x0300;
lpLogPal->palNumEntries = 256;
for (i=0; i<255; i++)
{
lpLogPal->palPalEntry[i].peRed = palette[i][0];
lpLogPal->palPalEntry[i].peGreen = palette[i][1];
lpLogPal->palPalEntry[i].peBlue = palette[i][2];
lpLogPal->palPalEntry[i].peFlags = 0;
}
hPalette = ::CreatePalette(lpLogPal);
delete [](BYTE *)lpLogPal;
</strong></font></pre>
<p><font size="2" face="Arial">If you're using MFC then you'll
probably want to attach the palette handle to a CPalette
variable. Or better yet, call the CPalette's CreatePalette()
member function and pass the <em>lpLogPal</em> variable into it.</font></p>
<p><font size="2" face="Arial"><strong>Displaying the Bitmap</strong></font></p>
<p><font size="2" face="Arial">The information presented in this
section is enough to display the bitmap if the user's display is
set to an RGB mode (eg 16 or 24 bits per pixel). However, it's <em>not</em>
enough for displaying in 256-color modes. To do that you need the
code in this section, plus handlers for an extra 2 windows
messages (which I'll show in the next section).</font></p>
<p><font size="2" face="Arial">To display the bitmap you
obviously need a device context for the window you're rendering
to. This is usually obtained by calling BeginPaint() in response
to a WM_PAINT message. The first task is to create a compatible
device context for the bitmap. This is done by calling <em>CreateCompatibleDC()</em>
and passing in the destination dc. Next, we need to select the
bitmap into it by calling <em>SelectObject()</em>. Don't forget
to save a copy of the bitmap handle it returns, you'll need to
select it back into the dc when you're done. Finally, we need to
select the palette into the destination dc, this is done with a
call to the <em>SelectPalette()</em> function.</font></p>
<p><font size="2" face="Arial">Before going any further, let me
explain a bit about the <em>SelectPalette()</em> function and how
it works. This function accepts a device context (the destination
dc in our case), a handle to the palette object itself and a
BOOLEAN variable called <em>bForceBackground</em>. <em>bForceBackground</em>
indicates to Windows what it should do with the palette object
we've just given it. If it's set to FALSE, then that means we
want windows to try and perfectly match as many of the palette
indices as possible. Windows normally reserves 20 palette entries
for itself and other applications may add their own entries to
the palette. If your application currently has the input focus
then you get palette priority over other programs, but Windows
still has priority over you to set the 20 reserved entries. When
you set a palette, Windows searches for any matches between your
palette entries and the entries in the current physical palette
(i.e. the actual palette that the screen is set to). If no match
is found, then what Windows does depends on the <em>bForceBackground
</em>parameter. If <em>bForceBackground</em> is set to FALSE,
then Windows will go ahead and pick the closest matching index
from the current physical palette. If it's set to TRUE then
Windows will find an empty entry in the physical palette and add
the new index to it. None of this really matters in 16 or 24 bit
modes, since Windows doesn't use a physical palette in those
modes. It makes a big difference though in 256-color modes, since
you want Windows to display as many of your palette colors as
possible. Note that if your window does not have the focus and
another window has set the palette, then Windows will map your
palette indices to that application's palette regardless of what <em>bForceBackground</em>
value you passed in.</font></p>
<p><font size="2" face="Arial">So obviously we want to always
pass in TRUE when we first call <em>SelectPalette()</em>, if our
window doesn't have the focus then it'll just be ignored anyway.
The function returns the handle to the previous palette, and when
we're done rendering we need to set that palette back into the
device context. In this second case though, we <em>don't</em>
want windows to go and change all the palette entries back to the
old palette, we want it to simply remap them to the palette we've
just set. So when we call <em>SelectPalette()</em> the second
time to restore the old palette, we want to pass in FALSE.</font></p>
<p><font size="2" face="Arial">With the palette set we can now
blt the bitmap to the destination dc. Here's some code that uses
BitBlt to display the bitmap:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Assume hPaintDC is a variable of type HDC, and the dc we're rendering to
HDC hBitmapDC = CreateCompatibleDC(hPaintDC);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
HPALETTE hOldPalette = SelectPalette(hPaintDC, hPalette, FALSE);
BitBlt(hPaintDC, 0, 0, BITMAP_WIDTH, BITMAP_HEIGHT, hBitmapDC, 0, 0, SRCCOPY);
SelectPalette(hPaintDC, hOldPalette, TRUE);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);</strong></font></pre>
<p><font size="2" face="Arial"><strong>Dueling Palettes</strong></font></p>
<p><font size="2" face="Arial">Windows is a multi-tasking
environment, and that means that at any given moment there are
typically numerous applications all fighting for control of the
palette. Windows has a very simple method of determining who gets
what: if your window has the input focus, then you get palette
priority, and all other windows have their palettes remapped to
yours. Windows loops through each index of all the other
palettes, finds the entry in your palette that's closest and
makes a note of it. Whenever one of those applications renders
something to the screen Windows looks up each pixel's value in an
internal table and draws the remapped color instead. Since the
other application is using your palette, it's not going to look
anywhere near as good as if it were using it's own, but at least
it's better than the alternative (i.e. a jumbled mess of pixels).</font></p>
<p><font size="2" face="Arial">Unfortunately it works both ways,
since you too are subject to having another application rip the
palette out from under your feet. In order to help you deal with
this in an effective manner, Windows provides two messages to
notify you of palette changes: WM_PALETTECHANGED and
WM_QUERYNEWPALETTE.</font></p>
<p><font size="2" face="Arial">WM_QUERYNEWPALETTE is sent
whenever your application gets the input focus, thus giving you a
chance to prepare the palette for rendering. When you select a
palette into a device context, Windows assigns each palette index
a space in the physical palette, but it does not actually go
ahead and make changes to the physical palette itself. To do that
you need to call the <em>RealizePalette()</em> function. The
correct way to handle the WM_QUERYNEWPALETTE message is to get
the device context for the window, select the palette into it
with <em>bForceBackground</em> set to FALSE (remember to save the
old palette handle), realize the palette, select the old palette
back in with <em>bForceBackground</em> set to TRUE and release
the device context. Here's the WM_QUERYNEWPALETTE handler code to
do all this:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>HDC hDC = GetWindowDC(hWnd);
HPALETTE hOldPalette = SelectPalette(hDC, hPalette, FALSE);
UINT nChanged = RealizePalette(hDC);
SelectPalette(hDC, hOldPalette, TRUE);
ReleaseDC(hWnd, hDC);</strong></font></pre>
<p><font size="2" face="Arial">(Note that we could avoid handling
this message by simply realizing the palette immediately after
the SelectPalette() call in the WM_PAINT handler. Realizing a
palette however is slow, so we may as well only do it when we
need to).</font></p>
<p><font size="2" face="Arial">WM_PALETTECHANGED is sent whenever
any application, including yours, causes changes to the physical
palette. If it's your own application doing the changing then you
should ignore this message, but if it's another application then
you need to realize your palette. Realizing the palette can be
done with the same code as used for the WM_QUERYNEWPALETTE
handler. Since this message is only handled when another window
has received the input focus, we should be able to to still pass
in a <em>bForceBackground </em>parameter of FALSE, since it'll be
ignored anyway. However, one document I read stated that it's
possible for the WM_PALETTECHANGED message to be sent to your
window <em>before</em> the other window has actually received the
input focus. If this happens and you're passing in FALSE, then
the other windows' palette will be messed up, so it's best to
stay on the safe side and pass in the correct value. When this
message is received, check the wParam value to see if it matches
your windows' HWND. If it's different, then realize the palette:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>HDC hDC = GetWindowDC(hWnd);
HPALETTE hOldPalette = SelectPalette(hDC, hPalette, TRUE);
UINT nChanged = RealizePalette(hDC);
SelectPalette(hDC, hOldPalette, TRUE);
ReleaseDC(hWnd, hDC);</strong></font></pre>
<p><font size="2" face="Arial">To avoid code duplication, you
should probably have each message call a function which accepts
the appropriate <em>bForceBackground</em> value and passes it
into the first <em>SelectPalette()</em> call.</font></p>
<p><font size="2" face="Arial">One last thing to keep in mind: if
the <em>RealizePalette()</em> function in either handler returns
non-zero, then you should invalidate and repaint your entire
client area. This is needed to fix any image degradation caused
when by another window changing the palette.</font></p>
<p><font size="2" face="Arial"><strong>True-Color Tyranny</strong></font></p>
<p><font size="2" face="Arial">24-bit DIBs are somewhat easier to
create than their 8-bit counterparts, since you no longer have to
worry about a palette. Displaying them is a bit different though
(that is, if want them to look semi-decent on a 256-color
display).</font></p>
<p><font size="2" face="Arial">To create a 24-bit bitmap you
simply set the <em>biBitCount</em> field of the BITMAPINFOHEADER
structure to 24. Since this bitmap doesn't require a palette, we
can use an actual BITMAPINFOHEADER structure instead of a
BITMAPINFO structure. The important thing to remember here is to <em>save
a copy of the BITMAPINFOHEADER variable</em>. You need it to
display the bitmap, for reasons which will become apparent in a
minute. Here's the code to create a 24-bit DIB:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>BITMAPINFOHEADER m_BitmapInfo; // <- this should be saved, eg make it a member variable
m_BitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
m_BitmapInfo.biWidth = BITMAP_WIDTH;
m_BitmapInfo.biHeight = BITMAP_HEIGHT;
m_BitmapInfo.biPlanes = 1;
m_BitmapInfo.biBitCount = 24;
m_BitmapInfo.biCompression = BI_RGB;
m_BitmapInfo.biSizeImage = 0;
m_BitmapInfo.biXPelsPerMeter = 0;
m_BitmapInfo.biYPelsPerMeter = 0;
m_BitmapInfo.biClrUsed = 0;
m_BitmapInfo.biClrImportant = 0;
HDC hScreenDC = GetWindowDC(NULL);
hBitmap = CreateDIBSection(hScreenDC, (LPBITMAPINFO)&m_BitmapInfo, DIB_RGB_COLORS, (LPVOID *)&m_pBits, NULL, 0);
ReleaseDC(NULL,hScreenDC);</strong></font></pre>
<p><font size="2" face="Arial">We no longer have to worry about
selecting and realizing palettes, so we can just go ahead and
select the bitmap into a device context and blt it to the
destination device<br>
in our WM_PAINT handler:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>HDC hBitmapDC = CreateCompatibleDC(hPaintDC);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
BitBlt(hPaintDC, 0, 0, BITMAP_WIDTH, BITMAP_HEIGHT, hBitmapDC, 0, 0, SRCCOPY);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);</strong></font></pre>
<p><font size="2" face="Arial">This works fine if the display is
in a true color mode, but if it's in a 256-color mode then
Windows maps each pixel to the closest entry in the physical
palette, i.e. usually one of it's 20 reserved entries. Needless
to say, it looks like crap! In theory, we should should be able
to call <em>SetStretchBltMode()</em>, <em>SetBrushOrgEx()</em>
and <em>StretchBlt()</em> to render with dithering. I have tried
and tried to get this to work, but to no avail. It may be a
feature that only certain drivers support. If so, I have yet to
find one that does!</font></p>
<p><font size="2" face="Arial">Fortunately, Video for Windows
provides a function for dithering DIBs. Instead of accepting the
bitmap's device context, it requires a pointer to the memory bits
and, lo-and-behold, it's BITMAPINFOHEADER structure (good thing
you saved it, huh?). To use video for windows you need to add the
following declarations to the top of your source. The first line
includes it's header file while the second links in the
appropriate lib file:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Include video for windows
#include
#pragma comment(lib, "vfw32.lib")</strong></font></pre>
<p><font size="2" face="Arial">We no longer need a device
context, so our display code is reduced to just 3 measly lines:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>HDRAWDIB hdd = DrawDibOpen();
DrawDibDraw(hdd, hPaintDC,0,0,BITMAP_WIDTH,BITMAP_HEIGHT,&m_BitmapInfo,m_pBits,0,0,BITMAP_WIDTH,BITMAP_HEIGHT,DDF_HALFTONE);
DrawDibClose(hdd);</strong></font></pre>
<p><font size="2" face="Arial">DrawDib apparently uses some kind
of pattern dither (Bayer?) to display images, but it does a
surprisingly good job of it. On my machine it's reasonably fast
too! In the past I've used it to emulate the primary surface in
debug builds of my DirectDraw code, since it allows me to display
16-bit images in a window even when I'm running in a 256-color
mode.</font></p>
<p><font size="2" face="Arial"><strong>Full-Screen Without
DirectX</strong></font></p>
<p><font size="2" face="Arial">If you want to develop high-speed
full-screen applications then you'll almost certainly want to use
DirectX. However, the techniques discussed in this file can be
used to develop full-screen apps, provided you don't try and
update too much of the screen each frame (otherwise it'll bog
down, particularly at higher resolutions).</font></p>
<p><font size="2" face="Arial">The first thing you'll probably
want to do is change the screen resolution. Win32 allows you to
do this on the fly <em>provided</em> that you don't try and
change the number of bits-per-pixel. I've already shown how to
handle different pixel depths, so only changing the resolution
will be adequate for our needs. Of course, if the user is running
in a 16 or 24-bit mode and you're rendering an 8-bit bitmap then
there'll be some slowdown since Windows has to convert it. The
code to change the display mode is as follows:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>SIZE m_sOldRes; // <-- save this somewhere</strong></font></pre>
<pre><font color="#008080" size="2" face="Arial"><strong>// Get current display mode
sOldRes.cx = GetSystemMetrics(SM_CXSCREEN);
sOldRes.cy = GetSystemMetrics(SM_CYSCREEN);
// Switch to our desired display mode
DEVMODE mode;
ZeroMemory(&mode, sizeof(mode));
mode.dmSize = sizeof(mode);
mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
mode.dmPelsWidth = SCREEN_WIDTH; // eg 640
mode.dmPelsHeight = SCREEN_HEIGHT; // eg 480
ChangeDisplaySettings(&mode, 0); <- don't forget to check the error returned here</strong></font></pre>
<p><font size="2" face="Arial">To change it back again once the
program has finished you simply plug in the old resolution
values:</font></p>
<pre><font color="#008080" size="2" face="Arial"><strong>// Restore old display mode
DEVMODE mode;
ZeroMemory(&mode, sizeof(mode));
mode.dmSize = sizeof(mode);
mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
mode.dmPelsWidth = sOldRes.cx;
mode.dmPelsHeight = sOldRes.cy;
ChangeDisplaySettings(&mode, 0);</strong></font></pre>
<p><font size="2" face="Arial">Finally, we need to create a
window that covers the entire screen, including the task bar.
This is easily done by creating a window with the WS_POPUP style
and maximizing it with a call to ShowWindow(hWnd,
SW_SHOWMAXIMISED).</font></p>
<div align="center"><center>
<table border="0" width="100%" bgcolor="#00FFFF">
<tr>
<td> </td>
</tr>
</table>
</center></div>
<pre><font size="2" face="Arial"><em>Copyright (c) 1997 </em></font><a
href="http://www.geocities.com/SiliconValley/2151"><font size="2"
face="Arial"><em>Mark Feldman</em></font></a><font size="2"
face="Arial"><em> (</em></font><a
href="mailto:pcgpe@geocities.com"><font size="2" face="Arial"><em>pcgpe@geocities.com</em></font></a><font
size="2" face="Arial"><em>) - All Rights Reserved</em></font></pre>
<pre><font size="2" face="Arial"><em>This article is part of </em></font><a
href="http://www.geocities.com/SiliconValley/2151/win95gpe.html"><font
size="2" face="Arial"><em>The Win95 Game Programmer's Encyclopedia</em></font></a></pre>
<pre><font size="2" face="Arial"><em>Please retain this footer if you distribute this file.</em></font></pre>
<div align="left">
<table border="0">
<tr>
<td><a href="graphics.html"><font size="2" face="Arial"><em><img
src="back.jpg" align="baseline" border="0" width="32"
height="32"></em></font></a></td>
<td><a href="graphics.html"><font size="2" face="Arial"><em>Back
to Graphics</em></font></a></td>
</tr>
</table>
</div>
</body>
</html>
<!-- <SERVICE NAME="pop"> -->
<SCRIPT LANGUAGE="javascript">
<!--
var cuid= "10197"; var keywords= "none";
// -->
</SCRIPT>
<DIV CLASS="GeoBrandingV2" ID="GeoBrandingV2" STYLE="position:absolute;top:1;visibility:hide;" ALIGN="right"><DIV CLASS="GeoBrandingV2" ID="GeoBrandingV2" TTYLE="position:absolute;top:1;visibility:hide;" ALIGN="right"><A HREF="http://www.geocities.com/?source=watermark&browser=NS" TARGET="_top"><IMG SRC="http://pic.geocities.com/images/watermark/v1/geocities.gif" ALT="Click Here!" WIDTH="107" HEIGHT="41" BORDER="0"></A></DIV>
|