Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!rutgers!ames!sdcsvax!ucsdhub!hp-sdd!hplabs!sdcrdcf!trwrb!scgvaxd!wlbr!etn-rad!jru From: jru@etn-rad.UUCP (John Unekis) Newsgroups: comp.sys.ibm.pc Subject: Re: Graphics driver Message-ID: <263@etn-rad.UUCP> Date: Fri, 28-Aug-87 17:16:26 EDT Article-I.D.: etn-rad.263 Posted: Fri Aug 28 17:16:26 1987 Date-Received: Sun, 30-Aug-87 09:00:07 EDT References: <1096@ark.cs.vu.nl> <2436@bnrmtv.UUCP> <1099@ark.cs.vu.nl> Reply-To: jru@etn-rad.UUCP (0000-John Unekis) Organization: Eaton Inc. IMSD, Westlake Village, CA Lines: 1285 In article <1099@ark.cs.vu.nl> lesmem@cs.vu.nl (Marco Lesmeister) writes: >... > Can somebody post a fast line drawing algorithm that >uses direct memory writes to CGA memory. I am posting some source code here which I yanked out of my blastcga game. Since no one wanted to buy the source, I figured I would just post it for free. This is not the complete game(sorry , I wrote the game stream-of- consciousness style, and there are no comments in the code, as soon as I find time to put some in I'll post it). Included here are the graphics routines for CGA/EGA boards in mono mode. Some notes: )you MUST compile with the large model (msc /AL) )before you call the vector routines you MUST call graphmode or dismode(6) to put the board into mono graphics mode (only once) )before you call the vector routines you MUST call setxdotyadd() to init the array of screen address offsets (only once) )before you call the rotate routine you MUST call init_cos() to init the sin and cosine arrays (only once) )you should link with a large stack segment (i.e. link /stack:30000 ) This is not a shell archive(sorry , ours is broke) you must pull it apart with vi. Happy hunting. mail questions to {voder | ihnp4}!wlbr!etn-rad!jru figures.h ####################### cut here ########################### /* This is the include file that drives the blastcga game, it includes parameters for the number of monsters and such, as well as screen limits and stuff. It contains structures which allow an object to be stored either as a series of x,y points or as a series of angle and radius polar coordinates */ struct object { int x_vel; int y_vel; int x_pos; int y_pos; int num_vertices; int x[50]; int y[50]; int alive; int state; int angle; }; struct polar_object { int angle[50]; int radius[50]; }; struct object monsters[10]; struct object ship; struct polar_object polar_ship; struct polar_object polar_bent; struct object specials[5]; struct polar_object polar_specials[5]; int monster_moves; int special_moves; int num_monsters; int num_specials; int num_loops; int num_ships; int energy; int delay; struct missile { int x_pos; int y_pos; int x_vel; int y_vel; int running; int state; }; struct missile missiles[20]; int num_missiles; int next_missile; int bounce; int magnet; int sound; int max_missile; int kill_monst; int kill_special; int olden; int gen_monster; int gen_special; #define MAX_MISSILE 20 #define MAX_MONSTER 10 #define MAX_SPECIAL 5 #define MAX_SHIPS 3 #define X_LIMIT1 40 #define X_LIMIT2 600 #define Y_LIMIT1 15 #define Y_LIMIT2 185 #define MON_X_COL 13 #define MON_Y_COL 5 #define SPC_X_COL 12 #define SPC_Y_COL 5 #define ALIVE 999 #define NEW 777 #define BENT 555 #define MONSTER_GEN 50 #define SPECIAL_GEN 100 xorobj.c ####################### cut here ########################### #include "figures.h" /* routine to exclusive or the lines of a figure with screen memory John Unekis 1/18/87 */ xorobj(p) struct object *p; { register int i,j,k; i = (*p).num_vertices - 1; for(j=0;j 0) && ((*p).x[j+1] > 0)) shortvec((*p).x[j],(*p).y[j],(*p).x[j+1],(*p).y[j+1]); } } shortvec.c ####################### cut here ########################### int yadd[200]; char xdot[8]; struct scrnmem { char scrn[16636]; } ; /* The screen memory when the CGA is in mono mode is organized as one bit per pixel, 80 bytes per line gives 640 pixels per line. The scan lines are taken alternately from two banks of 8K memory each. One block of 8K for even lines, one for odd lines . The screen memory begins at B800:0000 */ struct scrnmem * scrptr; /* this routine puts the physical address offset from the beginning of screen memory for each screen line (in mono mode CGA) into an array indexed by line number. The physical address of a pixel is BASE OF SCREEN MEMORY + yadd[line number] + X ADDRESS /8, and the pixel to set within the byte at that address is X ADDRESS mod 8 */ setxdotyadd() { int i,j,k; char a,b,c; /* start of screen memory */ scrptr = (struct scrnmem *) 0xb8000000; /* offset to each y-line */ for(i=0;i<200;i++) { j = i & 1; j = j * 0x2000; k = i >> 1; k = k * 80; yadd[i] = j + k; } /* for each bit pixel within a byte, create a byte with just that pixel on, to be xor'ed with byte on screen */ for(i=0;i<8;i++) { xdot[i] = 0x01 << (7 - i); } } /* Xor the screen memory with a dot at x,y (upper left is 0,0) */ xordot(x,y) int x,y; { int offst; offst = yadd[y]; offst += x >> 3; scrptr->scrn[offst] ^= xdot[x & 7]; } /* This routine will draw a vector up to 128 pixels long from x1,y1 to x2,y2 on the cga screen in mono mode. It uses a fixed point binary representation for the x and y offsets, where 8 bits is whole number and eight bits is fraction. The algorithm assumes that for any given line either dx/dy is fractional, or dy/dx is fractional. the routine figures out which is which, then if dy/dx is fractional we move x by one each time, and y by dy/dx, otherwise if dx/dy is fractional we move y by one each time, and x by dx/dy. The dot on the screen is xor'ed at the whole number portion of x,y . */ shortvec(x1,y1,x2,y2) int x1,y1,x2,y2; { int dx,dy,deltx,delty,i,j,k; /* the line always moves in the positive direction */ if(x1 > x2) dx = x1 - x2; else dx = x2 - x1; if(y1 > y2) dy = y1 - y2; else dy = y2 - y1; if(dx > dy) { delty = dy << 8; delty = delty / dx; if(y2 > y1) { if(x2 > x1) yfrac(x1,x2,1,y1,delty); else yfrac(x1,x2,-1,y1,delty); } else { if(x1 > x2) yfrac(x2,x1,1,y2,delty); else yfrac(x2,x1,-1,y2,delty); } } else { deltx = dx << 8; if(dy > 0) deltx = deltx / dy; else deltx = 0x0100; if(x2 > x1) { if(y2 > y1) xfrac(x1,deltx,y1,y2,1); else xfrac(x1,deltx,y1,y2,-1); } else { if(y1 > y2) xfrac(x2,deltx,y2,y1,1); else xfrac(x2,deltx,y2,y1,-1); } } } xfrac.c ####################### cut here ########################### int yadd[200]; char xdot[8]; struct scrnmem { char scrn[16636]; }; struct scrnmem * scrptr; /* draw a vector on the cga screen in monochrome mode, assuming that y moves by one each time , and x by fractional dx/dy */ xfrac(xstart,xdelt,ystart,yend,ydelt) int xstart,xdelt,ystart,yend,ydelt; { register int loop,yoff,xrun,xpos; loop = ystart; xrun = 0; while(loop != yend) { xpos = xstart + (xrun >> 8); yoff = yadd[loop]; yoff += xpos >> 3; scrptr->scrn[yoff] ^= xdot[xpos & 7]; loop += ydelt; xrun += xdelt; } } yfrac.c ####################### cut here ########################### int yadd[200]; char xdot[8]; struct scrnmem { char scrn[16636]; }; struct scrnmem * scrptr; /* draw a vector in cga mono assuming that x moves by one each time, and y moves by fractional dy/dx */ yfrac(xstart,xend,xdelt,ystart,ydelt) int xstart,xend,xdelt,ystart,ydelt; { register int loop,yoff,yrun; loop = xstart; yrun = 0; while(loop != xend) { yoff = yadd[ystart+(yrun >> 8)]; yoff += loop >> 3; scrptr->scrn[yoff] ^= xdot[loop & 7]; loop += xdelt; yrun += ydelt; } } laser.c ####################### cut here ########################### #include "figures.h" /* Routine to fire ships laser John Unekis 1/18/87 */ /* this is a long vector drawing routine from the blastcga game, it is used to draw the laser beam. If you ignore the code that checks for hits on the monsters, it shows how to draw a long fast vector , assuming that either dx/dy or dy/dx is fractional. This routine differs from the short vector routines in that it uses 32 bits for dx/dy and dy/dx, with 16 bits fractional and 16 bits whole number. This allows it to draw a line across the whole screen, but it is just a bit slower. */ laser() { int x_start,y_start,x,y,i,j,k,l,m,n; int ptx[1000],pty[1000],pts,hit,incs; int notes; union lll{ int ii[2]; long ll; } il; union lll xrun; union lll yrun; union lll xdelt; union lll ydelt; yrun.ll = 0; xrun.ll = 0; hit = 0; incs = 0; pts = 0; x_start = ship.x_pos; y_start = ship.y_pos; m = ship.angle; i = sin(m); j = cos(m); ydelt.ii[1] = i ; xdelt.ii[1] = j ; if(i > 0) k = i; else k = -i; if(j > 0) l = j; else l = - j; il.ll = 0; if(k > l) il.ii[0] = k; else il.ii[0] = l; xdelt.ll = xdelt.ll / il.ll; ydelt.ll = ydelt.ll / il.ll; yrun.ii[1] = y_start; xrun.ii[1] = x_start; notes = 0; if(sound != 0) high_note('G'); /* we check for hits on objects as we draw the vector */ while (hit == 0) { x = xrun.ii[1]; y = yrun.ii[1]; xordot(x,y); /* draw the point and save the x,y pair for later erasure */ ptx[pts] = x; pty[pts] = y; pts += 1; incs += 1; if(incs >= 8) { incs = 0; if(((x > X_LIMIT2) || (x < X_LIMIT1)) || ((y > Y_LIMIT2) || (y < Y_LIMIT1))) hit = 999; for(i=0;i 32 or this algorithm may overflow in the trig functions. To avoid this, one might divide the trig values by 10 before using */ rotobj(p,q,ang) struct object *p; struct polar_object *q; int ang; { register int k,l; int i,j,m,n; int y_off,x_off; (*p).angle += ang; if( (*p).angle < 0 ) (*p).angle += 360; (*p).angle = (*p).angle % 360; n = (*p).num_vertices; for(i=0;i