Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Ramblings in Real Time


SP95: RAMBLINGS IN REAL TIME

RAMBLINGS IN REAL TIME

The Day The World Changed

Michael Abrash

Michael is the author of numerous programming books, including Zen of Code Optimization. He can be contacted at [email protected].


This must have been what it was like for Jon Landau when he attended a concert at the Harvard Square Theater in 1974 and afterwards wrote, "I saw rock'n'roll future and its name is Bruce Springsteen."

Surely this is the way the people at Apple felt when they visited Xerox PARC, used a strange device called a "mouse" to move bitmapped windows around the screen, and suddenly glimpsed a future very different from the one they had envisioned just hours before.

We're talking the apes dancing around the monolith in 2001; an asteroid hitting the Earth and clearing the way for us mammals; a bunch of amino acids coming together in just the right way to create the first dim hint of life. What we're talking here is The Day The World Changed, if you catch my drift.

Let me explain.

At the Game Developers Conference in April 1994, there were rumors flying around about DOOM running under Windows. Given that DOOM was and is a DOS phenomenon sui generis, and that Windows had zero mindshare for real-time games, the rumors seemed improbable, to say the least, but they were confirmed when Microsoft urged people to stop by Chris Hecker's talk to see WinDOOM. So the room was packed with people expecting to see DOOM running under Windows--and still the crowd literally gasped when it actually happened. There was DOOM, running along in what was indisputably real time--in a window, with Program Manager, and Clock, and all the rest up there too. And in that moment I had one of those rare glimpses of the future--a future in which Windows becomes the mainstream, real-time graphics platform. That future is one in which all the rules of real-time graphics programming change, a future in which Mode X and SuperVGA and DOS extenders and adapter support and the other myriad complexities of DOS programming vanish.

You see, Windows is a DOS extender, it provides driver support in a generally device-independent way, and it attracts far more drivers than any other platform. The only thing missing for real-time graphics is fast, direct, double-buffered graphics-- or, rather, I should say "was," because that gap is now filled by WinG (pronounced win-GEE), the software that made WinDOOM possible. WinG does nothing more or less profound than support fast, double-buffered drawing on Win 3.1, Win32s, and Win32, and that's precisely the missing ingredient in making Windows an excellent real-time animation platform.

I know what you're thinking: Is that all? Is that what you're getting so excited about? Well, yes. Think of it this way. Right now, if you want to do real-time, 256-color graphics above 320x200 under DOS, you have to deal with the complexities of Mode X. If you want to go past 360x480, you have to deal with supporting dozens of different SuperVGAs, and you have to handle banked video memory. You also have to do all the drawing yourself, including text. Furthermore, you have to deal with protected mode somehow, plus input handling, and all the rest.

With WinG, the details of protected mode, devices, and input handling are handled by Windows, and 32-bit programming is a snap with Windows NT or Win32s or, soon, Windows 95, with tools galore available. Better yet, you can do all your drawing into a single, linear pixel buffer, with GDI's help, if you'd like, and then WinG will copy or stretch that buffer to the screen at memory bandwidth. No banking, no Mode X, no mode-set complexities, just the big, linear pixel buffer with 32-bit addressing that you've always dreamed of--and Windows is everywhere nowadays, so we're talking about a huge and rapidly growing installed base.

So sure, I think WinG is worth getting excited about, if for no other reason than because it means that game authors are well on their way to having a single, standard, hardware-independent PC environment in which to program. I have a more selfish reason for liking WinG, though; it allows me to have all of the code in this column draw to linear pixel buffers, freeing me to concentrate on challenging, high-level, real-time graphics issues rather than hardware- and OS-specific details. What I'm going to do this month is provide a quick overview of WinG, then present a simple, WinG-based animation program that will serve as the foundation for our future ramblings in real time. Once we've got that basic program in place, we can put just about any kind of graphics on top of it, without spending any more precious column space on low-level details. And believe me, column space is indeed precious--I can already think of more hardware-independent graphics topics than I could cover in a decade's worth of columns!

WinG

WinG is a set of binaries that can be used by any Win32, Win32s, or Win 3.1 ("Win 3.1" means WFW as well, in this column) app to get fast graphics. The problem solved by WinG is this: You--as a real-time graphics programmer--want fast, smooth graphics. That requires two things: a buffer in which to compose each new screen, and a way to get the pixels from each finished buffer onto the screen quickly. The typical way to do that under DOS is to draw the pixels to an off screen buffer with your own carefully optimized code, then display that buffer as quickly as possible, either by copying it to the screen or by page flipping. Although page flipping isn't available under Windows, copying a pixel buffer to the screen is certainly possible, but neither of the two standard Windows drawing surfaces--compatible bitmaps and Device Independent Bitmaps (DIBs)--provides everything needed for fast graphics.

