directdraw and bitmaps part 3
Download
Skip this Video
Download Presentation
DirectDraw and Bitmaps Part 3

Loading in 2 Seconds...

play fullscreen
1 / 50

DirectDraw and Bitmaps Part 3 - PowerPoint PPT Presentation


  • 118 Views
  • 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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
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

UM-Dearborn

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

or

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

} BITMAPFILEHEADER;

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

} BITMAPFILEHEADER;

bitmap info section
Bitmap Info Section

typedef struct BITMAP_FILE_TAG

{

BITMAPINFOHEADER bmiHeader; // header info

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

} BITMAPINFO;

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

} BITMAP_FILE, *BITMAP_FILE_PTR;

load bitmap file
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)

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)

{

_lclose(file_handle); // close the file

return(0); // return error

} // end if

load bitmap file1
Load_Bitmap_File

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

// finally the image data itself

_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

// now read in the image

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

bitmap->bitmapinfoheader.biBitCount==16 ||

bitmap->bitmapinfoheader.biBitCount==24)

{

// delete the last image if there was one

if (bitmap->buffer)

free(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

_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);

} // end if

load bitmap file3
Load_Bitmap_File

// close the file

_lclose(file_handle);

// flip the bitmap

Flip_Bitmap(bitmap->buffer,

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

bitmap->bitmapinfoheader.biHeight);

// return success

return(1);

} // end Load_Bitmap_File

unload 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

free(bitmap->buffer);

// reset pointer

bitmap->buffer = NULL;

} // end if

// return success

return(1);

} // end Unload_Bitmap_File

flip bitmap
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)))

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

ddraw fill surface
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

DDRAW_INIT_STRUCT(ddbltfx);

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

return(1);

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

return(0);

// load it\'s palette into directdraw

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

return(0);

// clean the surfaces

DDraw_Fill_Surface(lpddsprimary,0);

DDraw_Fill_Surface(lpddsback,0);

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

lpddsbackground->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

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

Unload_Bitmap_File(&bitmap);

// seed random number generator

srand(GetTickCount()); 

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

return(0);

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

Unload_Bitmap_File(&bitmap);

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

aliens[0].frames[index];

scan image bitmap
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

*dest_ptr;

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

lpdds->Lock(NULL,

&ddsd,

DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,

NULL);

scan image bitmap1
Scan_Image_Bitmap

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

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

lpdds->Unlock(NULL);

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;

dest_rect.top = y;

dest_rect.right = x+width-1;

dest_rect.bottom = y+height-1;

// fill in the source rect

source_rect.left = 0;

source_rect.top = 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,

(DDBLT_WAIT | DDBLT_KEYSRC), NULL)))

return(0);

} // end if

else

{

// perform blit without color key

// blt to destination surface

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

return(0);

} // end if

transparency
Transparency
  • 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
transparency1
Transparency
  • 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
filtering
Filtering
  • 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
Game_Init

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

RECT dest_rect, // the destination rectangle

source_rect; // the source rectangle

// fill in the destination rect

dest_rect.left = x;

dest_rect.top = y;

dest_rect.right = x+width_dest-1;

dest_rect.bottom = y+height_dest-1;

// fill in the source rect

source_rect.left = 0;

source_rect.top = 0;

source_rect.right = width_src-1;

source_rect.bottom = height_src-1;

ddraw draw surface scaled2
DDRaw_Draw_Surface_Scaled

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

NULL)))

return(0);

} // end if

else

{

// perform blit without color keyblt to destination surface

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

&source_rect,(DDBLT_WAIT),

NULL)))

return(0);

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

} BLINKER, *BLINKER_PTR;

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

lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].off_color);

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

lpddpal->SetEntries(0,lights[id].color_index,1,&lights[id].off_color);

else

lpddpal->SetEntries(0,lights[id].color_index,1,&lights[id].on_color);

} break;

case BLINKER_RUN: // run the algorithm

{

// run thru database and process each light

// update color

lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].on_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

lpddpal->GetEntries(0,start_index,colors,work_pal);

// shift the colors

lpddpal->SetEntries(0,start_index+1,colors-1,work_pal);

// fix up the last color

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

// update shadow palette

lpddpal->GetEntries(0,0,MAX_COLORS_PALETTE,palette);

// return success

return(1);

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

COLORREF color, LPDIRECTDRAWSURFACE7 lpdds)

{

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

return(0);

// set the colors for the text up

SetTextColor(xdc,color);

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

SetBkMode(xdc, TRANSPARENT);

TextOut(xdc,x,y,text,strlen(text));

// release the dc

lpdds->ReleaseDC(xdc);

return(1); // return success

} // end Draw_Text_GDI

ad