Directdraw and bitmaps part 3
1 / 50

DirectDraw and Bitmaps Part 3 - PowerPoint PPT Presentation

  • Uploaded on

DirectDraw and Bitmaps Part 3. CIS 487/587 Bruce R. Maxim UM-Dearborn. Reading Bitmap Files. The process of reading bit maps from files involves reading header information and then reading byte data into memory

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
Download Presentation

PowerPoint Slideshow about 'DirectDraw and Bitmaps Part 3' - niveditha

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Directdraw and bitmaps part 3

DirectDraw and BitmapsPart 3

CIS 487/587

Bruce R. Maxim


Reading bitmap files
Reading Bitmap Files

  • The process of reading bit maps from files involves reading header information and then reading byte data into memory

  • The size of the memory region is determined the the color depth and screen dimensions from the header

Bitmap file header
Bitmap File Header

Bitmap file header

Bitmap info

Palette if palettized

Bitmap data

RGB Pixels


Indexed data

Bitmap file header1
Bitmap File Header

typedef struct tag8BITMAPFILEHEADFER


WORD bfType; // file type = 0xD42 for .BMP

DWORD bfSize; // file size in bytes

WORD bfReserved; // must be 0

WORD bfReserved2; // must be 0

DWORD bfOffBits; // length in bytes of header


Bitmap info header
Bitmap Info Header

typedef struct tagBITMAPINFOHEADER


DWORD biSize; // structure size in bytes

LONG biWidth; // bitmap width

LONG biHeight; // bitmap height (<0 upside down)

WORD biPlanes; // # color planes

WORD biBitCount; // # bits per pixel 1,4,8,16,24,32

DWORD biCompression; // compression type = BI_RGB for .bmp

DWORD biSizeIMage; // image size in bytes

LONG biXPelsPerMeter; // pixels per meter x-axis

LONG biYPelsPerMeter; // pixels per meter y-axis

DWORD biClrUsed; // # colors used in bitmap

DWORD biClrImportant; // # important colors


Bitmap info section
Bitmap Info Section

typedef struct BITMAP_FILE_TAG


BITMAPINFOHEADER bmiHeader; // header info

RGBQUAD bmiColors[1]; // palette if one is used


Bitmap data area
Bitmap Data Area

  • It is possible that the bitmap image was written line by line to the file “upside down”

  • It is also the case that the bitmap palette (if it exists) is written in RGB Quad which the reverse normal palette entries

  • It is easier to write your own bitmap loader than to tweak the data and try to use the LoadImage( ) function in Win32 API

Bitmap file tag

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


Load bitmap file

int Load_Bitmap_File(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)


// 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)


_lclose(file_handle); // close the file

return(0); // return error

} // end if

Load bitmap file1

// 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,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));

// now set all the flags in the palette correctly and fix the reversed

// BGR RGBQUAD data format

for (index=0; index < MAX_COLORS_PALETTE; 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

Load bitmap file2

// finally the image data itself


// now read in the image

if (bitmap->bitmapinfoheader.biBitCount==8 ||

bitmap->bitmapinfoheader.biBitCount==16 ||



// delete the last image if there was one

if (bitmap->buffer)


// allocate the memory for the image

if (!(bitmap->buffer=(UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))


_lclose(file_handle); // close the file

return(0); // return error

} // end if

// now read it in


} // end if

Load bitmap file3

// close the file


// flip the bitmap


bitmap->bitmapinfoheader.biWidth*(bitmap >bitmapinfoheader.biBitCount/8),


// return success


} // end Load_Bitmap_File

Unload bitmap file

int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)


// this function releases all memory associated with "bitmap"

if (bitmap->buffer)


// release memory


// reset pointer

bitmap->buffer = NULL;

} // end if

// return success


} // end Unload_Bitmap_File

Flip bitmap

int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)


// used to flip bottom-up .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)))


// copy image to work area


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


// return success


} // end Flip_Bitmap

Ddraw fill surface

int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)


DDBLTFX ddbltfx; // this contains the DDBLTFX structure 

// clear out the structure and set the size field


// set the dwfillcolor field to the desired color

ddbltfx.dwFillColor = color;

// ready to blt to surface

lpdds->Blt(NULL, // ptr to dest rectangle

NULL, // ptr to source surface, NA

NULL, // ptr to source rectangle, NA

DDBLT_COLORFILL | DDBLT_WAIT, // fill and wait

&ddbltfx); // ptr to DDBLTFX structure 

