· draw your bitmaps in cells
(frames) to keep them the same size
· must all use same color
values, bit-depth, palettes, etc.
· make size a power of 2 for
efficiency 32x16, 64x64
o
see my templates
loading bitmaps
//
bitmap loading software – “bitmapReader.H”
#define
WIN32_LEAN_AND_MEAN
#include
<windows.h>
#include
<windowsx.h>
#include
<iostream.h>
#include
<stdlib.h>
#include
<stdarg.h>
#include
<stdio.h>
#include
<math.h>
#include
<io.h>
#include
<fcntl.h>
#include
<signal.h>
#include
<float.h>
#define
BITMAP_ID 0x4D42 // this is the universal id for a bitmap
#define
_RGB16BIT(r,g,b) ((b%32)+((g%32)<<5)+((r%32)<<10))
//
container structure for bitmaps .BMP file
typedef
struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader; // this contains the bitmapfile header
BITMAPINFOHEADER bitmapinfoheader; // this is all the info including the palette
PALETTEENTRY palette[256]; // we will store the palette here
UCHAR *buffer; // this is a pointer to the data
} BITMAP_FILE, *BITMAP_FILE_PTR;
int
LoadBitmapFile(BITMAP_FILE_PTR bitmap, char *filename)
{ //
this function opens a bitmap file and loads the data into bitmap
int file_handle, // the file handle
index; // looping index
UCHAR *temp_buffer = NULL; // used to convert
24 bit images to 16 bit
OFSTRUCT file_data; // the file data information
// open the file if it exists
if ((file_handle =
OpenFile(filename,&file_data,OF_READ))==-1)
return(0);
// now load the bitmap file header
_lread(file_handle,
&bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
{ // close the file
_lclose(file_handle);
// return error
return(0);
} // end if
// now we know this is a bitmap, so read in
all the sections
// first the bitmap infoheader now load the
bitmap file header
_lread(file_handle,
&bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount ==
8)
{ _lread(file_handle,
&bitmap->palette,256*sizeof(PALETTEENTRY));
// now set all the flags in the palette
correctly and fix the reversed
// BGR RGBQUAD data format
for (index=0; index<256; index++)
{ // reverse the red and green fields
int temp_color =
bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue =
temp_color;
// always set the flags word to this
bitmap->palette[index].peFlags =
PC_NOCOLLAPSE;
} // end for index
} // end if
// finally the image data itself
_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
// now read in the image, if the image is 8
or 16 bit then simply read it
// but if its 24 bit then read it into a
temporary area and then convert
// it to a 16 bit image
if (bitmap->bitmapinfoheader.biBitCount==8
|| bitmap->bitmapinfoheader.biBitCount==16)
{ // allocate the memory for the image
if (!(bitmap->buffer = (UCHAR
*)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{ // close the file
_lclose(file_handle);
// return error
return(0);
} // end if
// now read it in
_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
} // end if
else
{ // this must be a 24 bit image, load it in
and convert it to 16 bit
printf("\nconverting 24 bit
image...");
// allocate temporary buffer
if (!(temp_buffer = (UCHAR
*)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{ //
close the file
_lclose(file_handle);
// return error
return(0);
} // end if
// allocate final 16 bit storage buffer
if (!(bitmap->buffer = (UCHAR *)malloc(2
* bitmap->bitmapinfoheader.biWidth * bitmap->bitmapinfoheader.biHeight)))
{ // close the file
_lclose(file_handle);
// release working buffer
free(temp_buffer);
// return error
return(0);
} // end if
// now read it in
_lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);
// now convert each 24 bit RGB value into a
16 bit value
for (index=0;
index<bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight;
index++)
{ // extract RGB components
UCHAR red = temp_buffer[index*3 + 0],
green = temp_buffer[index*3 + 1],
blue = temp_buffer[index*3 + 2];
// build up 16 bit color word
USHORT color = _RGB16BIT(red,green,blue);
// write color to buffer
((USHORT *)bitmap->buffer)[index] =
color;
} // end for index
} // end if
// write the file info out
printf("\nfilename:%s \nsize=%d
\nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
filename,
bitmap->bitmapinfoheader.biSizeImage, bitmap->bitmapinfoheader.biWidth,
bitmap->bitmapinfoheader.biHeight,
bitmap->bitmapinfoheader.biBitCount,
bitmap->bitmapinfoheader.biClrUsed,
bitmap->bitmapinfoheader.biClrImportant);
// close the file
_lclose(file_handle);
// return success
return(1);
} //
end Load_Bitmap_File
int
UnloadBitmapFile(BITMAP_FILE_PTR bitmap)
{ //
this function releases all memory associated with "bitmap"
if (bitmap->buffer)
{ // release memory
free(bitmap->buffer);
// reset pointer
bitmap->buffer = NULL;
} // end if
// return success
return(1);
} //
end Unload_Bitmap_File
int
FlipBitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip upside down
.BMP images
UCHAR *buffer; // used to perform the image
processing
int index;
// looping index
// allocate the temporary buffer
if (!(buffer = (UCHAR
*)malloc(bytes_per_line*height)))
return(0);
// copy image to work area
memcpy(buffer,image,bytes_per_line*height);
// flip vertically
for (index=0; index < height; index++)
memcpy(&image[((height-1) -
index)*bytes_per_line],
&buffer[index*bytes_per_line],
bytes_per_line);
// release the memory
free(buffer);
// return success
return(1);
} //
end Flip_Bitmap
To
Use:
#include
“bitmapReader.H”
void
main(void)
{ char
filename[80];
BITMAP_FILE bitmap;
bool more = true;
// load in .bmp files
while(more)
{
printf("\nenter filename to load or 'end' to stop?");
scanf("%s", filename);
if
(strcmp(filename, "end") != 0)
{ Load_BitmapFile(&bitmap,filename);
UnloadBitmapFile(&bitmap);
}
else
more = false;
} // end while
} //
end main
Example – bmp16Loader.cpp
// a
640x480x16 bitmap loader
#define
WIN32_LEAN_AND_MEAN
#include
<windows.h> // include important
windows stuff
#include
<windowsx.h>
#include
<mmsystem.h>
#include
<iostream.h> // include important C/C++ stuff
#include
<conio.h>
#include
<stdlib.h>
#include
<malloc.h>
#include
<memory.h>
#include
<string.h>
#include
<stdarg.h>
#include
<stdio.h>
#include
<math.h>
#include
<io.h>
#include
<fcntl.h>
#include
<ddraw.h> // directX includes
#include
"bitmapReader.h"
//
defines for windows
#define
WINDOW_CLASS_NAME "WINXCLASS"
// class name
#define
WINDOW_WIDTH 640 // size of window
#define
WINDOW_HEIGHT 480
#define
SCREEN_WIDTH 640 // size of screen
#define
SCREEN_HEIGHT 480
#define
SCREEN_BPP 16 // bits per pixel
//
these read the keyboard asynchronously
#define
KEY_DOWN(vk_code)((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define
KEY_UP(vk_code) ((GetAsyncKeyState(vk_code)
& 0x8000) ? 0 : 1)
typedef
unsigned short USHORT;
typedef
unsigned short WORD;
typedef
unsigned char UCHAR;
typedef
unsigned char BYTE;
int
GameInit(void *parms=NULL);
int
GameShutdown(void *parms=NULL);
int
GameMain(void *parms=NULL);
// GLOBALS
HWND
mainWindowHandle = NULL; // save the window handle
HINSTANCE
mainInstance = NULL; // save the instance
char
buffer[80]; // used to
print text
LPDIRECTDRAW lpdd = NULL; // dd object
LPDIRECTDRAWSURFACE lpddsprimary = NULL; // dd primary surface
LPDIRECTDRAWSURFACE lpddsback
= NULL; // dd back surface
LPDIRECTDRAWPALETTE lpddpal
= NULL; // ptr to created dd
palette
DDSURFACEDESC ddsd; // ddraw surface description
DDSCAPS ddscaps; // ddraw surf capabilities
HRESULT ddrval; // result back from dd calls
UCHAR *primary_buffer = NULL; //
primary video buffer
BITMAP_FILE bitmap16bit; // a 16 bit bitmap file
//
FUNCTIONS
LRESULT
CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{ //
this is the main message handler of the system
PAINTSTRUCT ps;
// used in WM_PAINT
HDC hdc; //
handle to a device context
// what is the message
switch(msg)
{
case WM_CREATE:
{
//
do initialization stuff here
return(0);
} break;
case WM_PAINT:
{
// start painting
hdc = BeginPaint(hwnd,&ps);
// end painting
EndPaint(hwnd,&ps);
return(0);
} break;
case WM_DESTROY:
{
//
kill the application
PostQuitMessage(0);
return(0);
} break;
default:break;
} // end switch
// process any messages that we didn't take
care of
return (DefWindowProc(hwnd, msg, wparam,
lparam));
} //
end WinProc
//
*************** WINMAIN *****************
int
WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int ncmdshow)
{
WNDCLASS winclass; // this will hold the class we create
HWND
hwnd; // generic window handle
MSG
msg; // generic message
HDC
hdc; // generic dc
PAINTSTRUCT ps; // generic paintstruct
// first fill in the window class stucture
winclass.style = CS_DBLCLKS | CS_OWNDC |
CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
// register the window class
if (!RegisterClass(&winclass))
return(0);
// create the window, note the use of
WS_POPUP
if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME,
// class
"WinX Game Console", // title
WS_POPUP | WS_VISIBLE,
0,0, // x,y
WINDOW_WIDTH, // width
WINDOW_HEIGHT, //
height
NULL, // handle to parent
NULL, // handle to menu
hinstance,// instance
NULL))) //
creation parms
return(0);
// hide the mouse
ShowCursor(FALSE);
// save the window handle and instance in a
global
mainWindowHandle = hwnd;
mainInstance = hinstance;
// perform all game console specific
initialization
GameInit();
// enter main event loop
while(1)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
// test if this is a quit
if (msg.message == WM_QUIT)
break;
// translate any accelerator keys
TranslateMessage(&msg);
// send the message to the window
proc
DispatchMessage(&msg);
} // end if
// main game processing goes here
GameMain();
} // end while
// shutdown game and release all resources
GameShutdown();
// return to Windows like this
return(msg.wParam);
} //
end WinMain
// WINX
GAME PROGRAMMING CONSOLE FUNCTIONS
int
GameInit(void *parms)
{
// this function is where you do all the
initialization
// for your game
// create object and test for error
if
(DirectDrawCreate(NULL,&lpdd,NULL)!=DD_OK)
return(0);
// set cooperation level to windowed mode
normal
if
(lpdd->SetCooperativeLevel(mainWindowHandle,
DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN
|
DDSCL_EXCLUSIVE |
DDSCL_ALLOWREBOOT)!=DD_OK)
return(0);
// set the display mode
if (lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP)!=DD_OK)
return(0);
// Create the primary surface
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)!=DD_OK)
return(0);
// now load the 16 bit color bitmap
LoadBitmapFile(&bitmap16bit,
"bmp.BMP");
// return success
return(1);
} //
end GameInit
int
GameShutdown(void *parms)
{
// this function is where you shutdown your
game and
// release all resources that you allocated
// first release the primary surface
if (lpddsprimary!=NULL)
lpddsprimary->Release();
// release the directdraw object
if (lpdd!=NULL)
lpdd->Release();
//
delete the bitmap
UnloadBitmapFile(&bitmap16bit);
// return success
return(1);
} //
end GameShutdown
int
GameMain(void *parms)
{
// this is the workhorse of your game it will
be called
// continuously in real-time this is like
main() in C
// all the calls for you game go here!
// check of user is trying to exit
if (KEY_DOWN(VK_ESCAPE) ||
KEY_DOWN(VK_SPACE))
PostMessage(mainWindowHandle,
WM_DESTROY,0,0);
// set up the surface description to lock the
surface
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
// lock the primary surface, note in a real
game you would
lpddsprimary->Lock(NULL,&ddsd,
DDLOCK_SURFACEMEMORYPTR |
DDLOCK_WAIT,NULL);
// get video pointer
primary_buffer = (UCHAR *)ddsd.lpSurface;
// copy each bitmap line into primary buffer
// taking into consideration non-linear video
// cards and the memory pitch lPitch
for (int y=0; y < SCREEN_HEIGHT; y++)
{
// copy the line
memcpy(&primary_buffer[y*ddsd.lPitch],
// dest address
&bitmap16bit.buffer[y*SCREEN_WIDTH*2], // src address
SCREEN_WIDTH*2); // bytes to copy
} // end for y
// unlock the surface
lpddsprimary->Unlock(primary_buffer);
// return success
return(1);
} //
end GameMain