www.pudn.com > Windows Game Programming Gurus Examp > blackbox.cpp


// BLACKBOX.CPP - Game Engine  
  
// INCLUDES /////////////////////////////////////////////////// 
 
#define WIN32_LEAN_AND_MEAN  // make sure all macros are included 
 
 
#include          // include important windows stuff 
#include   
#include  
 
#include         // include important C/C++ stuff 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include            // directX includes 
#include "blackbox.h"        // game library includes 
                                    
// DEFINES //////////////////////////////////////////////////// 
 
// TYPES ////////////////////////////////////////////////////// 
 
// PROTOTYPES ///////////////////////////////////////////////// 
 
// EXTERNALS ////////////////////////////////////////////////// 
 
extern HWND main_window_handle; // save the window handle 
extern HINSTANCE main_instance; // save the instance 
 
// GLOBALS //////////////////////////////////////////////////// 
 
LPDIRECTDRAW7         lpdd         = NULL;   // dd object 
LPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   // dd primary surface 
LPDIRECTDRAWSURFACE7  lpddsback    = NULL;   // dd back surface 
LPDIRECTDRAWPALETTE   lpddpal      = NULL;   // a pointer to the created dd palette 
LPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   // dd clipper 
PALETTEENTRY          palette[256];          // color palette 
PALETTEENTRY          save_palette[256];     // used to save palettes 
DDSURFACEDESC2        ddsd;                  // a direct draw surface description struct 
DDBLTFX               ddbltfx;               // used to fill 
DDSCAPS2              ddscaps;               // a direct draw surface capabilities struct 
HRESULT               ddrval;                // result back from dd calls 
DWORD                 start_clock_count = 0; // used for timing 
 
// these defined the general clipping rectangle 
int min_clip_x = 0,                          // clipping rectangle  
    max_clip_x = SCREEN_WIDTH-1, 
    min_clip_y = 0, 
    max_clip_y = SCREEN_HEIGHT-1; 
 
// these are overwritten globally by DD_Init() 
int screen_width  = SCREEN_WIDTH,            // width of screen 
    screen_height = SCREEN_HEIGHT,           // height of screen 
    screen_bpp    = SCREEN_BPP;              // bits per pixel 
 
// FUNCTIONS ////////////////////////////////////////////////// 
 
int DD_Init(int width, int height, int bpp) 
{ 
// this function initializes directdraw 
int index; // looping variable 
 
// create object and test for error 
if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)!=DD_OK) 
   return(0); 
 
// set cooperation level to windowed mode normal 
if (lpdd->SetCooperativeLevel(main_window_handle, 
           DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN |  
           DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)!=DD_OK) 
    return(0); 
 
// set the display mode 
if (lpdd->SetDisplayMode(width,height,bpp,0,0)!=DD_OK) 
   return(0); 
 
// set globals 
screen_height = height; 
screen_width  = width; 
screen_bpp    = bpp; 
 
// Create the primary surface 
memset(&ddsd,0,sizeof(ddsd)); 
ddsd.dwSize = sizeof(ddsd); 
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; 
 
// we need to let dd know that we want a complex  
// flippable surface structure, set flags for that 
ddsd.ddsCaps.dwCaps =  
  DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; 
 
// set the backbuffer count to 1 
ddsd.dwBackBufferCount = 1; 
 
// create the primary surface 
lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL); 
 
// query for the backbuffer i.e the secondary surface 
ddscaps.dwCaps = DDSCAPS_BACKBUFFER; 
lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback); 
 
// create and attach palette 
 
// create palette data 
// clear all entries defensive programming 
memset(palette,0,256*sizeof(PALETTEENTRY)); 
 