// return success


} // end DDraw_Fill_Surface

Loading 16 bit bitmap
Loading 16-Bit Bitmap

  • There is no palette to load

  • Very few paint programs actually create 16-bit bitmaps, so you may need to convert 24-bit to 16-bit before drawing

  • LaMothe’s Load_Bitmap_File( ) does all this work for you

Loading 24 bit bitmaps
Loading 24-Bit Bitmaps

  • This is simplest of the 3 cases

  • However since many graphics cards support 32-bit pixel data rather than 24-bit and extra byte is used for padding or alpha channeling

  • Again Load_Bitmap_File( ) does most of the work for you

Using offscreen surfaces
Using Offscreen Surfaces

  • Create a DirectDraw application

  • Create primary and secondary surfaces

  • Load bitmap into secondary surface

  • Load palette info in primary surface palette

  • Scan rectangles from regions on secondary surface and blit them to the primary surface

    Note: Steps 1 to 4 done in GameInit( ) and

    ScanImage( ) used to extract animation frames

Game init
Game_Init( )

// create IDirectDraw interface 7.0 object and test for error

// set cooperation to full screen

// set display mode to 640x480x8

// we need a complex surface system with a primary and backbuffer

// set the backbuffer count field to 1

// request a complex, flippable

// create the primary surface

// now query for attached surface from the primary surface

// get the attached back buffer surface

// create the palette object

// finally attach the palette to the primary surface

// set clipper up on back buffer since that's where well clip

Game init1
Game_Init( )

// load the 8-bit image

if (!Load_Bitmap_File(&bitmap,"alley8.bmp"))


// load it's palette into directdraw

if (FAILED(lpddpal->SetEntries(0,0,MAX_COLORS_PALETTE,bitmap.palette)))


// clean the surfaces



// create the buffer to hold the background

lpddsbackground = DDraw_Create_Surface(640,480,0,-1);

// copy the background bitmap image to the background surface

// lock the surface


// get video pointer to primary surfce

UCHAR *image_buffer = (UCHAR *)ddsd.lpSurface;

Game init2
Game_Init( )

// copy memory from double buffer to primary buffer

// now unlock the primary surface

// unload the bitmap file, we no longer need it


// seed random number generator


// initialize all the aliens

// alien on level 1 of complex

aliens[0].x = rand()%SCREEN_WIDTH;

aliens[0].y = 116 - 72;

aliens[0].velocity = 2+rand()%4;

aliens[0].current_frame = 0;

aliens[0].counter = 0;

Game init3
Game_Init( )

// now load the bitmap containing the alien imagery

// then scan the images out into the surfaces of alien[0]

// and copy then into the other two, be careful of reference counts!

// load the 8-bit image

if (!Load_Bitmap_File(&bitmap,"dedsp0.bmp"))


// create each surface and load bits

for (int index = 0; index < 3; index++)


// create surface to hold image

aliens[0].frames[index] = DDraw_Create_Surface(72,80,0);

// now load bits...

Scan_Image_Bitmap(&bitmap, // bitmap file to scan image data from

aliens[0].frames[index], // surface to hold data

index, 0); // cell to scan image from

} // end for index

Game init4
Game_Init( )

// unload the bitmap file, we no longer need it


// now for the tricky part. There is no need to create more

// surfaces with the samedata, so you copy the surface

// pointers member for member to each alien

// however, be careful, since the reference counts do NOT go

// up, you still only need

// to release() each surface once!

for (index = 0; index < 3; index++)

aliens[1].frames[index] =

aliens[2].frames[index] =


Scan image bitmap

int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap, // bitmap file

LPDIRECTDRAWSURFACE7 lpdds, // surface to hold data

int cx, int cy) // cell to scan image from


// this function extracts a bitmap out of a bitmap file

UCHAR *source_ptr, // working pointers


DDSURFACEDESC2 ddsd; // direct draw surface description

// get the addr to destination surface memory

// set size of the structure

ddsd.dwSize = sizeof(ddsd);

// lock the display surface





Scan image bitmap1

// compute position to start scanning bits from

cx = cx*(ddsd.dwWidth+1) + 1;

cy = cy*(ddsd.dwHeight+1) + 1;

gwidth = ddsd.dwWidth;

gheight = ddsd.dwHeight;

// extract bitmap data

source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;

// assign a pointer to the memory surface for manipulation

dest_ptr = (UCHAR *)ddsd.lpSurface;