DIBs give the app complete control over drawing, which is good. A DIB is a packed-pixel buffer into which Windows apps can draw directly, and which GDI can then copy or stretch to the screen. See the Win32 documentation on the MSDN CD, available from Microsoft, for an astonishing amount of information about DIBs and everything else about Windows programming; if you don't subscribe to MSDN, you should--it is the single most valuable Windows programming resource I've ever seen. However, DIBs can't be copied to the screen at memory bandwidth for a couple of reasons. First, each DIB comes with a color table (a table describing the colors to which the DIB pixel values correspond); the translation between the color table and the hardware palette must be recalculated every time a normal DIB is copied to the screen with SetDIBitsToDevice() or StretchDIBits(); see Figure 1. Then, too, a number of drivers don't implement the DIB APIs very efficiently. Also, under Windows NT, DIBs must go through the time-consuming process of being copied from the app's address space into GDI's address space, where the frame buffer resides. Finally, sometimes it's helpful to have GDI do some of the drawing, especially of text, so your app doesn't have to--but GDI can't draw into DIBs.

GDI can draw into compatible bitmaps, which don't have color-table or address-space problems and can be copied very efficiently--but apps can't draw directly into compatible bitmaps, as shown in Figure 1. That's a fatal flaw for real-time graphics.

WinG meets all the needs for real-time graphics by creating a hybrid of a DIB and a compatible bitmap, called a "WinGBitmap," as shown in Figure 2. On Win 3.1 and Win32s, WinG bitmaps are always in 8-bit-per-pixel DIB format but can work with any display mode; however, copies from a WinGBitmap to the screen are fastest when the screen is in 8-bpp mode.

There are three special things about WinGBitmaps. First, both the app and GDI can draw into them; the app has complete control whenever needed for performance or quality reasons, and GDI does the rest of the work.

Second, because WinGBitmaps are mapped into both the app and GDI address spaces under Windows NT, GDI can access them directly when copying, so no copying overhead is incurred in the process of getting the WinGBitmap's pixels onto the screen. (On Win 3.1 and Win32s, WinG will seek out and use the fastest possible way of copying WinGBitmaps to the screen.)

Third, a WinGBitmap's color table is set explicitly when the WinGBitmap is created and stays that way unless it is changed via WinGSetDIBColorTable(). As a result, the translation to screen colors can be cached, rather than recalculated every time the WinGBitmap is copied to the screen. (All translations are not created equal, though; an identity palette--as described and illustrated in detail in the WinG online help, and as implemented in the code in this column--is essential for best performance.)

Although it's a compact API, WinG offers a few extra goodies to complement WinGBitmaps. WinGBitmaps are selected into WinGDCs, which are passed to WinGBitBlt() and WinGStretchBlt() for maximum-speed copies of WinGBitmaps to the screen. WinG can also make a run-time recommendation about the fastest-bltting DIB orientation--top-down or bottom-up--for the current system. (This may sound arcane, but it's covered beautifully in the WinG help--and can make a big difference in performance.) WinG also provides a handy palette, with a 6-6-6 color set for halftoning, a good selection of grays, and a guaranteed identity mapping if used as shown in the WinG SDK (this is the palette used in Listing One). Finally, WinG can create halftoned brushes to approximate any arbitrary RGB color.

What's the downside of using WinG? Not much. The WinG software is free and freely redistributable (read the license agreement first, but that's what it amounts to), so the only cost is having to put somewhere around 300K of WinG binaries on your distribution disks. The other drawback is the lack of support for high-color pixel buffers under Win 3.1 and Win32s, as I'll discuss later.

Where can you get WinG? You can download it from ftp.microsoft.com:/developer/drg/wing/wing10.zip, or from the WinMM forum on CompuServe, or you can find it on the MSDN level-2 CD.

One key to effective use of WinG: Read the online help! It's excellent and thorough, so much so that I'm not going to discuss WinG programming in any more detail.

When all is said and done, it comes down to this: WinG provides the missing pieces for real-time graphics under Windows. Enough said.

WinG on Win32

