Author : Alexander Russell
Page : << Previous 3 Next >>
draw the text. We will implement this with three functions: text_init(), set_font(), and draw_char(). To draw a string of text we will call draw_char() repeatedly.
text_init() will call the video bios to get the address of the 8x8 ROM font, and the 8x14 ROM font and save both addresses to pointers so we can access them quickly. set_font() will simply select one of these fonts as our current font.
// graphic text global vars ----------------------------------------
int CharHeight;
int CharWidth;
unsigned char far *FontPtr; // pointer to current font
unsigned char far *F8x8Ptr; // pointers to the two VGA ROM fonts
unsigned char far *F8x14Ptr;
// get the address of the two VGA ROM fonts and save them.
// make the 8x8 font active
void text_init(void)
{
struct REGPACK reg;
reg.r_ax=0x1130; // 30 get info on current set, 11 character info
reg.r_bx=0x0300; // get 8x8 font info
intr(0x10, ®);
// es:bp points to 8x8 font
F8x8Ptr=MK_FP(reg.r_es, reg.r_bp);
reg.r_ax=0x1130; // 30 get info on current set, 11 font info
reg.r_bx=0x0200; // get 8x14 font info
intr(0x10, ®);
// es:bp points to 8x14 font
F8x14Ptr=MK_FP(reg.r_es, reg.r_bp);
// make the 8x8 font the active font
FontPtr=F8x8Ptr;
CharWidth=8;
CharHeight=8;
}
void set_font(int font_id)
{
if ( font_id == 0 )
{
FontPtr=F8x8Ptr;
CharWidth=8;
CharHeight=8;
}
else
{
if ( font_id == 1 )
{
FontPtr=F8x14Ptr;
CharWidth=8;
CharHeight=14;
}
else
{
// user defined font, not implemented
}
}
}
// c is the character to draw
// must call text_init first!
// this code assumes all fonts are 8 pixels wide, stored as a bitmapped byte
void draw_char(int c, int x, int y, int forecolour, int backcolour)
{
unsigned char far *p, far *fnt;
int width, height, adj;
unsigned char mask;
// make p point to the screen
p=off_screen + y*screen_width + x;
adj=screen_width - CharWidth;
// make fnt point to the start of the character we want to draw.
// characters are 1 byte wide, and height bytes tall
fnt=FontPtr + c*CharHeight;
height=CharHeight;
while ( height-- )
{
width=CharWidth;
mask=128; // bit mask: 10000000
while ( width-- ) // assumes width of 8
{
if ( (*fnt) & mask ) // is this bit set?
{
// draw pixel
*p++=forecolour;
}
else
{
// draw background colour
*p++=backcolour;
}
mask>>=1; // shift mask to check next bit
}
p+=adj; // next line on screen
fnt++; // next line of font
}
}
For anything but a test game you will want to create fonts that look nicer than the built in VGA fonts. To do this you have to create a font, load this font into memory, and write code to draw it. If you use the same format as the VGA fonts you can re-use the above code. Another option that makes text look nicer is to implement proportional fonts. That is, fonts were each character can be a different width. One easy way to do this is limit all characters to a maximum of 8 pixels, and store the width for each character in a separate table. Then the only change you make to the code is the check for the width.
Loading images from drawing programsAll the art for your game will be created in commercial drawing programs which will save their files in many different format, none of which will be convenient to use in a game. To use the art from drawing programs you must know the file format that the artwork is stored with, and how to convert the stored file into a linear bitmap. The general technique is: read the artwork into memory, convert it into a linear bitmap in memory, save the linear bitmap to disk in a in a format that is easy to use in the game. For large games the size of the art might mean you will want to store it compressed, and uncompress at runtime. For this course we will be storing all our sprites, and other game art as uncompressed linear bitmaps with a width and height header.
We will cover one simple file format now: PCX. PCX files are stored with a small header, RLE encoded artwork, and a 256 colour palette at the end. PCX files were originally for art less than 256 colours, and they just added the 256 colour palette at the end. The RLE encoding used for PCX files is very simply, but doesn't give very good compression. For information on other file formats try: http://www.wotsit.org
We will now develop a small program to read in PCX files, and write them out as linear bitmaps, or RLE bitmaps that can be directly load into memory, and drawn with the code we have already written.
The program will take command line parameters for the file names, and which format to write them out in.
Program Outline
Read one of the specified files into memory. Decode into a plain linear bitmap. If RLE is requested, convert to RLE. Save to disk.
MAKESPR.EXE USE: Makespr filename. [/r]
e.g.
makespr *.pcx /r
makespr *.pcx
makespr b*.pcx c*.pcx
makespr b*.pcx c*.pcx /r
Filename can contain wildcards. There can be any number of file names. If /r is used the output will be RLE sprites, otherwise plain sprites are saved.
The interesting functions are:
pack_shape();
unpack_pcx();
save_bitmap();
save_bitmap_rle();
main();
/*
makespr.c
Internet: alexad3@uniserve.com
Copyright 1998, October 5 by Alex Russell, ALL rights reserved
Created - 1998/10/5
History:
New file
*/
#include
#include
#include
#include
#include
#include
#include
#include
// a simple sprite
typedef struct
{
unsigned short width, height;
unsigned char far *bitmap;
}
shape_t;
// for all pcx files (far as I know)
typedef struct
{
char manu; /// usually 10
char version;
char encoding;
char bits_per_pixel;
int xmin, ymin, xmax, ymax;
int hres, yres;
char palette[48]; // not used by 256 color pcx
char reserved;
char color_planes;
int bytes_per_line;
int palette_type;
char spare[58];
}
pcx_head_t;
#define PAL_SIZE 768
#define PCX_HD_SIZE 128
#define BSIZE 4096
// we are in medium model, so fread() expects a NEAR data pointer.
// Therefore we have to read the file into near mem, then copy it
// to the far buffer using _fmemcpy()
// allocate far memory, and load a file into that memory.
// only for files <64Kb in size!!!
unsigned char far *far_load(char *fname, unsigned int *size)
{
FILE *fp;
unsigned char *b;
unsigned char far *p, far *t1;
unsigned int u, i;
*size=0;
p=NULL;
fp=fopen(fname, "rb");
if ( fp )
{
u=filelength(fileno(fp));
*size=u;
p=farmalloc(u);
if ( p )
{
t1=p;
b=malloc(1024); // malloc 1Kb on the near heap
if ( b )
{
while ( u )
{
if ( u < 1024 )
{
i=fread(b, 1, u, fp);
if ( i == u )
{
_fmemcpy(t1, b, u);
u=0;
}
else
break; // error, quit
}
else
{
i=fread(b, 1, 1024, fp);
if ( i == 1024 )
{
_fmemcpy(t1, b, 1024);
t1+=1024;
u-=1024;
}
else
break; // error
}
}
free(b);
}
}
fclose(fp);
}
return p;
}
// used to write out the far bitmaps to file, just like fwrite(), but it accepts
// far pointers for `s'
/* ---------------------- far_fwrite() ------------------- March 10,1997 */
int far_fwrite(char far *s, unsigned int m, unsigned int n, FILE *fp)
{
long i=0;
int j;
char *b;
long size;
b=malloc(BSIZE);
if ( b )
{
size=(long )m*n;
while ( size )
{
if ( size >= BSIZE )
{
_fmemcpy(b, s, BSIZE);
size-=BSIZE;
j=BSIZE;
}
else
{
_fmemcpy(b, s, size);
j=size;
size=0;
}
i+=fwrite(b, 1, j, fp);
s+=j;
}
free(b);
}
else
printf("out of near mem\n");
return(i);
}
/*
pack a shape to speed up drawing TRANSPARENT shapes
run length encoded
0 byte next byte is number of bytes to skip
1 byte next byte is number of bytes to draw
only useful for TRANSPARENT SHAPES
all color zero areas will be transparent
MAX width and height is 255!!!!!
packed line by line for speed
this is NOT a good way to pack stuff if interested in saving space
returns size of packed bitmap
shp2->bitmap must already be allocated and big enough for the RLE sprite
*/
/* ---------------------- pack_shape() ------------------- April 15,1993 */
int pack_shape(shape_t *shp1, shape_t *shp2)
{
char far *s0, far *s1, far *t;
short num, x, y;
unsigned short size=0;
s0=shp1->bitmap;
s1=shp2->bitmap;
for
Page : << Previous 3 Next >>