doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

p_maputl.c (12042B)


      1 #include <stdlib.h>
      2 
      3 #include "m_bbox.h"
      4 #include "doomdef.h"
      5 #include "p_local.h"
      6 #include "r_state.h"
      7 
      8 fixed_t
      9 P_AproxDistance
     10 ( fixed_t	dx,
     11   fixed_t	dy )
     12 {
     13     dx = abs(dx);
     14     dy = abs(dy);
     15     if (dx < dy)
     16 	return dx+dy-(dx>>1);
     17     return dx+dy-(dy>>1);
     18 }
     19 
     20 
     21 
     22 
     23 
     24 
     25 int
     26 P_PointOnLineSide
     27 ( fixed_t	x,
     28   fixed_t	y,
     29   line_t*	line )
     30 {
     31     fixed_t	dx;
     32     fixed_t	dy;
     33     fixed_t	left;
     34     fixed_t	right;
     35 	
     36     if (!line->dx)
     37     {
     38 	if (x <= line->v1->x)
     39 	    return line->dy > 0;
     40 	
     41 	return line->dy < 0;
     42     }
     43     if (!line->dy)
     44     {
     45 	if (y <= line->v1->y)
     46 	    return line->dx < 0;
     47 	
     48 	return line->dx > 0;
     49     }
     50 	
     51     dx = (x - line->v1->x);
     52     dy = (y - line->v1->y);
     53 	
     54     left = FixedMul ( line->dy>>FRACBITS , dx );
     55     right = FixedMul ( dy , line->dx>>FRACBITS );
     56 	
     57     if (right < left)
     58 	return 0;		
     59     return 1;			
     60 }
     61 
     62 
     63 
     64 
     65 
     66 
     67 
     68 
     69 int
     70 P_BoxOnLineSide(fixed_t* tmbox, line_t* ld)
     71 {
     72     int	 p1, p2;
     73 	
     74     switch (ld->slopetype) {
     75 		case ST_HORIZONTAL:
     76 			p1 = tmbox[BOXTOP] > ld->v1->y;
     77 			p2 = tmbox[BOXBOTTOM] > ld->v1->y;
     78 			if (ld->dx < 0) {
     79 				p1 ^= 1;
     80 				p2 ^= 1;
     81 			}
     82 			break;
     83 		case ST_VERTICAL:
     84 			p1 = tmbox[BOXRIGHT] < ld->v1->x;
     85 			p2 = tmbox[BOXLEFT] < ld->v1->x;
     86 			if (ld->dy < 0) {
     87 				p1 ^= 1;
     88 				p2 ^= 1;
     89 			}
     90 			break;
     91 		case ST_POSITIVE:
     92 			p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
     93 			p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
     94 			break;
     95 		case ST_NEGATIVE:
     96 			p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
     97 			p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
     98 			break;
     99 		default:
    100 			p1 = p2 = 0;
    101     }
    102     if (p1 == p2)
    103 		return p1;
    104     return -1;
    105 }
    106 
    107 int
    108 P_PointOnDivlineSide
    109 ( fixed_t	x,
    110   fixed_t	y,
    111   divline_t*	line )
    112 {
    113     fixed_t	dx;
    114     fixed_t	dy;
    115     fixed_t	left;
    116     fixed_t	right;
    117 	
    118     if (!line->dx)
    119     {
    120 	if (x <= line->x)
    121 	    return line->dy > 0;
    122 	
    123 	return line->dy < 0;
    124     }
    125     if (!line->dy)
    126     {
    127 	if (y <= line->y)
    128 	    return line->dx < 0;
    129 
    130 	return line->dx > 0;
    131     }
    132 	
    133     dx = (x - line->x);
    134     dy = (y - line->y);
    135 	
    136     
    137     if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
    138     {
    139 	if ( (line->dy ^ dx) & 0x80000000 )
    140 	    return 1;		
    141 	return 0;
    142     }
    143 	
    144     left = FixedMul ( line->dy>>8, dx>>8 );
    145     right = FixedMul ( dy>>8 , line->dx>>8 );
    146 	
    147     if (right < left)
    148 	return 0;		
    149     return 1;			
    150 }
    151 
    152 
    153 
    154 
    155 
    156 
    157 void
    158 P_MakeDivline
    159 ( line_t*	li,
    160   divline_t*	dl )
    161 {
    162     dl->x = li->v1->x;
    163     dl->y = li->v1->y;
    164     dl->dx = li->dx;
    165     dl->dy = li->dy;
    166 }
    167 
    168 
    169 
    170 
    171 
    172 
    173 
    174 
    175 
    176 
    177 fixed_t
    178 P_InterceptVector
    179 ( divline_t*	v2,
    180   divline_t*	v1 )
    181 {
    182 #if 1
    183     fixed_t	frac;
    184     fixed_t	num;
    185     fixed_t	den;
    186 	
    187     den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
    188 
    189     if (den == 0)
    190 	return 0;
    191     
    192     
    193     num =
    194 	FixedMul ( (v1->x - v2->x)>>8 ,v1->dy )
    195 	+FixedMul ( (v2->y - v1->y)>>8, v1->dx );
    196 
    197     frac = FixedDiv (num , den);
    198 
    199     return frac;
    200 #else	
    201     float	frac;
    202     float	num;
    203     float	den;
    204     float	v1x;
    205     float	v1y;
    206     float	v1dx;
    207     float	v1dy;
    208     float	v2x;
    209     float	v2y;
    210     float	v2dx;
    211     float	v2dy;
    212 
    213     v1x = (float)v1->x/FRACUNIT;
    214     v1y = (float)v1->y/FRACUNIT;
    215     v1dx = (float)v1->dx/FRACUNIT;
    216     v1dy = (float)v1->dy/FRACUNIT;
    217     v2x = (float)v2->x/FRACUNIT;
    218     v2y = (float)v2->y/FRACUNIT;
    219     v2dx = (float)v2->dx/FRACUNIT;
    220     v2dy = (float)v2->dy/FRACUNIT;
    221 	
    222     den = v1dy*v2dx - v1dx*v2dy;
    223 
    224     if (den == 0)
    225 	return 0;	
    226     
    227     num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
    228     frac = num / den;
    229 
    230     return frac*FRACUNIT;
    231 #endif
    232 }
    233 
    234 
    235 
    236 
    237 
    238 
    239 
    240 
    241 fixed_t opentop;
    242 fixed_t openbottom;
    243 fixed_t openrange;
    244 fixed_t	lowfloor;
    245 
    246 
    247 void P_LineOpening (line_t* linedef)
    248 {
    249     sector_t*	front;
    250     sector_t*	back;
    251 	
    252     if (linedef->sidenum[1] == -1)
    253     {
    254 	
    255 	openrange = 0;
    256 	return;
    257     }
    258 	 
    259     front = linedef->frontsector;
    260     back = linedef->backsector;
    261 	
    262     if (front->ceilingheight < back->ceilingheight)
    263 	opentop = front->ceilingheight;
    264     else
    265 	opentop = back->ceilingheight;
    266 
    267     if (front->floorheight > back->floorheight)
    268     {
    269 	openbottom = front->floorheight;
    270 	lowfloor = back->floorheight;
    271     }
    272     else
    273     {
    274 	openbottom = back->floorheight;
    275 	lowfloor = front->floorheight;
    276     }
    277 	
    278     openrange = opentop - openbottom;
    279 }
    280 
    281 
    282 
    283 
    284 
    285 
    286 
    287 
    288 
    289 
    290 
    291 
    292 
    293 
    294 void P_UnsetThingPosition (mobj_t* thing)
    295 {
    296     int		blockx;
    297     int		blocky;
    298 
    299     if ( ! (thing->flags & MF_NOSECTOR) )
    300     {
    301 	
    302 	
    303 	if (thing->snext)
    304 	    thing->snext->sprev = thing->sprev;
    305 
    306 	if (thing->sprev)
    307 	    thing->sprev->snext = thing->snext;
    308 	else
    309 	    thing->subsector->sector->thinglist = thing->snext;
    310     }
    311 	
    312     if ( ! (thing->flags & MF_NOBLOCKMAP) )
    313     {
    314 	
    315 	
    316 	if (thing->bnext)
    317 	    thing->bnext->bprev = thing->bprev;
    318 	
    319 	if (thing->bprev)
    320 	    thing->bprev->bnext = thing->bnext;
    321 	else
    322 	{
    323 	    blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
    324 	    blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
    325 
    326 	    if (blockx>=0 && blockx < bmapwidth
    327 		&& blocky>=0 && blocky <bmapheight)
    328 	    {
    329 		blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
    330 	    }
    331 	}
    332     }
    333 }
    334 
    335 
    336 
    337 
    338 
    339 
    340 
    341 
    342 void
    343 P_SetThingPosition (mobj_t* thing)
    344 {
    345     subsector_t*	ss;
    346     sector_t*		sec;
    347     int			blockx;
    348     int			blocky;
    349     mobj_t**		link;
    350 
    351     
    352     
    353     ss = R_PointInSubsector (thing->x,thing->y);
    354     thing->subsector = ss;
    355     
    356     if ( ! (thing->flags & MF_NOSECTOR) )
    357     {
    358 	
    359 	sec = ss->sector;
    360 	
    361 	thing->sprev = NULL;
    362 	thing->snext = sec->thinglist;
    363 
    364 	if (sec->thinglist)
    365 	    sec->thinglist->sprev = thing;
    366 
    367 	sec->thinglist = thing;
    368     }
    369 
    370     
    371     
    372     if ( ! (thing->flags & MF_NOBLOCKMAP) )
    373     {
    374 	
    375 	blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
    376 	blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
    377 
    378 	if (blockx>=0
    379 	    && blockx < bmapwidth
    380 	    && blocky>=0
    381 	    && blocky < bmapheight)
    382 	{
    383 	    link = &blocklinks[blocky*bmapwidth+blockx];
    384 	    thing->bprev = NULL;
    385 	    thing->bnext = *link;
    386 	    if (*link)
    387 		(*link)->bprev = thing;
    388 
    389 	    *link = thing;
    390 	}
    391 	else
    392 	{
    393 	    
    394 	    thing->bnext = thing->bprev = NULL;
    395 	}
    396     }
    397 }
    398 
    399 
    400 
    401 
    402 
    403 
    404 
    405 
    406 
    407 
    408 
    409 
    410 
    411 
    412 
    413 
    414 
    415 
    416 
    417 
    418 boolean
    419 P_BlockLinesIterator
    420 ( int			x,
    421   int			y,
    422   boolean(*func)(line_t*) )
    423 {
    424     int			offset;
    425     short*		list;
    426     line_t*		ld;
    427 	
    428     if (x<0
    429 	|| y<0
    430 	|| x>=bmapwidth
    431 	|| y>=bmapheight)
    432     {
    433 	return true;
    434     }
    435     
    436     offset = y*bmapwidth+x;
    437 	
    438     offset = *(blockmap+offset);
    439 
    440     for ( list = blockmaplump+offset ; *list != -1 ; list++)
    441     {
    442 	ld = &lines[*list];
    443 
    444 	if (ld->validcount == validcount)
    445 	    continue; 	
    446 
    447 	ld->validcount = validcount;
    448 		
    449 	if ( !func(ld) )
    450 	    return false;
    451     }
    452     return true;	
    453 }
    454 
    455 
    456 
    457 
    458 
    459 boolean
    460 P_BlockThingsIterator
    461 ( int			x,
    462   int			y,
    463   boolean(*func)(mobj_t*) )
    464 {
    465     mobj_t*		mobj;
    466 	
    467     if ( x<0
    468 	 || y<0
    469 	 || x>=bmapwidth
    470 	 || y>=bmapheight)
    471     {
    472 	return true;
    473     }
    474     
    475 
    476     for (mobj = blocklinks[y*bmapwidth+x] ;
    477 	 mobj ;
    478 	 mobj = mobj->bnext)
    479     {
    480 	if (!func( mobj ) )
    481 	    return false;
    482     }
    483     return true;
    484 }
    485 
    486 
    487 
    488 
    489 
    490 
    491 intercept_t	intercepts[INT_MAXERCEPTS];
    492 intercept_t*	intercept_p;
    493 
    494 divline_t 	trace;
    495 boolean 	earlyout;
    496 int		ptflags;
    497 
    498 
    499 
    500 
    501 
    502 
    503 
    504 
    505 
    506 
    507 
    508 boolean
    509 PIT_AddLineIntercepts (line_t* ld)
    510 {
    511     int			s1;
    512     int			s2;
    513     fixed_t		frac;
    514     divline_t		dl;
    515 	
    516     
    517     if ( trace.dx > FRACUNIT*16
    518 	 || trace.dy > FRACUNIT*16
    519 	 || trace.dx < -FRACUNIT*16
    520 	 || trace.dy < -FRACUNIT*16)
    521     {
    522 	s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
    523 	s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
    524     }
    525     else
    526     {
    527 	s1 = P_PointOnLineSide (trace.x, trace.y, ld);
    528 	s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
    529     }
    530     
    531     if (s1 == s2)
    532 	return true;	
    533     
    534     
    535     P_MakeDivline (ld, &dl);
    536     frac = P_InterceptVector (&trace, &dl);
    537 
    538     if (frac < 0)
    539 	return true;	
    540 	
    541     
    542     if (earlyout
    543 	&& frac < FRACUNIT
    544 	&& !ld->backsector)
    545     {
    546 	return false;	
    547     }
    548     
    549 	
    550     intercept_p->frac = frac;
    551     intercept_p->isaline = true;
    552     intercept_p->d.line = ld;
    553     intercept_p++;
    554 
    555     return true;	
    556 }
    557 
    558 
    559 
    560 
    561 
    562 
    563 boolean PIT_AddThingIntercepts (mobj_t* thing)
    564 {
    565     fixed_t		x1;
    566     fixed_t		y1;
    567     fixed_t		x2;
    568     fixed_t		y2;
    569     
    570     int			s1;
    571     int			s2;
    572     
    573     boolean		tracepositive;
    574 
    575     divline_t		dl;
    576     
    577     fixed_t		frac;
    578 	
    579     tracepositive = (trace.dx ^ trace.dy)>0;
    580 		
    581     
    582     if (tracepositive)
    583     {
    584 	x1 = thing->x - thing->radius;
    585 	y1 = thing->y + thing->radius;
    586 		
    587 	x2 = thing->x + thing->radius;
    588 	y2 = thing->y - thing->radius;			
    589     }
    590     else
    591     {
    592 	x1 = thing->x - thing->radius;
    593 	y1 = thing->y - thing->radius;
    594 		
    595 	x2 = thing->x + thing->radius;
    596 	y2 = thing->y + thing->radius;			
    597     }
    598     
    599     s1 = P_PointOnDivlineSide (x1, y1, &trace);
    600     s2 = P_PointOnDivlineSide (x2, y2, &trace);
    601 
    602     if (s1 == s2)
    603 	return true;		
    604 	
    605     dl.x = x1;
    606     dl.y = y1;
    607     dl.dx = x2-x1;
    608     dl.dy = y2-y1;
    609     
    610     frac = P_InterceptVector (&trace, &dl);
    611 
    612     if (frac < 0)
    613 	return true;		
    614 
    615     intercept_p->frac = frac;
    616     intercept_p->isaline = false;
    617     intercept_p->d.thing = thing;
    618     intercept_p++;
    619 
    620     return true;		
    621 }
    622 
    623 
    624 
    625 
    626 
    627 
    628 
    629 boolean
    630 P_TraverseIntercepts
    631 ( traverser_t	func,
    632   fixed_t	maxfrac )
    633 {
    634     int			count;
    635     fixed_t		dist;
    636     intercept_t*	scan;
    637     intercept_t*	in;
    638 	
    639     count = intercept_p - intercepts;
    640     
    641     in = 0;			
    642 	
    643     while (count--)
    644     {
    645 	dist = INT_MAX;
    646 	for (scan = intercepts ; scan<intercept_p ; scan++)
    647 	{
    648 	    if (scan->frac < dist)
    649 	    {
    650 		dist = scan->frac;
    651 		in = scan;
    652 	    }
    653 	}
    654 	
    655 	if (dist > maxfrac)
    656 	    return true;	
    657 
    658 #if 0  
    659     {
    660 	
    661 	in = scan = intercepts;
    662 	for ( scan = intercepts ; scan<intercept_p ; scan++)
    663 	    if (scan->frac > maxfrac)
    664 		*in++ = *scan;
    665 	intercept_p = in;
    666 	return false;
    667     }
    668 #endif
    669 
    670         if ( !func (in) )
    671 	    return false;	
    672 
    673 	in->frac = INT_MAX;
    674     }
    675 	
    676     return true;		
    677 }
    678 
    679 
    680 
    681 
    682 
    683 
    684 
    685 
    686 
    687 
    688 
    689 boolean
    690 P_PathTraverse
    691 ( fixed_t		x1,
    692   fixed_t		y1,
    693   fixed_t		x2,
    694   fixed_t		y2,
    695   int			flags,
    696   boolean (*trav) (intercept_t *))
    697 {
    698     fixed_t	xt1;
    699     fixed_t	yt1;
    700     fixed_t	xt2;
    701     fixed_t	yt2;
    702     
    703     fixed_t	xstep;
    704     fixed_t	ystep;
    705     
    706     fixed_t	partial;
    707     
    708     fixed_t	xintercept;
    709     fixed_t	yintercept;
    710     
    711     int		mapx;
    712     int		mapy;
    713     
    714     int		mapxstep;
    715     int		mapystep;
    716 
    717     int		count;
    718 		
    719     earlyout = flags & PT_EARLYOUT;
    720 		
    721     validcount++;
    722     intercept_p = intercepts;
    723 	
    724     if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
    725 	x1 += FRACUNIT;	
    726     
    727     if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
    728 	y1 += FRACUNIT;	
    729 
    730     trace.x = x1;
    731     trace.y = y1;
    732     trace.dx = x2 - x1;
    733     trace.dy = y2 - y1;
    734 
    735     x1 -= bmaporgx;
    736     y1 -= bmaporgy;
    737     xt1 = x1>>MAPBLOCKSHIFT;
    738     yt1 = y1>>MAPBLOCKSHIFT;
    739 
    740     x2 -= bmaporgx;
    741     y2 -= bmaporgy;
    742     xt2 = x2>>MAPBLOCKSHIFT;
    743     yt2 = y2>>MAPBLOCKSHIFT;
    744 
    745     if (xt2 > xt1)
    746     {
    747 	mapxstep = 1;
    748 	partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
    749 	ystep = FixedDiv (y2-y1,abs(x2-x1));
    750     }
    751     else if (xt2 < xt1)
    752     {
    753 	mapxstep = -1;
    754 	partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
    755 	ystep = FixedDiv (y2-y1,abs(x2-x1));
    756     }
    757     else
    758     {
    759 	mapxstep = 0;
    760 	partial = FRACUNIT;
    761 	ystep = 256*FRACUNIT;
    762     }	
    763 
    764     yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
    765 
    766 	
    767     if (yt2 > yt1)
    768     {
    769 	mapystep = 1;
    770 	partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
    771 	xstep = FixedDiv (x2-x1,abs(y2-y1));
    772     }
    773     else if (yt2 < yt1)
    774     {
    775 	mapystep = -1;
    776 	partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
    777 	xstep = FixedDiv (x2-x1,abs(y2-y1));
    778     }
    779     else
    780     {
    781 	mapystep = 0;
    782 	partial = FRACUNIT;
    783 	xstep = 256*FRACUNIT;
    784     }	
    785     xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
    786     
    787     
    788     
    789     
    790     mapx = xt1;
    791     mapy = yt1;
    792 	
    793     for (count = 0 ; count < 64 ; count++)
    794     {
    795 	if (flags & PT_ADDLINES)
    796 	{
    797 	    if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts))
    798 		return false;	
    799 	}
    800 	
    801 	if (flags & PT_ADDTHINGS)
    802 	{
    803 	    if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts))
    804 		return false;	
    805 	}
    806 		
    807 	if (mapx == xt2
    808 	    && mapy == yt2)
    809 	{
    810 	    break;
    811 	}
    812 	
    813 	if ( (yintercept >> FRACBITS) == mapy)
    814 	{
    815 	    yintercept += ystep;
    816 	    mapx += mapxstep;
    817 	}
    818 	else if ( (xintercept >> FRACBITS) == mapx)
    819 	{
    820 	    xintercept += xstep;
    821 	    mapy += mapystep;
    822 	}
    823 		
    824     }
    825     
    826     return P_TraverseIntercepts ( trav, FRACUNIT );
    827 }
    828 
    829 
    830