WinG is not required on Win32 proper (excluding Win32s), because native Win32 APIs can do everything WinG does, except generate halftone brushes. (The palette created by Windows NT's CreateHalftonePalette() call differs from the WinG halftone palette, but any app can easily create a custom palette that matches the WinG palette.) On Win32, WinG is mostly a layer onto Win32 APIs such as CreateDIBSection(), SetDIBColorTable(), BitBlt(), and StretchBlt().

Nonetheless, even if you're developing only 32-bit apps, it often makes sense to use WinG. Apps don't lose any significant performance or features by using WinG on Win32, and WinG allows apps to run unmodified on Win32s; if I were writing a 32-bit Windows game right now, I'd certainly want to expand my potential market by having it run on Win32s. Better yet, if you should want to port the code to Win 3.1, you won't have to change the WinG calls at all. If you use WinG, your code will work well on all current and future x86 Windows platforms. (Note, however, that WinG doesn't run on RISC Windows NT platforms; there you'll have to use CreateDIBSection(). Also, be aware that neither WinG nor CreateDIBSection() works on any version of Windows NT prior to 3.5.)

CreateDIBSection() is a full-fledged part of GDI, so all DIB formats (1, 4, 8, 16, 24, and 32 bpp) are supported by the DIB sections (equivalent to WinGBitmaps) it creates. Because WinG is just a layer onto Win32 APIs on Win32, WinG, likewise, supports all DIB formats as WinGBitmaps on Win32.

Win32: Our Platform for Rambling

I'll work primarily with RGB modes in this column, because RGB is both a much simpler model to work with and the wave of the future for 3-D. The upcoming generation of low-cost 3-D accelerators will target RGB modes almost exclusively because it's difficult to do hardware acceleration of smooth-shaded texture maps in palettized modes. Consequently, the code I'll develop in this column will be Win32 code developed in Visual C++ 2.0, in large part so I can use the 16-bpp-and-up WinGBitmap formats that aren't supported on Win 3.1 and Win32s. The code in this column will mostly use direct-drawn graphics, so it will be reasonably easy to port it to Win32s and Win 3.1, but I'll develop and test it on Win32. Because the code is Win32-specific, it's actually not necessary to use WinG, but I'm going to use WinG anyway, to make it easier for you to get it running on Win32s and Win 3.1 if you want to, and so I can use the WinG halftone palette.

Why am I targeting Win32, when Win 3.1 is wildly popular right now? With Windows 95 and Windows NT, Win32 will clearly be the standard soon, and although neither of those systems is the standard today, I'm guessing that most of you readers, being developers, already have one or the other. Also, by not having to deal with the complications of 16-bit code, we'll be better able to focus on more interesting issues. Finally, the point of this column is real-time graphics, not Windows, and WinG in a 32-bit environment makes for very portable graphics code.

An Animation Framework

Listing One is a simple WinG-based animation program. Simple--but nonetheless complete, in the sense that it includes all the basic elements needed by a fast graphics application under Win32: a message loop, input handling, and, of course, direct drawing to a DIB that is then copied to the screen at high speed. (Set DRAW_DIRECT to 1 to draw directly into the WinGBitmap, or to 0 to have GDI do the drawing; this illustrates that WinGBitmaps support both sorts of drawing.) Listing One will be the foundation for the real-time graphics software that we'll develop from here on out.

Listing Two is the header file for Listing One, and Listing Three is the resource file. To build the sample program, put the files in a directory, start a new project in VC++ 2.0, add the CPP and RC files to the project, build, and run.

Listing One can run in any display mode, but the WinGBitmap itself is always 8 bpp in Listing One, because WinGRecommendDIBFormat() always returns a BITMAPINFOHEADER with biBitCount set to 8. However, you can, if you wish, set biBitCount to any valid DIB value to change a WinGBitmap's color depth on Win32.

Coming Up

I think the most interesting part of the industry right now is real-time 3-D, so that's where we'll head next. We'll put a polygon-based rendering layer on top of WinG, and we'll look at the really interesting stuff that sits on top of rendering: clipping, transforms, and, most of all, hidden-surface removal. We'll check out z-buffering, BSP trees (the heart of DOOM), octrees, and more. Somewhere in there, I'll try to get my X-Sharp package introduced in the "Graphics Programming" column of Dr. Dobb's Journal back in 1992 onto WinG, and let you know what I learned in the process.

I have seen the future of real-time PC graphics, and I'm heading there as fast as I can. I'd be delighted if you'd join me for the trip.

Figure 1 The two standard types of Windows drawing surface.

Figure 2 A WinGBitmap is a hybrid of a DIB and a compatible bitmap.

Listing One


// ANIMSAMP.CPP: Simple animation demo using WinG. Tested with
// Microsoft VC++ 2.0 running under Windows NT. Always draws to an
// 8-bpp DIB, but the results can be displayed at any color depth.
// Adapted from the Cube sample program in the WinG SDK.

#include <windows.h>
#include <windowsx.h>
#include <wing.h>
#include "animsamp.hpp"

#define DRAW_DIRECT     1   // 0 to draw boxes via GDI, 1 for direct
#define MIN_DIB_WIDTH   100 // minimum dimensions of WinGBitmap,
#define MIN_DIB_HEIGHT  100 //  to avoid out-of-bounds drawing
// A box is the only sort of object in the world we'll draw
#define NUM_BOXES   7
typedef struct _box {
    int X;
    int Y;
    int Width;
    int Height;
    int XInc;
    int YInc;
} box;
box Boxes[NUM_BOXES] = {
    {0, 0, 20, 20, 5, 5},
    {0, 0, 30, 10, 4, 7},
    {0, 0, 60, 24, 5, 9},
    {0, 0, 24, 24, 7, 7},
    {0, 0, 16, 30, 8, 1},
    {0, 0, 40, 20, 2, 6},
    {0, 0, 24, 30, 4, 2},
};
static char szAppName[]="Sample WinG animation demo";
static int      appActive;
static HWND     hwndApp;
static HPALETTE hpalApp = 0;
static HDC      hdcWinG;
static HBITMAP  hbmOld;
static HBITMAP  hbmWinG;
struct {
    BITMAPINFOHEADER    Header;
    RGBQUAD             aColorTable[256];
} HeaderAndPalette = {
    sizeof(BITMAPINFOHEADER), 50, 50, 1, 8, BI_RGB, 0, 0, 0, 0, 0
};
static int DibWidth, DibHeight, DibPitch;;
char *pBits;

LRESULT CALLBACK AppWndProc(HWND hwnd, UINT msg, WPARAM wParam,
    LPARAM lParam);
void AppExit(void);
int AppIdle(void);
void AppPaint(HWND hwnd, HDC hdc);

void ClearSystemPalette(void);

// Load time initialization.

int LoadInit(HINSTANCE hInst,HINSTANCE hPrev,int sw,LPSTR szCmdLine)
{
    WNDCLASS cls;

    ClearSystemPalette();   // Make sure we can get the whole palette

    if (!hPrev) {
        cls.hCursor        = LoadCursor(0, IDC_ARROW);
        cls.hIcon          = 0;
        cls.lpszMenuName   = "AppMenu";
        cls.lpszClassName  = szAppName;
        cls.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);
        cls.hInstance      = hInst;
        cls.style          = CS_BYTEALIGNCLIENT | CS_VREDRAW |
                             CS_HREDRAW;
        cls.lpfnWndProc    = (WNDPROC)AppWndProc;
        cls.cbClsExtra     = 0;
        cls.cbWndExtra     = 0;
        if (!RegisterClass(&cls))
            return FALSE;
    }

    hwndApp = CreateWindow (szAppName, szAppName,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, 0, 350,350, 0, 0, hInst, 0);
    hdcWinG = WinGCreateDC();
    ShowWindow(hwndApp, sw);
    return TRUE;
}