// create a R,G,B,GR gradient palette 
for (index=0; index < 256; index++) 
    { 
    // set each entry 
    if (index < 64)  
        palette[index].peRed = index*4;  
    else           // shades of green 
    if (index >= 64 && index < 128)  
        palette[index].peGreen = (index-64)*4; 
    else           // shades of blue 
    if (index >= 128 && index < 192)  
       palette[index].peBlue = (index-128)*4; 
    else           // shades of grey 
    if (index >= 192 && index < 256)  
        palette[index].peRed = palette[index].peGreen =  
        palette[index].peBlue = (index-192)*4; 
     
    // set flags 
    palette[index].peFlags = PC_NOCOLLAPSE; 
    } // end for index 
 
// now create the palette object 
if (lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256, 
                         palette,&lpddpal,NULL)!=DD_OK) 
   return(0); 
 
// attach the palette to the primary 
if (lpddsprimary->SetPalette(lpddpal)!=DD_OK) 
   return(0); 
 
// clear out both primary and secondary surfaces 
DD_Fill_Surface(lpddsprimary,0); 
DD_Fill_Surface(lpddsback,0); 
 
// attach a clipper to the screen 
RECT screen_rect = {0,0,screen_width,screen_height}; 
lpddclipper = DD_Attach_Clipper(lpddsback,1,&screen_rect); 
 
// return success 
return(1); 
} // end DD_Init 
 
/////////////////////////////////////////////////////////////// 
 
int DD_Shutdown(void) 
{ 
// this function release all the resources directdraw 
// allocated, mainly to com objects 
 
// release the clipper first 
if (lpddclipper) 
    lpddclipper->Release(); 
 
// release the palette 
if (lpddpal) 
   lpddpal->Release(); 
 
// release the secondary surface 
if (lpddsback) 
    lpddsback->Release(); 
 
// release the primary surface 
if (lpddsprimary) 
   lpddsprimary->Release(); 
 
// finally, the main dd object 
if (lpdd) 
    lpdd->Release(); 
 
// return success 
return(1); 
} // end DD_Shutdown 
 
///////////////////////////////////////////////////////////////    
 
LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds, 
                                      int num_rects, 
                                      LPRECT clip_list) 
 
{ 
// this function creates a clipper from the sent clip list and attaches 
// it to the sent surface 
 
int index;                         // looping var 
LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper 
LPRGNDATA region_data;             // pointer to the region data that contains 
                                   // the header and clip list 
 
// first create the direct draw clipper 
if ((lpdd->CreateClipper(0,&lpddclipper,NULL))!=DD_OK) 
   return(NULL); 
 
// now create the clip list from the sent data 
 
// first allocate memory for region data 
region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT)); 
 
// now copy the rects into region data 
memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects); 
 
// set up fields of header 
region_data->rdh.dwSize          = sizeof(RGNDATAHEADER); 
region_data->rdh.iType           = RDH_RECTANGLES; 
region_data->rdh.nCount          = num_rects; 
region_data->rdh.nRgnSize        = num_rects*sizeof(RECT); 
 
region_data->rdh.rcBound.left    =  64000; 
region_data->rdh.rcBound.top     =  64000; 
region_data->rdh.rcBound.right   = -64000; 
region_data->rdh.rcBound.bottom  = -64000; 
 
// find bounds of all clipping regions 
for (index=0; indexrdh.rcBound.left) 
       region_data->rdh.rcBound.left = clip_list[index].left; 
 
    if (clip_list[index].right > region_data->rdh.rcBound.right) 
       region_data->rdh.rcBound.right = clip_list[index].right; 
 
    if (clip_list[index].top < region_data->rdh.rcBound.top) 
       region_data->rdh.rcBound.top = clip_list[index].top; 
 
    if (clip_list[index].bottom > region_data->rdh.rcBound.bottom) 
       region_data->rdh.rcBound.bottom = clip_list[index].bottom; 
 
    } // end for index 
 
// now we have computed the bounding rectangle region and set up the data 
// now let's set the clipping list 
 
if ((lpddclipper->SetClipList(region_data, 0))!=DD_OK) 
   { 
   // release memory and return error 
   free(region_data); 
   return(NULL); 
   } // end if 
 