Scan image bitmap2

// iterate thru each scanline and copy bitmap

for (int index_y=0; index_y < ddsd.dwHeight; index_y++)


// copy next line of data to destination

memcpy(dest_ptr, source_ptr, ddsd.dwWidth);

// advance pointers

dest_ptr += (ddsd.lPitch); // (ddsd.dwWidth);

source_ptr += bitmap->bitmapinfoheader.biWidth;

} // end for index_y

// unlock the surface


Drawing blitter objects
Drawing Blitter Objects

int DDraw_Draw_Surface(LPDIRECTDRAWSURFACE7 source, // source surface to draw

int x, int y, // position to draw at

int width, int height, // size of source surface

LPDIRECTDRAWSURFACE7 dest, // surface to draw bob on

int transparent = 1) // transparency flag


// draw a bob at the x,y defined in the BOB

// on the destination surface defined in dest

RECT dest_rect, // the destination rectangle

source_rect; // the source rectangle

// fill in the destination rect

dest_rect.left = x; = y;

dest_rect.right = x+width-1;

dest_rect.bottom = y+height-1;

// fill in the source rect

source_rect.left = 0; = 0;

source_rect.right = width-1;

source_rect.bottom = height-1;

Drawing blitter objects1
Drawing Blitter Objects

// test transparency flag

if (transparent)


// enable color key blit

// blt to destination surface

if (FAILED(dest->Blt(&dest_rect, source,&source_rect,



} // end if



// perform blit without color key

// blt to destination surface

if (FAILED(dest->Blt(&dest_rect, source, &source_rect,(DDBLT_WAIT), NULL)))


} // end if


  • When your bitmap does not cover an entire rectangle you need to designate the background color as a transparent color so that screen in not wiped out when you blit

  • Most people use RGB black (0,0,0) when in RGB mode and color index 0 in palette color mode


  • Each pixel is tested for transparency as it is drawn

  • To keep black objects in the foreground you might decide that anything blue in the destination can’t be blitted

Color keying
Color Keying

  • One nice thing about Direct Draw is that you can control which colors are transparent and then the blitter handles testing pixels for transparency

  • Source key blits are accomplished by using SetColorKey( ) to make a range of colors transparent

  • Destination key are also possible but not used in the LaMothe text

Rotaton and scaling
Rotaton and Scaling

  • The Direct Draw allows blitting with size scaling, but does not allow blitting with rotation

  • To get the effect of blitting with rotation in Direct Draw you need to set up your bitmap frames to show the rotation

Scaling jaggies
Scaling (jaggies)

1x4 pixels 1x8 pixels

0 20 0 20

  • 5 1 20

  • 12 2 5

  • 85 3 5

    4 12

    5 12

    6 85

    7 85

Scaling data loss
Scaling (data loss)

1x4 pixels 1x2 pixels

0 20 0 20

  • 5 1 12

  • 12

  • 85


  • To avoid severe data loss you could use a could probability filter to select colors to copy (e.g. sample_rate = 4 / 3 = 1.33)

    0 12 0 0 12

    1 34 1.33 1 34

    2 56 2.66 2 56

    3 90

Game init5

// initialize all the aliens

// alien on level 1 of complex

aliens[0].x = rand()%SCREEN_WIDTH;

aliens[0].y = 116 - 72;

aliens[0].velocity = 2+rand()%4;

aliens[0].current_frame = 0;

aliens[0].counter = 0;

aliens[0].width = 72; // set real size

aliens[0].height = 80;

aliens[0].scale = ((float)(1+rand()%20))/10; // scale 0.1 to 2.0

// fix up feet so they still contact floor

aliens[0].y+=(72 - aliens[0].scale*72);

// do the same for each alien and then load bitmaps as before

Ddraw draw surface scaled

int DDraw_Draw_Surface_Scaled(LPDIRECTDRAWSURFACE7 source, // source

int x, int y, // position to draw

int width_src, int height_src, // size of source

int width_dest, int height_dest,// size of dest

LPDIRECTDRAWSURFACE7 dest, // surface to draw on

int transparent = 1) // transparency flag


// draw the surface at the x,y defined by dest, send both the original

// source size of surface, along with the desired size, if they are

// different then directdraw will scale the bitmap for you

// note that we are sending the size of the surface

Ddraw draw surface scaled1

RECT dest_rect, // the destination rectangle

source_rect; // the source rectangle

// fill in the destination rect

dest_rect.left = x; = y;

dest_rect.right = x+width_dest-1;

dest_rect.bottom = y+height_dest-1;

// fill in the source rect

source_rect.left = 0; = 0;

source_rect.right = width_src-1;

source_rect.bottom = height_src-1;

Ddraw draw surface scaled2

// test transparency flag

if (transparent)


// enable color key blitblt to destination surface

if (FAILED(dest->Blt(&dest_rect, source,

&source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),



} // end if



// perform blit without color keyblt to destination surface

if (FAILED(dest->Blt(&dest_rect, source,




} // end if

Blinking lights
Blinking Lights

  • The palette can be used to animate blinking lights

  • Basically, you need to pick 2 colors like 253 and 254

  • Then write code to toggle the colors in the bit map using SetEntries( )

Blinking lights1
Blinking Lights

// defines for Blink_Colors

#define BLINKER_ADD 0 // add a light to database

#define BLINKER_DELETE 1 // delete a light from database

#define BLINKER_UPDATE 2 // update a light

#define BLINKER_RUN 3 // run normal

// blinking light structure

typedef struct BLINKER_TYP


// user sets these

int color_index; // index of color to blink

PALETTEENTRY on_color; // RGB value of "on" color

PALETTEENTRY off_color; // RGB value of "off" color

int on_time; // number of frames to keep "on"

int off_time; // number of frames to keep "off" 

// internal member

int counter; // counter for state transitions

int state; // state of light, -1 off, 1 on, 0 dead


int green_id = -1, red_id = -1; // these hold the ids of blinkers

Blink colors
Blink_Colors( )

int Blink_Colors(int command, BLINKER_PTR new_light, int id)


// this function blinks a set of lights

static BLINKER lights[256]; // supports up to 256 blinking lights

static int initialized = 0; // tracks if function has initialized

// test if this is the first time function has ran

if (!initialized)


// set initialized

initialized = 1;

// clear out all structures

memset((void *)lights,0, sizeof(lights));

} // end if

Blink colors1
Blink_Colors( )

// clear out all structures

memset((void *)lights,0, sizeof(lights));

} // end if

// now test what command user is sending

switch (command)


case BLINKER_ADD: // add a light to the database


// update palette entry


} break;

  case BLINKER_DELETE: // delete light from database

// delete the light sent in id

if (lights[id].state != 0)


// kill the light

memset((void *)&lights[id],0,sizeof(BLINKER));

} break;

