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

High Speed Win32 Animation


August 1996/High Speed Win32 Animation/Listing 1

Listing 1: The demo program


/* MAIN.C by Jeff Heaton - Demo of how 
   to interface to the Sprite Routines */
#include "sprite.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

/* Global defines */
#define NUM_SPRITES 8
#define Random(range) \
    ((int)((double)range* \
    ((double)rand()/ \
    (double)RAND_MAX)))

/* Global Variables */

/* The class name and application names, instance */
char *szClassName = "STARDEMO";
char *szAppName = "Stars Demo";
HANDLE hInstance;

/* The master bitmap, made by CreateDIBSection */
HBITMAP dibSect = NULL;    
BITMAPINFO *info = NULL;    
BYTE *bitmap;

/* The palette created from STARS.BMP's color table */
HPALETTE hp=NULL;

/* Pixel number of frames, size and pixel map */
extern struct SPRITE *firstSprite;
int maxFrames,spriteSize;
BYTE *spritePattern=NULL;

int fps,tfps;/* Calculate frames-per-second */
/* A brush to fill the client background, and the
   size of the background */
RECT clientSize;
extern struct SPRITE *firstSprite;

/* LoadSprites - Load the sprite images in from STARS.BMP */
BOOL LoadSprites(void)
{
int     i,iSysColors,iPalEntries,j;
BYTE     table[256],*flipPattern;
FILE     *fp;
BITMAPFILEHEADER fhdr;
BITMAPINFOHEADER starInfo;
LOGPALETTE     *pal;
HDC     hdcScreen;
HWND     hwndScreen;
HPALETTE oldPal;
PALETTEENTRY pe[256];
RGBQUAD quad[256],*qptr;
WORD     *qd;
BYTE     *s,*d;

    hp=NULL;
/* Read in STARS.BMP and allocate enough memory */
/* Also, make sure STARS.BMP is in the right format */
    fp=fopen("STARS.BMP","rb");
    if( fp == NULL ) {
        MessageBox(NULL,
            "Can't open STARS.BMP.",
            szAppName,MB_ICONSTOP);
        return FALSE;
    }
    
    fread( &fhdr, sizeof(BITMAPFILEHEADER), 1, fp);
    fread( &starInfo, sizeof(BITMAPINFOHEADER), 1, fp);
    if( starInfo.biBitCount != 8 ) {
        MessageBox(NULL,
            "STARS.BMP must be stored as a 8-bit"
            "(256 color) bitmap.",szAppName,MB_ICONSTOP);
        return FALSE;
    }

    if( starInfo.biCompression != BI_RGB ) {
        MessageBox(NULL,"STARS.BMP must not be compressed,"
            " and have a palette.",szAppName,MB_ICONSTOP);
        return FALSE;
    }

    memset( quad, 0,  sizeof(RGBQUAD) * 256 );
    fread(quad, sizeof(RGBQUAD) * starInfo.biClrUsed, 1, fp);
    spritePattern = malloc( starInfo.biWidth * starInfo.biHeight );
    flipPattern = malloc( starInfo.biWidth * starInfo.biHeight );
    fread( flipPattern, starInfo.biWidth * starInfo.biHeight, 1, fp);
    fclose(fp);

    maxFrames = starInfo.biHeight / starInfo.biWidth;
    spriteSize = starInfo.biWidth;

    // Now flip all sprites(BMP's are stored upside down)
    for(i = 0;i < maxFrames; i++){
        s = flipPattern + (spriteSize * spriteSize * i )
 +( (spriteSize-1) * spriteSize);// Address of bottom row
        d = spritePattern + ( spriteSize * spriteSize * i );
        
        for( j = 0 ; j < spriteSize ; j++) {
            memcpy( d, s ,spriteSize);
            s -= spriteSize;
            d += spriteSize;
        }
    }
    free(flipPattern);

/* Allocate enough, or perhaps just a bit more than 
    enough memory for info structure */

    info = malloc(sizeof(BITMAPINFOHEADER)+(256*sizeof(RGBQUAD)));
    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
       info->bmiHeader.biWidth = (clientSize.right/4L)*4L;
       info->bmiHeader.biHeight = -clientSize.bottom;
       info->bmiHeader.biPlanes = 1;
       info->bmiHeader.biBitCount = 8;
       info->bmiHeader.biCompression = BI_RGB;
       info->bmiHeader.biSizeImage = 0;
       info->bmiHeader.biXPelsPerMeter = 0;
       info->bmiHeader.biYPelsPerMeter = 0;
       info->bmiHeader.biClrUsed = 0;
       info->bmiHeader.biClrImportant = 0;

/* Get a window to realize the palette(that we just created) into */

    hwndScreen = GetActiveWindow();
    hdcScreen = GetDC(hwndScreen);

/* Does this device support palettes */

    if( GetDeviceCaps(hdcScreen, RASTERCAPS) & RC_PALETTE ) {
/* Convert the bitmap's color table into a palette */
        pal = malloc( sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256);
        pal->palVersion = 0x300;
        pal->palNumEntries = 256;
        for( i = 0; i < 256 ; i++) {
            pal->palPalEntry[i].peRed = quad[i].rgbRed;
            pal->palPalEntry[i].peBlue = quad[i].rgbBlue;
            pal->palPalEntry[i].peGreen = quad[i].rgbGreen;
            pal->palPalEntry[i].peFlags = 0;
        }
        hp = CreatePalette(pal);
        free(pal);
/* The following code is very important for using CreateDIBSection
    with the DIB_PAL_COLORS option.  This code transforms the above
    DIB's optimal palette into the true mix of the requested palette,
    and the 20(or so) reserved windows colors.  The resulting 
    palette, when selected, becomes BOTH the logical and physical
    palette.  Because of this we can save windows the processor
    expensive process of mapping a DIB's color tables to the physical
    palette.

    This, of course, means we have to readjust the DIB's
    pixel map to make it correct for the new color map.  
    This is done later */

/* Determine how many colors we have available, and how many
    are system(that Windows does not allow to be changed)*/

        iSysColors = GetDeviceCaps(hdcScreen, NUMCOLORS);
        iPalEntries = GetDeviceCaps(hdcScreen, SIZEPALETTE);

/* The following code causes Windows to correctly combine 
    our palette with the System palette */

        SetSystemPaletteUse(hdcScreen, SYSPAL_NOSTATIC);
        SetSystemPaletteUse(hdcScreen, SYSPAL_STATIC);

/* Realize our optimal palette */
        oldPal = SelectPalette(hdcScreen, hp, FALSE);
        RealizePalette(hdcScreen);
        SelectPalette( hdcScreen, oldPal, FALSE);

/* The system palette is now a combination of its 20 
    reserved colors, and our new optimal palette. We now
    read in this palette color data, and setup a new palette
    that is the same as the system palette we created. */

        GetSystemPaletteEntries(hdcScreen, 0, iPalEntries, pe);

        for( i = 0; i < iSysColors/2 ; i++)
            pe[i].peFlags=0;

        for( ;i<iPalEntries-iSysColors/2;i++)
            pe[i].peFlags=PC_NOCOLLAPSE;

        for( ;i<iPalEntries;i++)
            pe[i].peFlags=0;

/* Create our "identity" palette as a real palette */
        ResizePalette(hp,iPalEntries);
        SetPaletteEntries(hp,0,iPalEntries,pe);
        ReleaseDC(hwndScreen,hdcScreen);

/* Build a table that will allow us to convert the pixel
    map to the new color table. */
           
        for(i=0;i<=255;i++)
            table[i]=GetNearestPaletteIndex(hp,RGB(
                quad[i].rgbRed,
                quad[i].rgbGreen,
                quad[i].rgbBlue));

/* Now remap the pixel map to the new color table */
        for(i=0;i<(starInfo.biWidth*starInfo.biHeight);i++)
            spritePattern[i]=table[spritePattern[i]];

        qd=(WORD*)&info->bmiColors[0];
        for(i=0;i<=255;i++,qd++)
            *qd=(WORD)i;
    } else {
        qptr = &info->bmiColors[0];

        for(i = 0;i <= 255; i++, qptr++){
            qptr->rgbRed = quad[i].rgbRed;
            qptr->rgbGreen = quad[i].rgbGreen;
            qptr->rgbBlue = quad[i].rgbBlue;
        }
    }
    ReleaseDC(hwndScreen,hdcScreen);
    return TRUE;
}