// Main proc and message pump.

int CALLBACK WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR szCmdLine,
    int sw)
{
    MSG msg;

    if (!LoadInit(hInst, hPrev, sw, szCmdLine)) // initialize the app
        return FALSE;

    // Pump messages until quitting time, letting the idle proc
    // draw, if possible, when there's nothing else to do.
    for (;;) {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        } else {
            if (AppIdle())
                WaitMessage();
        }
    }
    return msg.wParam;
}

// Idle loop; draws if the app is the active app or is an icon,
// does nothing otherwise.

int AppIdle()
{
    if (appActive || IsIconic(hwndApp)) {
        // Move all the objects
        for (int i=0; i<NUM_BOXES; i++) {
            // Bounce if at edge
            if (((Boxes[i].XInc < 0) &&
                ((Boxes[i].X + Boxes[i].XInc) < 0)) ||
                ((Boxes[i].XInc > 0) &&
                 ((Boxes[i].X + Boxes[i].Width + Boxes[i].XInc)
                 >= DibWidth))) {
                Boxes[i].XInc = -Boxes[i].XInc;
            }
            if (((Boxes[i].YInc < 0) &&
                 ((Boxes[i].Y + Boxes[i].YInc) < 0)) ||
                ((Boxes[i].YInc > 0) &&
                 ((Boxes[i].Y + Boxes[i].Height + Boxes[i].YInc)
                 >= DibHeight))) {
                Boxes[i].YInc = -Boxes[i].YInc;
            }
            Boxes[i].X += Boxes[i].XInc;
            Boxes[i].Y += Boxes[i].YInc;
        }
        // Draw the world with the new positions
        HDC hdc = GetDC(hwndApp);
        if (hpalApp) {
            SelectPalette(hdc, hpalApp, FALSE);
            RealizePalette(hdc);
        }
        AppPaint(hwndApp, hdc); // draw the world
        ReleaseDC(hwndApp, hdc);
        return FALSE;
    } else {
        return TRUE;    // nothing to do
    }
}

