Author: James McCue
Author's e-mail: aloiterer@juno.com
Author's homepage: Jim the loiterer's PC games, programming, & stuff

// this routine does clipping, in that it resets the values
// in rcRect, which are used in the call to BltFast...
// Again, not the neatest way
void Draw_Other_Objects(int right, int bottom)
{
LPDIRECTDRAWSURFACE pdds; // an alias we'll use to the
// tile to be used in BltFast!
RECT rcRect; // used by Bltfast, to determine what
// part of our "tiles/sprites" are drawn
HRESULT ddrval;
int actual_screen_x, // these are the actual screen coordinates
actual_screen_y; // for the upper left hand corner of each sprite
int left, top; // the left and top virtual coordinates of the
// viewport
int index;
for (index = 0; index<NUMCLOUDS; index++)
{
// start of assuming we won't need to clip
rcRect.left = 0;
rcRect.top = 0;
rcRect.right = CLOUD_WIDTH;
rcRect.bottom = CLOUD_HEIGHT;
// the right side and bottom of the viewport are
// sent, use the screenwidth and height to determine
// the left and top sides..
left = right - SCREEN_WIDTH;
top = bottom - SCREEN_HEIGHT;
// if at least a sliver of the cloud will be in view... then...
if ((cloud[index].x >= left-CLOUD_WIDTH) &&
(cloud[index].x < right) &&
(cloud[index].y >= top-CLOUD_HEIGHT) &&
(cloud[index].y < bottom))
{
// do we need to clip it to the left side of the viewport?
if (cloud[index].x < left)
{
actual_screen_x = 0;
rcRect.left = left-cloud[index].x;
}
else // apparently not...
{
actual_screen_x = cloud[index].x - left;
// how about the right side?
if (cloud[index].x > (right - CLOUD_WIDTH))
{
rcRect.right = right - cloud[index].x;
}
}
// do we need to clip it to the top of the viewport?
if (cloud[index].y < top)
{
actual_screen_y = 0;
rcRect.top = top-cloud[index].y;
}
else // nope...
{
actual_screen_y = cloud[index].y - top;
// how about the bottom?
if (cloud[index].y > (bottom - CLOUD_HEIGHT))
{
rcRect.bottom = bottom-cloud[index].y;
}
} // end else
pdds = lpddsenemy;
ddrval = lpddsback->BltFast( actual_screen_x,
actual_screen_y,
pdds,
&rcRect,
DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
} // end if not culled
} // end for cloud
} // end Draw_Other_Objects
A couple of other terms that are commonly heard in reference to both 2d and 3d graphics are CULLING and CLIPPING.
// this routine lays down all the tiles...
void Render_Scene(int right, int bottom)
{
LPDIRECTDRAWSURFACE pdds; // an alias we'll use to the
// tile to be used in BltFast!
RECT rcRect; // used for clipping tiles
HRESULT ddrval;
int start_left, start_top;
int start_right, start_bottom;
int start_x_cell, start_y_cell;
int render_it_x,render_it_y;
int clip_right, clip_bottom;
int which_cell,cell_x_save;
int num_x_tiles, num_y_tiles;
int x_offset, y_offset;
int orig_left_clip,orig_top_clip;
// my muddleheaded setup for the tile engine
start_left = right-SCREEN_WIDTH;
start_top = bottom-SCREEN_HEIGHT;
// find the cell of the "map" to inspect (the map is very close
// to the top of this source, you could have loaded it from a disk
// if you wished, later versions of this tile engine will do that
start_x_cell = start_left / CELL_X_SIZE;
start_y_cell = start_top / CELL_Y_SIZE;
// since we're tiling left to right, top to bottom, we only
// *really* need to keep the orig_left_clip, which is the clipping
// info for the left side of all the rows of tiles we'll be rendering
orig_left_clip = rcRect.left = start_left%CELL_X_SIZE;
orig_top_clip = rcRect.top = start_top%CELL_Y_SIZE;
// you know something, this might be a completely extraneous step..
start_right = (start_left+CELL_X_SIZE)%CELL_X_SIZE;
start_bottom = (start_top+CELL_Y_SIZE)%CELL_Y_SIZE;
if (start_right<=start_left)
rcRect.right = CELL_X_SIZE;
else
rcRect.right = start_right;
if (start_bottom<=start_top)
rcRect.bottom = CELL_Y_SIZE;
else
rcRect.bottom = start_bottom;
// get starting texture to draw with
cell_x_save = start_x_cell + (start_y_cell<<TILE_Y_NUM_SHIFT);
// we'll save it for calculating the starting tile for each row,
// because sometimes we'll be drawing more tiles accross than at other
// times, because the numbers I have chosen can draw 10 tiles to
// cover the screen, but if you
// move horizontally, you'll need 11
which_cell = cell_x_save;
x_offset = 0;
y_offset = 0;
num_x_tiles = ((SCREEN_WIDTH+start_left)/ CELL_X_SIZE) + 1;
num_y_tiles = ((SCREEN_HEIGHT+start_top)/ CELL_Y_SIZE) + 1;
// loop thru entire scene left to right, top to bottom
for (render_it_y = 0; render_it_y<num_y_tiles; render_it_y++)
{
x_offset = 0;
// get original start left clip for each x loop
rcRect.left = orig_left_clip;
// assume, for now, that we've got the whole tile
// to work with horizontally
rcRect.right = CELL_X_SIZE;
// draw tiles left to right
for (render_it_x = 0; render_it_x<num_x_tiles; render_it_x++)
{
pdds = lpddstextures[terrain_texture[which_cell]];
ddrval = lpddsback->BltFast( x_offset, y_offset, pdds, &rcRect, DDBLTFAST_WAIT );
// the following will only evaluate to a value other
// than CELL_X_SIZE once for every row of tiles
x_offset+=CELL_X_SIZE-rcRect.left;
++which_cell;
rcRect.left = 0;
rcRect.right = CELL_X_SIZE;
// determine where to kick out of the loop
// or just clip the right hand side of the rect
clip_right = SCREEN_WIDTH - x_offset;
if ((clip_right)<0)
break;
if ((clip_right)<CELL_X_SIZE)
if ((clip_right)==0)
{
++which_cell;
break;
}
else
rcRect.right = clip_right;
} // end for render_it_x
// this will only evaluate to a value other than CELL_Y_SIZE
// once...
y_offset+=CELL_Y_SIZE-rcRect.top;
cell_x_save += TILE_X_NUM;
which_cell = cell_x_save;
rcRect.top = 0;
rcRect.bottom = CELL_Y_SIZE;
// clip tiles w/ respect to Y screen boundary
clip_bottom = SCREEN_HEIGHT - y_offset;
if ((clip_bottom)<CELL_Y_SIZE)
if ((clip_bottom)<=0)
break;
else
rcRect.bottom = SCREEN_HEIGHT-y_offset;
} // end for render_it_y
} // Render_Scene
As with the first demo, the action is in this demo is in the source to Game Main(), but this time around, it's more of the "Higher Level" action type... Jeez! This may actually approach GOOD CODING STANDARDS in the end ; )
// SHORT MUSIC ROUTINES, THAT USE MCI //////////////////////////////////
void Open_Music(void)
{
char strCommandString[80];
MCIERROR ret;
sprintf(strCommandString,"open PASSPORT.MID type sequencer alias jazz");
ret = mciSendString(strCommandString, 0, 0, 0);
if (ret == 0)
music_enabled = TRUE;
} // end Open_Music
void Start_Or_Restart_Track(void)
{
MCIERROR ret;
if (music_enabled)
ret = mciSendString("play jazz from 0", 0, 0, 0);
if (ret)
music_enabled=FALSE;
} // end Start_Or_Restart_Track(void)
void Stop_Music(void)
{
MCIERROR ret;
if (music_enabled)
ret = mciSendString("stop jazz", 0, 0, 0);
} // end Stop_Music
void Close_Music(void)
{
MCIERROR ret;
if (music_enabled)
{
ret = mciSendString("stop jazz", 0, 0, 0);
ret = mciSendString("close jazz", 0, 0, 0);
} // end if music enabled
} // end close music
Running the demo
This ship should remind people of the AWESOME cardware game called STAR MINES - find it if you can - it's excellent! I don't intend to use this ship for the little "game" I'll be making out of this tile engine, but I figured using it for this demo would be okay.