14 = Gives an estimation of distance (not exact)
19 fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
38 int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line)
56 dx = (x - line->v1->x);
57 dy = (y - line->v1->y);
59 left = FixedMul ( line->dy>>FRACBITS , dx );
60 right = FixedMul ( dy , line->dx>>FRACBITS );
63 return 0; // front side
64 return 1; // back side
73 = Considers the line to be infinite
74 = Returns side 0 or 1, -1 if box crosses the line
78 int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld)
82 switch (ld->slopetype)
85 p1 = tmbox[BOXTOP] > ld->v1->y;
86 p2 = tmbox[BOXBOTTOM] > ld->v1->y;
94 p1 = tmbox[BOXRIGHT] < ld->v1->x;
95 p2 = tmbox[BOXLEFT] < ld->v1->x;
103 p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
104 p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
107 p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
108 p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
120 = P_PointOnDivlineSide
126 int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line)
147 // try to quickly decide by looking at sign bits
148 if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
150 if ( (line->dy ^ dx) & 0x80000000 )
151 return 1; // (left is negative)
155 left = FixedMul ( line->dy>>8, dx>>8 );
156 right = FixedMul ( dy>>8 , line->dx>>8 );
159 return 0; // front side
160 return 1; // back side
173 void P_MakeDivline (line_t *li, divline_t *dl)
187 = Returns the fractional intercept point along the first divline
189 = This is only called by the addthings and addlines traversers
193 fixed_t P_InterceptVector (divline_t *v2, divline_t *v1)
196 fixed_t frac, num, den;
198 den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
201 // I_Error ("P_InterceptVector: parallel");
202 num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) +
203 FixedMul ( (v2->y - v1->y)>>8 , v1->dx);
204 frac = FixedDiv (num , den);
208 float frac, num, den, v1x,v1y,v1dx,v1dy,v2x,v2y,v2dx,v2dy;
210 v1x = (float)v1->x/FRACUNIT;
211 v1y = (float)v1->y/FRACUNIT;
212 v1dx = (float)v1->dx/FRACUNIT;
213 v1dy = (float)v1->dy/FRACUNIT;
214 v2x = (float)v2->x/FRACUNIT;
215 v2y = (float)v2->y/FRACUNIT;
216 v2dx = (float)v2->dx/FRACUNIT;
217 v2dy = (float)v2->dy/FRACUNIT;
219 den = v1dy*v2dx - v1dx*v2dy;
221 return 0; // parallel
222 num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
225 return frac*FRACUNIT;
234 = Sets opentop and openbottom to the window through a two sided line
235 = OPTIMIZE: keep this precalculated
239 fixed_t opentop, openbottom, openrange;
242 void P_LineOpening (line_t *linedef)
244 sector_t *front, *back;
246 if (linedef->sidenum[1] == -1)
247 { // single sided line
252 front = linedef->frontsector;
253 back = linedef->backsector;
255 if (front->ceilingheight < back->ceilingheight)
256 opentop = front->ceilingheight;
258 opentop = back->ceilingheight;
259 if (front->floorheight > back->floorheight)
261 openbottom = front->floorheight;
262 lowfloor = back->floorheight;
266 openbottom = back->floorheight;
267 lowfloor = front->floorheight;
270 openrange = opentop - openbottom;
274 ===============================================================================
276 THING POSITION SETTING
278 ===============================================================================
284 = P_UnsetThingPosition
286 = Unlinks a thing from block map and sectors
291 void P_UnsetThingPosition (mobj_t *thing)
295 if ( ! (thing->flags & MF_NOSECTOR) )
296 { // inert things don't need to be in blockmap
297 // unlink from subsector
299 thing->snext->sprev = thing->sprev;
301 thing->sprev->snext = thing->snext;
303 thing->subsector->sector->thinglist = thing->snext;
306 if ( ! (thing->flags & MF_NOBLOCKMAP) )
307 { // inert things don't need to be in blockmap
308 // unlink from block map
310 thing->bnext->bprev = thing->bprev;
312 thing->bprev->bnext = thing->bnext;
315 blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
316 blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
317 if (blockx>=0 && blockx < bmapwidth
318 && blocky>=0 && blocky <bmapheight)
319 blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
330 = Links a thing into both a block and a subsector based on it's x y
331 = Sets thing->subsector properly
336 void P_SetThingPosition (mobj_t *thing)
344 // link into subsector
346 ss = R_PointInSubsector (thing->x,thing->y);
347 thing->subsector = ss;
348 if ( ! (thing->flags & MF_NOSECTOR) )
349 { // invisible things don't go into the sector links
353 thing->snext = sec->thinglist;
355 sec->thinglist->sprev = thing;
356 sec->thinglist = thing;
360 // link into blockmap
362 if ( ! (thing->flags & MF_NOBLOCKMAP) )
363 { // inert things don't need to be in blockmap
364 blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
365 blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
366 if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky <bmapheight)
368 link = &blocklinks[blocky*bmapwidth+blockx];
370 thing->bnext = *link;
372 (*link)->bprev = thing;
376 { // thing is off the map
377 thing->bnext = thing->bprev = NULL;
385 ===============================================================================
389 For each line/thing in the given mapblock, call the passed function.
390 If the function returns false, exit with false without checking anything else.
392 ===============================================================================
398 = P_BlockLinesIterator
400 = The validcount flags are used to avoid checking lines
401 = that are marked in multiple mapblocks, so increment validcount before
402 = the first call to P_BlockLinesIterator, then make one or more calls to it
406 boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) )
412 if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
414 offset = y*bmapwidth+x;
416 offset = *(blockmap+offset);
418 for ( list = blockmaplump+offset ; *list != -1 ; list++)
421 if (ld->validcount == validcount)
422 continue; // line has already been checked
423 ld->validcount = validcount;
429 return true; // everything was checked
436 = P_BlockThingsIterator
441 boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) )
445 if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
448 for (mobj = blocklinks[y*bmapwidth+x] ; mobj ; mobj = mobj->bnext)
456 ===============================================================================
460 ===============================================================================
463 intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
472 = PIT_AddLineIntercepts
474 = Looks for lines in the given block that intercept the given trace
475 = to add to the intercepts list
476 = A line is crossed if its endpoints are on opposite sides of the trace
477 = Returns true if earlyout and a solid line hit
481 boolean PIT_AddLineIntercepts (line_t *ld)
487 // avoid precision problems with two routines
488 if ( trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16
489 || trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
491 s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
492 s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
496 s1 = P_PointOnLineSide (trace.x, trace.y, ld);
497 s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
500 return true; // line isn't crossed
505 P_MakeDivline (ld, &dl);
506 frac = P_InterceptVector (&trace, &dl);
508 return true; // behind source
510 // try to early out the check
511 if (earlyout && frac < FRACUNIT && !ld->backsector)
512 return false; // stop checking
514 intercept_p->frac = frac;
515 intercept_p->isaline = true;
516 intercept_p->d.line = ld;
519 return true; // continue
527 = PIT_AddThingIntercepts
532 boolean PIT_AddThingIntercepts (mobj_t *thing)
534 fixed_t x1,y1, x2,y2;
536 boolean tracepositive;
540 tracepositive = (trace.dx ^ trace.dy)>0;
542 // check a corner to corner crossection for hit
546 x1 = thing->x - thing->radius;
547 y1 = thing->y + thing->radius;
549 x2 = thing->x + thing->radius;
550 y2 = thing->y - thing->radius;
554 x1 = thing->x - thing->radius;
555 y1 = thing->y - thing->radius;
557 x2 = thing->x + thing->radius;
558 y2 = thing->y + thing->radius;
560 s1 = P_PointOnDivlineSide (x1, y1, &trace);
561 s2 = P_PointOnDivlineSide (x2, y2, &trace);
563 return true; // line isn't crossed
569 frac = P_InterceptVector (&trace, &dl);
571 return true; // behind source
572 intercept_p->frac = frac;
573 intercept_p->isaline = false;
574 intercept_p->d.thing = thing;
577 return true; // keep going
584 = P_TraverseIntercepts
586 = Returns true if the traverser function returns true for all lines
590 boolean P_TraverseIntercepts ( traverser_t func, fixed_t maxfrac )
594 intercept_t *scan, *in;
596 count = intercept_p - intercepts;
597 in = 0; // shut up compiler warning
602 for (scan = intercepts ; scan<intercept_p ; scan++)
603 if (scan->frac < dist)
610 return true; // checked everything in range
612 { // don't check these yet, ther may be others inserted
613 in = scan = intercepts;
614 for ( scan = intercepts ; scan<intercept_p ; scan++)
615 if (scan->frac > maxfrac)
623 return false; // don't bother going farther
627 return true; // everything was traversed
637 = Traces a line from x1,y1 to x2,y2, calling the traverser function for each
638 = Returns true if the traverser function returns true for all lines
642 boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
643 int flags, boolean (*trav) (intercept_t *))
645 fixed_t xt1,yt1,xt2,yt2;
648 fixed_t xintercept, yintercept;
649 int mapx, mapy, mapxstep, mapystep;
652 earlyout = flags & PT_EARLYOUT;
655 intercept_p = intercepts;
657 if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
658 x1 += FRACUNIT; // don't side exactly on a line
659 if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
660 y1 += FRACUNIT; // don't side exactly on a line
668 xt1 = x1>>MAPBLOCKSHIFT;
669 yt1 = y1>>MAPBLOCKSHIFT;
673 xt2 = x2>>MAPBLOCKSHIFT;
674 yt2 = y2>>MAPBLOCKSHIFT;
679 partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
680 ystep = FixedDiv (y2-y1,abs(x2-x1));
685 partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
686 ystep = FixedDiv (y2-y1,abs(x2-x1));
692 ystep = 256*FRACUNIT;
694 yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
700 partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
701 xstep = FixedDiv (x2-x1,abs(y2-y1));
706 partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
707 xstep = FixedDiv (x2-x1,abs(y2-y1));
713 xstep = 256*FRACUNIT;
715 xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
719 // step through map blocks
720 // Count is present to prevent a round off error from skipping the break
724 for (count = 0 ; count < 64 ; count++)
726 if (flags & PT_ADDLINES)
728 if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts))
729 return false; // early out
731 if (flags & PT_ADDTHINGS)
733 if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts))
734 return false; // early out
737 if (mapx == xt2 && mapy == yt2)
740 if ( (yintercept >> FRACBITS) == mapy)
745 else if ( (xintercept >> FRACBITS) == mapx)
755 // go through the sorted list
757 return P_TraverseIntercepts ( trav, FRACUNIT );