wolf3d

The original open source release of Wolfenstein 3D
Log | Files | Refs

WL_DRAW.C (26558B)


      1 // WL_DRAW.C
      2 
      3 #include "WL_DEF.H"
      4 #include <DOS.H>
      5 #pragma hdrstop
      6 
      7 //#define DEBUGWALLS
      8 //#define DEBUGTICS
      9 
     10 /*
     11 =============================================================================
     12 
     13 						 LOCAL CONSTANTS
     14 
     15 =============================================================================
     16 */
     17 
     18 // the door is the last picture before the sprites
     19 #define DOORWALL	(PMSpriteStart-8)
     20 
     21 #define ACTORSIZE	0x4000
     22 
     23 /*
     24 =============================================================================
     25 
     26 						 GLOBAL VARIABLES
     27 
     28 =============================================================================
     29 */
     30 
     31 
     32 #ifdef DEBUGWALLS
     33 unsigned screenloc[3]= {0,0,0};
     34 #else
     35 unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START};
     36 #endif
     37 unsigned freelatch = FREESTART;
     38 
     39 long 	lasttimecount;
     40 long 	frameon;
     41 
     42 unsigned	wallheight[MAXVIEWWIDTH];
     43 
     44 fixed	tileglobal	= TILEGLOBAL;
     45 fixed	mindist		= MINDIST;
     46 
     47 
     48 //
     49 // math tables
     50 //
     51 int			pixelangle[MAXVIEWWIDTH];
     52 long		far finetangent[FINEANGLES/4];
     53 fixed 		far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4);
     54 
     55 //
     56 // refresh variables
     57 //
     58 fixed	viewx,viewy;			// the focal point
     59 int		viewangle;
     60 fixed	viewsin,viewcos;
     61 
     62 
     63 
     64 fixed	FixedByFrac (fixed a, fixed b);
     65 void	TransformActor (objtype *ob);
     66 void	BuildTables (void);
     67 void	ClearScreen (void);
     68 int		CalcRotate (objtype *ob);
     69 void	DrawScaleds (void);
     70 void	CalcTics (void);
     71 void	FixOfs (void);
     72 void	ThreeDRefresh (void);
     73 
     74 
     75 
     76 //
     77 // wall optimization variables
     78 //
     79 int		lastside;		// true for vertical
     80 long	lastintercept;
     81 int		lasttilehit;
     82 
     83 
     84 //
     85 // ray tracing variables
     86 //
     87 int			focaltx,focalty,viewtx,viewty;
     88 
     89 int			midangle,angle;
     90 unsigned	xpartial,ypartial;
     91 unsigned	xpartialup,xpartialdown,ypartialup,ypartialdown;
     92 unsigned	xinttile,yinttile;
     93 
     94 unsigned	tilehit;
     95 unsigned	pixx;
     96 
     97 int		xtile,ytile;
     98 int		xtilestep,ytilestep;
     99 long	xintercept,yintercept;
    100 long	xstep,ystep;
    101 
    102 int		horizwall[MAXWALLTILES],vertwall[MAXWALLTILES];
    103 
    104 
    105 /*
    106 =============================================================================
    107 
    108 						 LOCAL VARIABLES
    109 
    110 =============================================================================
    111 */
    112 
    113 
    114 void AsmRefresh (void);			// in WL_DR_A.ASM
    115 
    116 /*
    117 ============================================================================
    118 
    119 			   3 - D  DEFINITIONS
    120 
    121 ============================================================================
    122 */
    123 
    124 
    125 //==========================================================================
    126 
    127 
    128 /*
    129 ========================
    130 =
    131 = FixedByFrac
    132 =
    133 = multiply a 16/16 bit, 2's complement fixed point number by a 16 bit
    134 = fraction, passed as a signed magnitude 32 bit number
    135 =
    136 ========================
    137 */
    138 
    139 #pragma warn -rvl			// I stick the return value in with ASMs
    140 
    141 fixed FixedByFrac (fixed a, fixed b)
    142 {
    143 //
    144 // setup
    145 //
    146 asm	mov	si,[WORD PTR b+2]	// sign of result = sign of fraction
    147 
    148 asm	mov	ax,[WORD PTR a]
    149 asm	mov	cx,[WORD PTR a+2]
    150 
    151 asm	or	cx,cx
    152 asm	jns	aok:				// negative?
    153 asm	neg	cx
    154 asm	neg	ax
    155 asm	sbb	cx,0
    156 asm	xor	si,0x8000			// toggle sign of result
    157 aok:
    158 
    159 //
    160 // multiply  cx:ax by bx
    161 //
    162 asm	mov	bx,[WORD PTR b]
    163 asm	mul	bx					// fraction*fraction
    164 asm	mov	di,dx				// di is low word of result
    165 asm	mov	ax,cx				//
    166 asm	mul	bx					// units*fraction
    167 asm add	ax,di
    168 asm	adc	dx,0
    169 
    170 //
    171 // put result dx:ax in 2's complement
    172 //
    173 asm	test	si,0x8000		// is the result negative?
    174 asm	jz	ansok:
    175 asm	neg	dx
    176 asm	neg	ax
    177 asm	sbb	dx,0
    178 
    179 ansok:;
    180 
    181 }
    182 
    183 #pragma warn +rvl
    184 
    185 //==========================================================================
    186 
    187 /*
    188 ========================
    189 =
    190 = TransformActor
    191 =
    192 = Takes paramaters:
    193 =   gx,gy		: globalx/globaly of point
    194 =
    195 = globals:
    196 =   viewx,viewy		: point of view
    197 =   viewcos,viewsin	: sin/cos of viewangle
    198 =   scale		: conversion from global value to screen value
    199 =
    200 = sets:
    201 =   screenx,transx,transy,screenheight: projected edge location and size
    202 =
    203 ========================
    204 */
    205 
    206 
    207 //
    208 // transform actor
    209 //
    210 void TransformActor (objtype *ob)
    211 {
    212 	int ratio;
    213 	fixed gx,gy,gxt,gyt,nx,ny;
    214 	long	temp;
    215 
    216 //
    217 // translate point to view centered coordinates
    218 //
    219 	gx = ob->x-viewx;
    220 	gy = ob->y-viewy;
    221 
    222 //
    223 // calculate newx
    224 //
    225 	gxt = FixedByFrac(gx,viewcos);
    226 	gyt = FixedByFrac(gy,viewsin);
    227 	nx = gxt-gyt-ACTORSIZE;		// fudge the shape forward a bit, because
    228 								// the midpoint could put parts of the shape
    229 								// into an adjacent wall
    230 
    231 //
    232 // calculate newy
    233 //
    234 	gxt = FixedByFrac(gx,viewsin);
    235 	gyt = FixedByFrac(gy,viewcos);
    236 	ny = gyt+gxt;
    237 
    238 //
    239 // calculate perspective ratio
    240 //
    241 	ob->transx = nx;
    242 	ob->transy = ny;
    243 
    244 	if (nx<mindist)			// too close, don't overflow the divide
    245 	{
    246 	  ob->viewheight = 0;
    247 	  return;
    248 	}
    249 
    250 	ob->viewx = centerx + ny*scale/nx;	// DEBUG: use assembly divide
    251 
    252 //
    253 // calculate height (heightnumerator/(nx>>8))
    254 //
    255 	asm	mov	ax,[WORD PTR heightnumerator]
    256 	asm	mov	dx,[WORD PTR heightnumerator+2]
    257 	asm	idiv	[WORD PTR nx+1]			// nx>>8
    258 	asm	mov	[WORD PTR temp],ax
    259 	asm	mov	[WORD PTR temp+2],dx
    260 
    261 	ob->viewheight = temp;
    262 }
    263 
    264 //==========================================================================
    265 
    266 /*
    267 ========================
    268 =
    269 = TransformTile
    270 =
    271 = Takes paramaters:
    272 =   tx,ty		: tile the object is centered in
    273 =
    274 = globals:
    275 =   viewx,viewy		: point of view
    276 =   viewcos,viewsin	: sin/cos of viewangle
    277 =   scale		: conversion from global value to screen value
    278 =
    279 = sets:
    280 =   screenx,transx,transy,screenheight: projected edge location and size
    281 =
    282 = Returns true if the tile is withing getting distance
    283 =
    284 ========================
    285 */
    286 
    287 boolean TransformTile (int tx, int ty, int *dispx, int *dispheight)
    288 {
    289 	int ratio;
    290 	fixed gx,gy,gxt,gyt,nx,ny;
    291 	long	temp;
    292 
    293 //
    294 // translate point to view centered coordinates
    295 //
    296 	gx = ((long)tx<<TILESHIFT)+0x8000-viewx;
    297 	gy = ((long)ty<<TILESHIFT)+0x8000-viewy;
    298 
    299 //
    300 // calculate newx
    301 //
    302 	gxt = FixedByFrac(gx,viewcos);
    303 	gyt = FixedByFrac(gy,viewsin);
    304 	nx = gxt-gyt-0x2000;		// 0x2000 is size of object
    305 
    306 //
    307 // calculate newy
    308 //
    309 	gxt = FixedByFrac(gx,viewsin);
    310 	gyt = FixedByFrac(gy,viewcos);
    311 	ny = gyt+gxt;
    312 
    313 
    314 //
    315 // calculate perspective ratio
    316 //
    317 	if (nx<mindist)			// too close, don't overflow the divide
    318 	{
    319 		*dispheight = 0;
    320 		return false;
    321 	}
    322 
    323 	*dispx = centerx + ny*scale/nx;	// DEBUG: use assembly divide
    324 
    325 //
    326 // calculate height (heightnumerator/(nx>>8))
    327 //
    328 	asm	mov	ax,[WORD PTR heightnumerator]
    329 	asm	mov	dx,[WORD PTR heightnumerator+2]
    330 	asm	idiv	[WORD PTR nx+1]			// nx>>8
    331 	asm	mov	[WORD PTR temp],ax
    332 	asm	mov	[WORD PTR temp+2],dx
    333 
    334 	*dispheight = temp;
    335 
    336 //
    337 // see if it should be grabbed
    338 //
    339 	if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2)
    340 		return true;
    341 	else
    342 		return false;
    343 }
    344 
    345 //==========================================================================
    346 
    347 /*
    348 ====================
    349 =
    350 = CalcHeight
    351 =
    352 = Calculates the height of xintercept,yintercept from viewx,viewy
    353 =
    354 ====================
    355 */
    356 
    357 #pragma warn -rvl			// I stick the return value in with ASMs
    358 
    359 int	CalcHeight (void)
    360 {
    361 	int	transheight;
    362 	int ratio;
    363 	fixed gxt,gyt,nx,ny;
    364 	long	gx,gy;
    365 
    366 	gx = xintercept-viewx;
    367 	gxt = FixedByFrac(gx,viewcos);
    368 
    369 	gy = yintercept-viewy;
    370 	gyt = FixedByFrac(gy,viewsin);
    371 
    372 	nx = gxt-gyt;
    373 
    374   //
    375   // calculate perspective ratio (heightnumerator/(nx>>8))
    376   //
    377 	if (nx<mindist)
    378 		nx=mindist;			// don't let divide overflow
    379 
    380 	asm	mov	ax,[WORD PTR heightnumerator]
    381 	asm	mov	dx,[WORD PTR heightnumerator+2]
    382 	asm	idiv	[WORD PTR nx+1]			// nx>>8
    383 }
    384 
    385 
    386 //==========================================================================
    387 
    388 /*
    389 ===================
    390 =
    391 = ScalePost
    392 =
    393 ===================
    394 */
    395 
    396 long		postsource;
    397 unsigned	postx;
    398 unsigned	postwidth;
    399 
    400 void	near ScalePost (void)		// VGA version
    401 {
    402 	asm	mov	ax,SCREENSEG
    403 	asm	mov	es,ax
    404 
    405 	asm	mov	bx,[postx]
    406 	asm	shl	bx,1
    407 	asm	mov	bp,WORD PTR [wallheight+bx]		// fractional height (low 3 bits frac)
    408 	asm	and	bp,0xfff8				// bp = heightscaler*4
    409 	asm	shr	bp,1
    410 	asm	cmp	bp,[maxscaleshl2]
    411 	asm	jle	heightok
    412 	asm	mov	bp,[maxscaleshl2]
    413 heightok:
    414 	asm	add	bp,OFFSET fullscalefarcall
    415 	//
    416 	// scale a byte wide strip of wall
    417 	//
    418 	asm	mov	bx,[postx]
    419 	asm	mov	di,bx
    420 	asm	shr	di,2						// X in bytes
    421 	asm	add	di,[bufferofs]
    422 
    423 	asm	and	bx,3
    424 	asm	shl	bx,3						// bx = pixel*8+pixwidth
    425 	asm	add	bx,[postwidth]
    426 
    427 	asm	mov	al,BYTE PTR [mapmasks1-1+bx]	// -1 because no widths of 0
    428 	asm	mov	dx,SC_INDEX+1
    429 	asm	out	dx,al						// set bit mask register
    430 	asm	lds	si,DWORD PTR [postsource]
    431 	asm	call DWORD PTR [bp]				// scale the line of pixels
    432 
    433 	asm	mov	al,BYTE PTR [ss:mapmasks2-1+bx]   // -1 because no widths of 0
    434 	asm	or	al,al
    435 	asm	jz	nomore
    436 
    437 	//
    438 	// draw a second byte for vertical strips that cross two bytes
    439 	//
    440 	asm	inc	di
    441 	asm	out	dx,al						// set bit mask register
    442 	asm	call DWORD PTR [bp]				// scale the line of pixels
    443 
    444 	asm	mov	al,BYTE PTR [ss:mapmasks3-1+bx]	// -1 because no widths of 0
    445 	asm	or	al,al
    446 	asm	jz	nomore
    447 	//
    448 	// draw a third byte for vertical strips that cross three bytes
    449 	//
    450 	asm	inc	di
    451 	asm	out	dx,al						// set bit mask register
    452 	asm	call DWORD PTR [bp]				// scale the line of pixels
    453 
    454 
    455 nomore:
    456 	asm	mov	ax,ss
    457 	asm	mov	ds,ax
    458 }
    459 
    460 void  FarScalePost (void)				// just so other files can call
    461 {
    462 	ScalePost ();
    463 }
    464 
    465 
    466 /*
    467 ====================
    468 =
    469 = HitVertWall
    470 =
    471 = tilehit bit 7 is 0, because it's not a door tile
    472 = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic
    473 =
    474 ====================
    475 */
    476 
    477 void HitVertWall (void)
    478 {
    479 	int			wallpic;
    480 	unsigned	texture;
    481 
    482 	texture = (yintercept>>4)&0xfc0;
    483 	if (xtilestep == -1)
    484 	{
    485 		texture = 0xfc0-texture;
    486 		xintercept += TILEGLOBAL;
    487 	}
    488 	wallheight[pixx] = CalcHeight();
    489 
    490 	if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit)
    491 	{
    492 		// in the same wall type as last time, so check for optimized draw
    493 		if (texture == (unsigned)postsource)
    494 		{
    495 		// wide scale
    496 			postwidth++;
    497 			wallheight[pixx] = wallheight[pixx-1];
    498 			return;
    499 		}
    500 		else
    501 		{
    502 			ScalePost ();
    503 			(unsigned)postsource = texture;
    504 			postwidth = 1;
    505 			postx = pixx;
    506 		}
    507 	}
    508 	else
    509 	{
    510 	// new wall
    511 		if (lastside != -1)				// if not the first scaled post
    512 			ScalePost ();
    513 
    514 		lastside = true;
    515 		lastintercept = xtile;
    516 
    517 		lasttilehit = tilehit;
    518 		postx = pixx;
    519 		postwidth = 1;
    520 
    521 		if (tilehit & 0x40)
    522 		{								// check for adjacent doors
    523 			ytile = yintercept>>TILESHIFT;
    524 			if ( tilemap[xtile-xtilestep][ytile]&0x80 )
    525 				wallpic = DOORWALL+3;
    526 			else
    527 				wallpic = vertwall[tilehit & ~0x40];
    528 		}
    529 		else
    530 			wallpic = vertwall[tilehit];
    531 
    532 		*( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
    533 		(unsigned)postsource = texture;
    534 
    535 	}
    536 }
    537 
    538 
    539 /*
    540 ====================
    541 =
    542 = HitHorizWall
    543 =
    544 = tilehit bit 7 is 0, because it's not a door tile
    545 = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic
    546 =
    547 ====================
    548 */
    549 
    550 void HitHorizWall (void)
    551 {
    552 	int			wallpic;
    553 	unsigned	texture;
    554 
    555 	texture = (xintercept>>4)&0xfc0;
    556 	if (ytilestep == -1)
    557 		yintercept += TILEGLOBAL;
    558 	else
    559 		texture = 0xfc0-texture;
    560 	wallheight[pixx] = CalcHeight();
    561 
    562 	if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit)
    563 	{
    564 		// in the same wall type as last time, so check for optimized draw
    565 		if (texture == (unsigned)postsource)
    566 		{
    567 		// wide scale
    568 			postwidth++;
    569 			wallheight[pixx] = wallheight[pixx-1];
    570 			return;
    571 		}
    572 		else
    573 		{
    574 			ScalePost ();
    575 			(unsigned)postsource = texture;
    576 			postwidth = 1;
    577 			postx = pixx;
    578 		}
    579 	}
    580 	else
    581 	{
    582 	// new wall
    583 		if (lastside != -1)				// if not the first scaled post
    584 			ScalePost ();
    585 
    586 		lastside = 0;
    587 		lastintercept = ytile;
    588 
    589 		lasttilehit = tilehit;
    590 		postx = pixx;
    591 		postwidth = 1;
    592 
    593 		if (tilehit & 0x40)
    594 		{								// check for adjacent doors
    595 			xtile = xintercept>>TILESHIFT;
    596 			if ( tilemap[xtile][ytile-ytilestep]&0x80 )
    597 				wallpic = DOORWALL+2;
    598 			else
    599 				wallpic = horizwall[tilehit & ~0x40];
    600 		}
    601 		else
    602 			wallpic = horizwall[tilehit];
    603 
    604 		*( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
    605 		(unsigned)postsource = texture;
    606 	}
    607 
    608 }
    609 
    610 //==========================================================================
    611 
    612 /*
    613 ====================
    614 =
    615 = HitHorizDoor
    616 =
    617 ====================
    618 */
    619 
    620 void HitHorizDoor (void)
    621 {
    622 	unsigned	texture,doorpage,doornum;
    623 
    624 	doornum = tilehit&0x7f;
    625 	texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0;
    626 
    627 	wallheight[pixx] = CalcHeight();
    628 
    629 	if (lasttilehit == tilehit)
    630 	{
    631 	// in the same door as last time, so check for optimized draw
    632 		if (texture == (unsigned)postsource)
    633 		{
    634 		// wide scale
    635 			postwidth++;
    636 			wallheight[pixx] = wallheight[pixx-1];
    637 			return;
    638 		}
    639 		else
    640 		{
    641 			ScalePost ();
    642 			(unsigned)postsource = texture;
    643 			postwidth = 1;
    644 			postx = pixx;
    645 		}
    646 	}
    647 	else
    648 	{
    649 		if (lastside != -1)				// if not the first scaled post
    650 			ScalePost ();			// draw last post
    651 	// first pixel in this door
    652 		lastside = 2;
    653 		lasttilehit = tilehit;
    654 		postx = pixx;
    655 		postwidth = 1;
    656 
    657 		switch (doorobjlist[doornum].lock)
    658 		{
    659 		case dr_normal:
    660 			doorpage = DOORWALL;
    661 			break;
    662 		case dr_lock1:
    663 		case dr_lock2:
    664 		case dr_lock3:
    665 		case dr_lock4:
    666 			doorpage = DOORWALL+6;
    667 			break;
    668 		case dr_elevator:
    669 			doorpage = DOORWALL+4;
    670 			break;
    671 		}
    672 
    673 		*( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage);
    674 		(unsigned)postsource = texture;
    675 	}
    676 }
    677 
    678 //==========================================================================
    679 
    680 /*
    681 ====================
    682 =
    683 = HitVertDoor
    684 =
    685 ====================
    686 */
    687 
    688 void HitVertDoor (void)
    689 {
    690 	unsigned	texture,doorpage,doornum;
    691 
    692 	doornum = tilehit&0x7f;
    693 	texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0;
    694 
    695 	wallheight[pixx] = CalcHeight();
    696 
    697 	if (lasttilehit == tilehit)
    698 	{
    699 	// in the same door as last time, so check for optimized draw
    700 		if (texture == (unsigned)postsource)
    701 		{
    702 		// wide scale
    703 			postwidth++;
    704 			wallheight[pixx] = wallheight[pixx-1];
    705 			return;
    706 		}
    707 		else
    708 		{
    709 			ScalePost ();
    710 			(unsigned)postsource = texture;
    711 			postwidth = 1;
    712 			postx = pixx;
    713 		}
    714 	}
    715 	else
    716 	{
    717 		if (lastside != -1)				// if not the first scaled post
    718 			ScalePost ();			// draw last post
    719 	// first pixel in this door
    720 		lastside = 2;
    721 		lasttilehit = tilehit;
    722 		postx = pixx;
    723 		postwidth = 1;
    724 
    725 		switch (doorobjlist[doornum].lock)
    726 		{
    727 		case dr_normal:
    728 			doorpage = DOORWALL;
    729 			break;
    730 		case dr_lock1:
    731 		case dr_lock2:
    732 		case dr_lock3:
    733 		case dr_lock4:
    734 			doorpage = DOORWALL+6;
    735 			break;
    736 		case dr_elevator:
    737 			doorpage = DOORWALL+4;
    738 			break;
    739 		}
    740 
    741 		*( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1);
    742 		(unsigned)postsource = texture;
    743 	}
    744 }
    745 
    746 //==========================================================================
    747 
    748 
    749 /*
    750 ====================
    751 =
    752 = HitHorizPWall
    753 =
    754 = A pushable wall in action has been hit
    755 =
    756 ====================
    757 */
    758 
    759 void HitHorizPWall (void)
    760 {
    761 	int			wallpic;
    762 	unsigned	texture,offset;
    763 
    764 	texture = (xintercept>>4)&0xfc0;
    765 	offset = pwallpos<<10;
    766 	if (ytilestep == -1)
    767 		yintercept += TILEGLOBAL-offset;
    768 	else
    769 	{
    770 		texture = 0xfc0-texture;
    771 		yintercept += offset;
    772 	}
    773 
    774 	wallheight[pixx] = CalcHeight();
    775 
    776 	if (lasttilehit == tilehit)
    777 	{
    778 		// in the same wall type as last time, so check for optimized draw
    779 		if (texture == (unsigned)postsource)
    780 		{
    781 		// wide scale
    782 			postwidth++;
    783 			wallheight[pixx] = wallheight[pixx-1];
    784 			return;
    785 		}
    786 		else
    787 		{
    788 			ScalePost ();
    789 			(unsigned)postsource = texture;
    790 			postwidth = 1;
    791 			postx = pixx;
    792 		}
    793 	}
    794 	else
    795 	{
    796 	// new wall
    797 		if (lastside != -1)				// if not the first scaled post
    798 			ScalePost ();
    799 
    800 		lasttilehit = tilehit;
    801 		postx = pixx;
    802 		postwidth = 1;
    803 
    804 		wallpic = horizwall[tilehit&63];
    805 
    806 		*( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
    807 		(unsigned)postsource = texture;
    808 	}
    809 
    810 }
    811 
    812 
    813 /*
    814 ====================
    815 =
    816 = HitVertPWall
    817 =
    818 = A pushable wall in action has been hit
    819 =
    820 ====================
    821 */
    822 
    823 void HitVertPWall (void)
    824 {
    825 	int			wallpic;
    826 	unsigned	texture,offset;
    827 
    828 	texture = (yintercept>>4)&0xfc0;
    829 	offset = pwallpos<<10;
    830 	if (xtilestep == -1)
    831 	{
    832 		xintercept += TILEGLOBAL-offset;
    833 		texture = 0xfc0-texture;
    834 	}
    835 	else
    836 		xintercept += offset;
    837 
    838 	wallheight[pixx] = CalcHeight();
    839 
    840 	if (lasttilehit == tilehit)
    841 	{
    842 		// in the same wall type as last time, so check for optimized draw
    843 		if (texture == (unsigned)postsource)
    844 		{
    845 		// wide scale
    846 			postwidth++;
    847 			wallheight[pixx] = wallheight[pixx-1];
    848 			return;
    849 		}
    850 		else
    851 		{
    852 			ScalePost ();
    853 			(unsigned)postsource = texture;
    854 			postwidth = 1;
    855 			postx = pixx;
    856 		}
    857 	}
    858 	else
    859 	{
    860 	// new wall
    861 		if (lastside != -1)				// if not the first scaled post
    862 			ScalePost ();
    863 
    864 		lasttilehit = tilehit;
    865 		postx = pixx;
    866 		postwidth = 1;
    867 
    868 		wallpic = vertwall[tilehit&63];
    869 
    870 		*( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
    871 		(unsigned)postsource = texture;
    872 	}
    873 
    874 }
    875 
    876 //==========================================================================
    877 
    878 //==========================================================================
    879 
    880 #if 0
    881 /*
    882 =====================
    883 =
    884 = ClearScreen
    885 =
    886 =====================
    887 */
    888 
    889 void ClearScreen (void)
    890 {
    891  unsigned floor=egaFloor[gamestate.episode*10+mapon],
    892 	  ceiling=egaCeiling[gamestate.episode*10+mapon];
    893 
    894   //
    895   // clear the screen
    896   //
    897 asm	mov	dx,GC_INDEX
    898 asm	mov	ax,GC_MODE + 256*2		// read mode 0, write mode 2
    899 asm	out	dx,ax
    900 asm	mov	ax,GC_BITMASK + 255*256
    901 asm	out	dx,ax
    902 
    903 asm	mov	dx,40
    904 asm	mov	ax,[viewwidth]
    905 asm	shr	ax,3
    906 asm	sub	dx,ax					// dx = 40-viewwidth/8
    907 
    908 asm	mov	bx,[viewwidth]
    909 asm	shr	bx,4					// bl = viewwidth/16
    910 asm	mov	bh,BYTE PTR [viewheight]
    911 asm	shr	bh,1					// half height
    912 
    913 asm	mov	ax,[ceiling]
    914 asm	mov	es,[screenseg]
    915 asm	mov	di,[bufferofs]
    916 
    917 toploop:
    918 asm	mov	cl,bl
    919 asm	rep	stosw
    920 asm	add	di,dx
    921 asm	dec	bh
    922 asm	jnz	toploop
    923 
    924 asm	mov	bh,BYTE PTR [viewheight]
    925 asm	shr	bh,1					// half height
    926 asm	mov	ax,[floor]
    927 
    928 bottomloop:
    929 asm	mov	cl,bl
    930 asm	rep	stosw
    931 asm	add	di,dx
    932 asm	dec	bh
    933 asm	jnz	bottomloop
    934 
    935 
    936 asm	mov	dx,GC_INDEX
    937 asm	mov	ax,GC_MODE + 256*10		// read mode 1, write mode 2
    938 asm	out	dx,ax
    939 asm	mov	al,GC_BITMASK
    940 asm	out	dx,al
    941 
    942 }
    943 #endif
    944 //==========================================================================
    945 
    946 unsigned vgaCeiling[]=
    947 {
    948 #ifndef SPEAR
    949  0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,
    950  0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,
    951  0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,
    952 
    953  0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,
    954  0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,
    955  0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd
    956 #else
    957  0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,
    958  0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc
    959 #endif
    960 };
    961 
    962 /*
    963 =====================
    964 =
    965 = VGAClearScreen
    966 =
    967 =====================
    968 */
    969 
    970 void VGAClearScreen (void)
    971 {
    972  unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon];
    973 
    974   //
    975   // clear the screen
    976   //
    977 asm	mov	dx,SC_INDEX
    978 asm	mov	ax,SC_MAPMASK+15*256	// write through all planes
    979 asm	out	dx,ax
    980 
    981 asm	mov	dx,80
    982 asm	mov	ax,[viewwidth]
    983 asm	shr	ax,2
    984 asm	sub	dx,ax					// dx = 40-viewwidth/2
    985 
    986 asm	mov	bx,[viewwidth]
    987 asm	shr	bx,3					// bl = viewwidth/8
    988 asm	mov	bh,BYTE PTR [viewheight]
    989 asm	shr	bh,1					// half height
    990 
    991 asm	mov	es,[screenseg]
    992 asm	mov	di,[bufferofs]
    993 asm	mov	ax,[ceiling]
    994 
    995 toploop:
    996 asm	mov	cl,bl
    997 asm	rep	stosw
    998 asm	add	di,dx
    999 asm	dec	bh
   1000 asm	jnz	toploop
   1001 
   1002 asm	mov	bh,BYTE PTR [viewheight]
   1003 asm	shr	bh,1					// half height
   1004 asm	mov	ax,0x1919
   1005 
   1006 bottomloop:
   1007 asm	mov	cl,bl
   1008 asm	rep	stosw
   1009 asm	add	di,dx
   1010 asm	dec	bh
   1011 asm	jnz	bottomloop
   1012 }
   1013 
   1014 //==========================================================================
   1015 
   1016 /*
   1017 =====================
   1018 =
   1019 = CalcRotate
   1020 =
   1021 =====================
   1022 */
   1023 
   1024 int	CalcRotate (objtype *ob)
   1025 {
   1026 	int	angle,viewangle;
   1027 
   1028 	// this isn't exactly correct, as it should vary by a trig value,
   1029 	// but it is close enough with only eight rotations
   1030 
   1031 	viewangle = player->angle + (centerx - ob->viewx)/8;
   1032 
   1033 	if (ob->obclass == rocketobj || ob->obclass == hrocketobj)
   1034 		angle =  (viewangle-180)- ob->angle;
   1035 	else
   1036 		angle =  (viewangle-180)- dirangle[ob->dir];
   1037 
   1038 	angle+=ANGLES/16;
   1039 	while (angle>=ANGLES)
   1040 		angle-=ANGLES;
   1041 	while (angle<0)
   1042 		angle+=ANGLES;
   1043 
   1044 	if (ob->state->rotate == 2)             // 2 rotation pain frame
   1045 		return 4*(angle/(ANGLES/2));        // seperated by 3 (art layout...)
   1046 
   1047 	return angle/(ANGLES/8);
   1048 }
   1049 
   1050 
   1051 /*
   1052 =====================
   1053 =
   1054 = DrawScaleds
   1055 =
   1056 = Draws all objects that are visable
   1057 =
   1058 =====================
   1059 */
   1060 
   1061 #define MAXVISABLE	50
   1062 
   1063 typedef struct
   1064 {
   1065 	int	viewx,
   1066 		viewheight,
   1067 		shapenum;
   1068 } visobj_t;
   1069 
   1070 visobj_t	vislist[MAXVISABLE],*visptr,*visstep,*farthest;
   1071 
   1072 void DrawScaleds (void)
   1073 {
   1074 	int 		i,j,least,numvisable,height;
   1075 	memptr		shape;
   1076 	byte		*tilespot,*visspot;
   1077 	int			shapenum;
   1078 	unsigned	spotloc;
   1079 
   1080 	statobj_t	*statptr;
   1081 	objtype		*obj;
   1082 
   1083 	visptr = &vislist[0];
   1084 
   1085 //
   1086 // place static objects
   1087 //
   1088 	for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)
   1089 	{
   1090 		if ((visptr->shapenum = statptr->shapenum) == -1)
   1091 			continue;						// object has been deleted
   1092 
   1093 		if (!*statptr->visspot)
   1094 			continue;						// not visable
   1095 
   1096 		if (TransformTile (statptr->tilex,statptr->tiley
   1097 			,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS)
   1098 		{
   1099 			GetBonus (statptr);
   1100 			continue;
   1101 		}
   1102 
   1103 		if (!visptr->viewheight)
   1104 			continue;						// to close to the object
   1105 
   1106 		if (visptr < &vislist[MAXVISABLE-1])	// don't let it overflow
   1107 			visptr++;
   1108 	}
   1109 
   1110 //
   1111 // place active objects
   1112 //
   1113 	for (obj = player->next;obj;obj=obj->next)
   1114 	{
   1115 		if (!(visptr->shapenum = obj->state->shapenum))
   1116 			continue;						// no shape
   1117 
   1118 		spotloc = (obj->tilex<<6)+obj->tiley;	// optimize: keep in struct?
   1119 		visspot = &spotvis[0][0]+spotloc;
   1120 		tilespot = &tilemap[0][0]+spotloc;
   1121 
   1122 		//
   1123 		// could be in any of the nine surrounding tiles
   1124 		//
   1125 		if (*visspot
   1126 		|| ( *(visspot-1) && !*(tilespot-1) )
   1127 		|| ( *(visspot+1) && !*(tilespot+1) )
   1128 		|| ( *(visspot-65) && !*(tilespot-65) )
   1129 		|| ( *(visspot-64) && !*(tilespot-64) )
   1130 		|| ( *(visspot-63) && !*(tilespot-63) )
   1131 		|| ( *(visspot+65) && !*(tilespot+65) )
   1132 		|| ( *(visspot+64) && !*(tilespot+64) )
   1133 		|| ( *(visspot+63) && !*(tilespot+63) ) )
   1134 		{
   1135 			obj->active = true;
   1136 			TransformActor (obj);
   1137 			if (!obj->viewheight)
   1138 				continue;						// too close or far away
   1139 
   1140 			visptr->viewx = obj->viewx;
   1141 			visptr->viewheight = obj->viewheight;
   1142 			if (visptr->shapenum == -1)
   1143 				visptr->shapenum = obj->temp1;	// special shape
   1144 
   1145 			if (obj->state->rotate)
   1146 				visptr->shapenum += CalcRotate (obj);
   1147 
   1148 			if (visptr < &vislist[MAXVISABLE-1])	// don't let it overflow
   1149 				visptr++;
   1150 			obj->flags |= FL_VISABLE;
   1151 		}
   1152 		else
   1153 			obj->flags &= ~FL_VISABLE;
   1154 	}
   1155 
   1156 //
   1157 // draw from back to front
   1158 //
   1159 	numvisable = visptr-&vislist[0];
   1160 
   1161 	if (!numvisable)
   1162 		return;									// no visable objects
   1163 
   1164 	for (i = 0; i<numvisable; i++)
   1165 	{
   1166 		least = 32000;
   1167 		for (visstep=&vislist[0] ; visstep<visptr ; visstep++)
   1168 		{
   1169 			height = visstep->viewheight;
   1170 			if (height < least)
   1171 			{
   1172 				least = height;
   1173 				farthest = visstep;
   1174 			}
   1175 		}
   1176 		//
   1177 		// draw farthest
   1178 		//
   1179 		ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight);
   1180 
   1181 		farthest->viewheight = 32000;
   1182 	}
   1183 
   1184 }
   1185 
   1186 //==========================================================================
   1187 
   1188 /*
   1189 ==============
   1190 =
   1191 = DrawPlayerWeapon
   1192 =
   1193 = Draw the player's hands
   1194 =
   1195 ==============
   1196 */
   1197 
   1198 int	weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY
   1199 	,SPR_MACHINEGUNREADY,SPR_CHAINREADY};
   1200 
   1201 void DrawPlayerWeapon (void)
   1202 {
   1203 	int	shapenum;
   1204 
   1205 #ifndef SPEAR
   1206 	if (gamestate.victoryflag)
   1207 	{
   1208 		if (player->state == &s_deathcam && (TimeCount&32) )
   1209 			SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1);
   1210 		return;
   1211 	}
   1212 #endif
   1213 
   1214 	if (gamestate.weapon != -1)
   1215 	{
   1216 		shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe;
   1217 		SimpleScaleShape(viewwidth/2,shapenum,viewheight+1);
   1218 	}
   1219 
   1220 	if (demorecord || demoplayback)
   1221 		SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1);
   1222 }
   1223 
   1224 
   1225 //==========================================================================
   1226 
   1227 
   1228 /*
   1229 =====================
   1230 =
   1231 = CalcTics
   1232 =
   1233 =====================
   1234 */
   1235 
   1236 void CalcTics (void)
   1237 {
   1238 	long	newtime,oldtimecount;
   1239 
   1240 //
   1241 // calculate tics since last refresh for adaptive timing
   1242 //
   1243 	if (lasttimecount > TimeCount)
   1244 		TimeCount = lasttimecount;		// if the game was paused a LONG time
   1245 
   1246 	do
   1247 	{
   1248 		newtime = TimeCount;
   1249 		tics = newtime-lasttimecount;
   1250 	} while (!tics);			// make sure at least one tic passes
   1251 
   1252 	lasttimecount = newtime;
   1253 
   1254 #ifdef FILEPROFILE
   1255 		strcpy (scratch,"\tTics:");
   1256 		itoa (tics,str,10);
   1257 		strcat (scratch,str);
   1258 		strcat (scratch,"\n");
   1259 		write (profilehandle,scratch,strlen(scratch));
   1260 #endif
   1261 
   1262 	if (tics>MAXTICS)
   1263 	{
   1264 		TimeCount -= (tics-MAXTICS);
   1265 		tics = MAXTICS;
   1266 	}
   1267 }
   1268 
   1269 
   1270 //==========================================================================
   1271 
   1272 
   1273 /*
   1274 ========================
   1275 =
   1276 = FixOfs
   1277 =
   1278 ========================
   1279 */
   1280 
   1281 void	FixOfs (void)
   1282 {
   1283 	VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight);
   1284 }
   1285 
   1286 
   1287 //==========================================================================
   1288 
   1289 
   1290 /*
   1291 ====================
   1292 =
   1293 = WallRefresh
   1294 =
   1295 ====================
   1296 */
   1297 
   1298 void WallRefresh (void)
   1299 {
   1300 //
   1301 // set up variables for this view
   1302 //
   1303 	viewangle = player->angle;
   1304 	midangle = viewangle*(FINEANGLES/ANGLES);
   1305 	viewsin = sintable[viewangle];
   1306 	viewcos = costable[viewangle];
   1307 	viewx = player->x - FixedByFrac(focallength,viewcos);
   1308 	viewy = player->y + FixedByFrac(focallength,viewsin);
   1309 
   1310 	focaltx = viewx>>TILESHIFT;
   1311 	focalty = viewy>>TILESHIFT;
   1312 
   1313 	viewtx = player->x >> TILESHIFT;
   1314 	viewty = player->y >> TILESHIFT;
   1315 
   1316 	xpartialdown = viewx&(TILEGLOBAL-1);
   1317 	xpartialup = TILEGLOBAL-xpartialdown;
   1318 	ypartialdown = viewy&(TILEGLOBAL-1);
   1319 	ypartialup = TILEGLOBAL-ypartialdown;
   1320 
   1321 	lastside = -1;			// the first pixel is on a new wall
   1322 	AsmRefresh ();
   1323 	ScalePost ();			// no more optimization on last post
   1324 }
   1325 
   1326 //==========================================================================
   1327 
   1328 /*
   1329 ========================
   1330 =
   1331 = ThreeDRefresh
   1332 =
   1333 ========================
   1334 */
   1335 
   1336 void	ThreeDRefresh (void)
   1337 {
   1338 	int tracedir;
   1339 
   1340 // this wouldn't need to be done except for my debugger/video wierdness
   1341 	outportb (SC_INDEX,SC_MAPMASK);
   1342 
   1343 //
   1344 // clear out the traced array
   1345 //
   1346 asm	mov	ax,ds
   1347 asm	mov	es,ax
   1348 asm	mov	di,OFFSET spotvis
   1349 asm	xor	ax,ax
   1350 asm	mov	cx,2048							// 64*64 / 2
   1351 asm	rep stosw
   1352 
   1353 	bufferofs += screenofs;
   1354 
   1355 //
   1356 // follow the walls from there to the right, drawwing as we go
   1357 //
   1358 	VGAClearScreen ();
   1359 
   1360 	WallRefresh ();
   1361 
   1362 //
   1363 // draw all the scaled images
   1364 //
   1365 	DrawScaleds();			// draw scaled stuff
   1366 	DrawPlayerWeapon ();	// draw player's hands
   1367 
   1368 //
   1369 // show screen and time last cycle
   1370 //
   1371 	if (fizzlein)
   1372 	{
   1373 		FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false);
   1374 		fizzlein = false;
   1375 
   1376 		lasttimecount = TimeCount = 0;		// don't make a big tic count
   1377 
   1378 	}
   1379 
   1380 	bufferofs -= screenofs;
   1381 	displayofs = bufferofs;
   1382 
   1383 	asm	cli
   1384 	asm	mov	cx,[displayofs]
   1385 	asm	mov	dx,3d4h		// CRTC address register
   1386 	asm	mov	al,0ch		// start address high register
   1387 	asm	out	dx,al
   1388 	asm	inc	dx
   1389 	asm	mov	al,ch
   1390 	asm	out	dx,al   	// set the high byte
   1391 	asm	sti
   1392 
   1393 	bufferofs += SCREENSIZE;
   1394 	if (bufferofs > PAGE3START)
   1395 		bufferofs = PAGE1START;
   1396 
   1397 	frameon++;
   1398 	PM_NextFrame();
   1399 }
   1400 
   1401 
   1402 //===========================================================================
   1403