// now attach the clipper to the surface 
if ((lpdds->SetClipper(lpddclipper))!=DD_OK) 
   { 
   // release memory and return error 
   free(region_data); 
   return(NULL); 
   } // end if 
 
// all is well, so release memory and send back the pointer to the new clipper 
free(region_data); 
return(lpddclipper); 
 
} // end DD_Attach_Clipper 
 
/////////////////////////////////////////////////////////////// 
    
int DD_Flip(void) 
{ 
// this function flip the primary surface with the secondary surface 
 
// flip pages 
while(lpddsprimary->Flip(NULL, DDFLIP_WAIT)!=DD_OK); 
 
// flip the surface 
 
// return success 
return(1); 
 
} // end DD_Flip 
 
/////////////////////////////////////////////////////////////// 
 
DWORD Start_Clock(void) 
{ 
// this function starts the clock, that is, saves the current 
// count, use in conjunction with Wait_Clock() 
 
return(start_clock_count = Get_Clock()); 
 
} // end Start_Clock 
 
/////////////////////////////////////////////////////////////// 
 
DWORD Get_Clock(void) 
{ 
// this function returns the current tick count 
 
// return time 
return(GetTickCount()); 
 
} // end Get_Clock 
 
/////////////////////////////////////////////////////////////// 
 
DWORD Wait_Clock(DWORD count) 
{ 
// this function is used to wait for a specific number of clicks 
// since the call to Start_Clock 
 
while((Get_Clock() - start_clock_count) < count); 
return(Get_Clock()); 
 
} // end Wait_Clock 
 
/////////////////////////////////////////////////////////////// 
 
int DD_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color) 
{ 
DDBLTFX ddbltfx; // this contains the DDBLTFX structure 
 
// clear out the structure and set the size field  
DD_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 | DDBLT_ASYNC,   // fill and wait                    
           &ddbltfx);  // ptr to DDBLTFX structure 
 
// return success 
return(1); 
} // end DD_Fill_Surface 
 
///////////////////////////////////////////////////////////////    
 
int Draw_Rectangle(int x1, int y1, int x2, int y2, int color, 
                   LPDIRECTDRAWSURFACE7 lpdds) 
{ 
// this function uses directdraw to draw a filled rectangle 
 
DDBLTFX ddbltfx; // this contains the DDBLTFX structure 
RECT fill_area;  // this contains the destination rectangle 
 
// clear out the structure and set the size field  
DD_INIT_STRUCT(ddbltfx); 
 
// set the dwfillcolor field to the desired color 
ddbltfx.dwFillColor = color;  
 
// fill in the destination rectangle data (your data) 
fill_area.top    = y1; 
fill_area.left   = x1; 
fill_area.bottom = y2+1; 
fill_area.right  = x2+1; 
 
// ready to blt to surface, in this case blt to primary 
lpdds->Blt(&fill_area, // ptr to dest rectangle 
           NULL,       // ptr to source surface, NA             
           NULL,       // ptr to source rectangle, NA 
           DDBLT_COLORFILL | DDBLT_WAIT | DDBLT_ASYNC,   // fill and wait                    
           &ddbltfx);  // ptr to DDBLTFX structure 
 
// return success 
return(1); 
 
} // end Draw_Rectangle 
 
/////////////////////////////////////////////////////////////// 
 
int Draw_Text_GDI(char *text, int x,int y,int 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 (lpdds->GetDC(&xdc)!=DD_OK) 
   return(0); 
 
// set the colors for the text up 
SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue) ); 
 
// set background mode to transparent so black isn't copied 
SetBkMode(xdc, TRANSPARENT); 
 
// draw the text a 
TextOut(xdc,x,y,text,strlen(text)); 
 
// release the dc 
lpdds->ReleaseDC(xdc); 
 
// return success 
return(1); 
} // end Draw_Text_GDI 
 
///////////////////////////////////////////////////////////////