// Draws the current state of the world to the DIB (WinGBitmap),
// then copies the result to the passed-in DC (the screen).

void AppPaint(HWND hwnd, HDC hdc)
{
    // Clear the DIB to black
    PatBlt(hdcWinG, 0, 0, DibWidth, DibHeight, BLACKNESS);
#if DRAW_DIRECT
    GdiFlush(); // make sure this gets drawn right away, so it
                //  happens before the direct drawing (GDI batches
                //  drawing calls under Windows NT)
#endif

    // Draw the world (all the boxes) to the DIB
    for (int i=0; i<NUM_BOXES; i++) {
#if DRAW_DIRECT
        int Color = GetNearestPaletteIndex(hpalApp,
           RGB(((i+1)&0x04)*63, ((i+1)&0x02)*127, ((i+1)&0x01)*255));
        char *pTemp = pBits + (Boxes[i].Y * DibPitch) + Boxes[i].X;
        int Step = DibPitch - Boxes[i].Width;
        for (int j=0; j<Boxes[i].Height; j++) {
            for (int k=0; k<Boxes[i].Width; k++) {
                *pTemp++ = Color;
            }
            pTemp += Step;
        }
#else
        HBRUSH hbr;
        RECT rect;
        hbr = CreateSolidBrush(RGB(((i+1)&0x04)*63, ((i+1)&0x02)*127,
                ((i+1)&0x01)*255));
        rect.top = Boxes[i].Y;
        rect.left = Boxes[i].X;
        rect.bottom = Boxes[i].Y + Boxes[i].Height;
        rect.right = Boxes[i].X + Boxes[i].Width;
        FillRect(hdcWinG, &rect, hbr);
        DeleteObject(hbr);
#endif
    }

    // Copy the DIB to the screen.
    RECT rc;
    GetClientRect(hwndApp, &rc);
    if (IsIconic(hwndApp)) {
        WinGStretchBlt(hdc, 0, 0, rc.right, rc.bottom, hdcWinG, 0, 0,
                DibWidth, DibHeight);
    } else {
        WinGBitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcWinG, 0, 0);
    }
    GdiFlush(); // make sure this gets drawn right away
}

// Main window proc. Receives all messages.