/* not shown: functions RenderReset (in Listing 2) and function
   MoveSprite (on code disk) -- mb */
   
/* Window Procedure for the main window */
LRESULT CALLBACK MainWndProc(
    HWND hwnd, 
    UINT message, 
    WPARAM wParam, 
    LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc,memDC;
HBITMAP old;
struct SPRITE *sprite;
int i;
char str[80];

    switch(message)
    {
        case WM_CREATE:
            if(LoadSprites()) {
                SetTimer( hwnd, 2, 10, NULL);
                SetTimer( hwnd, 1, 1000, NULL);
                srand( (unsigned)time( NULL ) );
                for( i = 0 ; i < NUM_SPRITES; i++) {
                    sprite =
                         CreateSprite(spriteSize,spriteSize,
spritePattern); SpriteSetPos(sprite, Random(100), Random(100)); sprite->xd = Random(40)-30; sprite->yd = Random(40)-30; } } else { PostQuitMessage(0); return -1; } break; /* Each timer tick moves the sprites */ case WM_TIMER: if(wParam==1) { tfps = fps; fps = 0; } else { MoveSprite( hwnd, &clientSize); InvalidateRect( hwnd, NULL, FALSE); } break; case WM_PAINT: hdc=BeginPaint( hwnd, &ps); fps++; memDC = CreateCompatibleDC( hdc); old = SelectObject( memDC, dibSect); if(hp!=NULL) { SelectPalette( memDC, hp, FALSE); SelectPalette( hdc, hp, FALSE); RealizePalette(hdc); } FillRect( memDC, &clientSize, GetStockObject(BLACK_BRUSH)); RenderSprites(hwnd); sprintf(str,"%i Frames Per Second ",tfps); TextOut( memDC, 0, 0, str, strlen(str)); BitBlt(hdc, 0, 0, clientSize.right, clientSize.bottom, memDC, 0, 0, SRCCOPY); SelectObject(memDC,old); DeleteDC(memDC); EndPaint(hwnd,&ps); break; case WM_SIZE: GetClientRect(hwnd,&clientSize); RenderReset(hwnd); break; case WM_DESTROY: while(firstSprite!=NULL) DeleteSprite(firstSprite); if(info!=NULL) free(info); if(spritePattern!=NULL) free(spritePattern); if(hp!=NULL) DeleteObject(hp); if(dibSect!=NULL) DeleteObject(dibSect); PostQuitMessage(0); break; } return (DefWindowProc(hwnd, message, wParam, lParam)); } /* not shown: WinMain function (on code disk) -- mb */ /* End of File */

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.