Blink colors2
Blink_Colors( )

case BLINKER_UPDATE: // update the light indicated by id

// update palette entry

if (lights[id].state == -1)




} break;

case BLINKER_RUN: // run the algorithm


// run thru database and process each light

// update color



default: break; 

} // end switch

Color rotation
Color Rotation

  • Easy way to simulate motion

  • Used to simulate flying through trenches on the Death Star

  • Done by retrieving a palette entry using GetEntries( )

  • The shifting the entry one place to the right and writing it back using SetEntries( )

Rotate colors
Rotate_Colors( )

int Rotate_Colors(int start_index, int end_index)


// this function rotates the color between start and end

int colors = end_index - start_index + 1;

PALETTEENTRY work_pal[MAX_COLORS_PALETTE]; // working palett

// get the color palette


// shift the colors


// fix up the last color

lpddpal->SetEntries(0,start_index,1,&work_pal[colors - 1]);

// update shadow palette


// return success


} // end Rotate_Colors

Mixing gdi and directx
Mixing GDI and DirectX

  • You are allowed to mix calls to these two libraries, but you need to do the work yourself since the cooperative level is set to “full screen, exlcusive”

  • The reason you might like to do this is that GDI is much better at drawing text than Direct Draw

Gdi options
GDI Options

  • Via high level controls (e.g. dialog boxes, message boxes, and avoiding graphic device contexts)

  • Via GDC (by requesting a GDC from inside DirectDraw using the function IDIRECTDRAWSURFACE)

  • Via one of the standard windowed modes, but writing games to work in windowed mode is tough

Draw text gdi
Draw_Text_GDI( )

int Draw_Text_GDI(char *text, int x,int y,



// this function draws the sent text on the sent surface

// using color index as the color in the palette

HDC xdc; // the working dc

// get the dc from surface

if (FAILED(lpdds->GetDC(&xdc)))


// set the colors for the text up


// set background mode to transparent so black isn't copied

SetBkMode(xdc, TRANSPARENT);


// release the dc


return(1); // return success

} // end Draw_Text_GDI