LRESULT CALLBACK AppWndProc(HWND hwnd, UINT msg, WPARAM wParam,
    LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    int f;
    int counter;

    switch (msg) {
        case WM_CREATE: 
            // Use the WinG halftone palette
            hpalApp = WinGCreateHalftonePalette();
            GetPaletteEntries(hpalApp, 0, 256,
                (PALETTEENTRY *)HeaderAndPalette.aColorTable);

            for(counter = 0; counter < 256; counter++) {
                // PALETTEENTRYs and RGBQUADs are reversed
                BYTE Temp =
                       HeaderAndPalette.aColorTable[counter].rgbBlue;
                HeaderAndPalette.aColorTable[counter].rgbBlue =
                        HeaderAndPalette.aColorTable[counter].rgbRed;
                HeaderAndPalette.aColorTable[counter].rgbRed = Temp;
            }
            break;

        case WM_ACTIVATEAPP:            // track if app in foreground
            appActive = (int)wParam;
            break;
            
        case WM_COMMAND:
            switch(wParam) {
                case MENU_EXIT:
                    PostMessage(hwnd, WM_CLOSE, 0, 0L);
                    break;
            }
            return 0L;

        case WM_DESTROY:                // clean up before leaving
            if (hpalApp)
                DeleteObject(hpalApp);
            if (hdcWinG) {
                SelectObject(hdcWinG, hbmOld);
                DeleteObject(hbmWinG);
                DeleteDC(hdcWinG);
            }
            PostQuitMessage(0);
            break;

        case WM_PALETTECHANGED:
            if ((HWND)wParam == hwnd)
                break;
            // if not current window doing the changing, fall through

        case WM_QUERYNEWPALETTE:
            hdc = GetDC(hwnd);
            if (hpalApp)
                SelectPalette(hdc, hpalApp, FALSE);
            f = RealizePalette(hdc);
            ReleaseDC(hwnd, hdc);
            if (f)      // if we got a realization, force a redraw
                InvalidateRect(hwnd, 0, FALSE);
            return f;

        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            if (hpalApp) {
                SelectPalette(hdc, hpalApp, FALSE);
                RealizePalette(hdc);
            }
            AppPaint (hwnd, hdc);
            EndPaint(hwnd,&ps);
            return 0L;

        case WM_SIZE:
            if (wParam != SIZE_MINIMIZED) {
                // Create a WinGBitmap to match the client area
                if (hbmWinG) {
                    SelectObject(hdcWinG, hbmOld);
                    DeleteObject(hbmWinG);
                }
                RECT rect;
                GetClientRect(hwnd, &rect);

                // Set up the header for the WinGBitmap, making sure
                // it never gets so small that objects could draw
                // out-of-bounds
                WinGRecommendDIBFormat((BITMAPINFO *)
                        &HeaderAndPalette);
                DibWidth = (rect.right > MIN_DIB_WIDTH) ?
                        rect.right : MIN_DIB_WIDTH;
                DibPitch = (DibWidth+3) & ~0x03; // round up to dword
                DibHeight = (rect.bottom > MIN_DIB_HEIGHT) ?
                        rect.bottom : MIN_DIB_HEIGHT;
                HeaderAndPalette.Header.biWidth = DibWidth;
                HeaderAndPalette.Header.biHeight *= DibHeight;
                hbmWinG = WinGCreateBitmap(hdcWinG,
                        (BITMAPINFO *)&HeaderAndPalette,
                        (void **)&pBits);
                hbmOld = SelectBitmap(hdcWinG, hbmWinG);

                // If bottom-up bitmap, point to the top scan & make
                // the scan size negative to scan from top to bottom
                if (HeaderAndPalette.Header.biHeight > 0) {
                    pBits += (HeaderAndPalette.Header.biHeight - 1) *
                            DibPitch;
                    DibPitch = -DibPitch;
                }

                // Reset all the objects to the upper left to 
                // sure they're in the DIB
                for (int i=0; i<NUM_BOXES; i++)
                    Boxes[i].X = Boxes[i].Y = 0;
            }
    }
    return DefWindowProc(hwnd,msg,wParam,lParam);
}

// Fills and empties the system palette, so if this is the
// foreground app, it can be sure of grabbing all the non-static
// entries starting at entry #10.

void ClearSystemPalette(void)
{
    static struct {
        WORD Version;
        WORD NumberOfEntries;
        PALETTEENTRY aEntries[256];
    } Palette = {
        0x300,
        256
    };
  
    // Make the whole palette black, with nocollapse to force a
    // separate system palette entry for each black entry. The RGB
    // entries are statically initialized to zero
    for(int counter = 0; counter < 256; counter++)
        Palette.aEntries[counter].peFlags = PC_NOCOLLAPSE;

    // Realize the palette & discard it, to clear the system palette.
    HDC ScreenDC = GetDC(NULL);
    HPALETTE hpalScreen= CreatePalette((LOGPALETTE *)&Palette);
    if (hpalScreen) {
        hpalScreen = SelectPalette(ScreenDC, hpalScreen, FALSE);
        RealizePalette(ScreenDC);
        hpalScreen = SelectPalette(ScreenDC, hpalScreen, FALSE);
        DeleteObject(hpalScreen);
    }
    ReleaseDC(NULL, ScreenDC);
    return;
}



Listing Two


// ANIMSAMP.HPP: Header file for simple animation demo using WinG.
#define MENU_EXIT         1



Listing Three


// ANIMSAMP.RC: Resource file for simple animation demo using WinG.
#include <windows.h>
#include "animsamp.hpp"

AppMenu menu
begin
    POPUP "&File"
        begin
            MENUITEM "E&xit",                                   MENU_EXIT
        end
end


Copyright © 1995, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.