1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // Movement/collision utility functions,
24 // as used by function in p_map.c.
25 // BLOCKMAP Iterator functions,
26 // and some PIT_* functions to use for iteration.
28 //-----------------------------------------------------------------------------
48 // Gives an estimation of distance (not exact)
94 dx
= (x
- line
->v1
->x
);
95 dy
= (y
- line
->v1
->y
);
97 left
= FixedMul ( line
->dy
>>FRACBITS
, dx
);
98 right
= FixedMul ( dy
, line
->dx
>>FRACBITS
);
101 return 0; // front side
102 return 1; // back side
109 // Considers the line to be infinite
110 // Returns side 0 or 1, -1 if box crosses the line.
120 switch (ld
->slopetype
)
123 p1
= tmbox
[BOXTOP
] > ld
->v1
->y
;
124 p2
= tmbox
[BOXBOTTOM
] > ld
->v1
->y
;
133 p1
= tmbox
[BOXRIGHT
] < ld
->v1
->x
;
134 p2
= tmbox
[BOXLEFT
] < ld
->v1
->x
;
143 p1
= P_PointOnLineSide (tmbox
[BOXLEFT
], tmbox
[BOXTOP
], ld
);
144 p2
= P_PointOnLineSide (tmbox
[BOXRIGHT
], tmbox
[BOXBOTTOM
], ld
);
148 p1
= P_PointOnLineSide (tmbox
[BOXRIGHT
], tmbox
[BOXTOP
], ld
);
149 p2
= P_PointOnLineSide (tmbox
[BOXLEFT
], tmbox
[BOXBOTTOM
], ld
);
160 // P_PointOnDivlineSide
192 // try to quickly decide by looking at sign bits
193 if ( (line
->dy
^ line
->dx
^ dx
^ dy
)&0x80000000 )
195 if ( (line
->dy
^ dx
) & 0x80000000 )
196 return 1; // (left is negative)
200 left
= FixedMul ( line
->dy
>>8, dx
>>8 );
201 right
= FixedMul ( dy
>>8 , line
->dx
>>8 );
204 return 0; // front side
205 return 1; // back side
228 // Returns the fractional intercept point
229 // along the first divline.
230 // This is only called by the addthings
231 // and addlines traversers.
243 den
= FixedMul (v1
->dy
>>8,v2
->dx
) - FixedMul(v1
->dx
>>8,v2
->dy
);
247 // I_Error ("P_InterceptVector: parallel");
250 FixedMul ( (v1
->x
- v2
->x
)>>8 ,v1
->dy
)
251 +FixedMul ( (v2
->y
- v1
->y
)>>8, v1
->dx
);
253 frac
= FixedDiv (num
, den
);
256 #else // UNUSED, float debug.
269 v1x
= (float)v1
->x
/FRACUNIT
;
270 v1y
= (float)v1
->y
/FRACUNIT
;
271 v1dx
= (float)v1
->dx
/FRACUNIT
;
272 v1dy
= (float)v1
->dy
/FRACUNIT
;
273 v2x
= (float)v2
->x
/FRACUNIT
;
274 v2y
= (float)v2
->y
/FRACUNIT
;
275 v2dx
= (float)v2
->dx
/FRACUNIT
;
276 v2dy
= (float)v2
->dy
/FRACUNIT
;
278 den
= v1dy
*v2dx
- v1dx
*v2dy
;
281 return 0; // parallel
283 num
= (v1x
- v2x
)*v1dy
+ (v2y
- v1y
)*v1dx
;
286 return frac
*FRACUNIT
;
293 // Sets opentop and openbottom to the window
294 // through a two sided line.
295 // OPTIMIZE: keep this precalculated
303 void P_LineOpening (line_t
* linedef
)
308 if (linedef
->sidenum
[1] == -1)
315 front
= linedef
->frontsector
;
316 back
= linedef
->backsector
;
318 if (front
->ceilingheight
< back
->ceilingheight
)
319 opentop
= front
->ceilingheight
;
321 opentop
= back
->ceilingheight
;
323 if (front
->floorheight
> back
->floorheight
)
325 openbottom
= front
->floorheight
;
326 lowfloor
= back
->floorheight
;
330 openbottom
= back
->floorheight
;
331 lowfloor
= front
->floorheight
;
334 openrange
= opentop
- openbottom
;
339 // THING POSITION SETTING
344 // P_UnsetThingPosition
345 // Unlinks a thing from block map and sectors.
346 // On each position change, BLOCKMAP and other
347 // lookups maintaining lists ot things inside
348 // these structures need to be updated.
350 void P_UnsetThingPosition (mobj_t
* thing
)
355 if ( ! (thing
->flags
& MF_NOSECTOR
) )
357 // inert things don't need to be in blockmap?
358 // unlink from subsector
360 thing
->snext
->sprev
= thing
->sprev
;
363 thing
->sprev
->snext
= thing
->snext
;
365 thing
->subsector
->sector
->thinglist
= thing
->snext
;
368 if ( ! (thing
->flags
& MF_NOBLOCKMAP
) )
370 // inert things don't need to be in blockmap
371 // unlink from block map
373 thing
->bnext
->bprev
= thing
->bprev
;
376 thing
->bprev
->bnext
= thing
->bnext
;
379 blockx
= (thing
->x
- bmaporgx
)>>MAPBLOCKSHIFT
;
380 blocky
= (thing
->y
- bmaporgy
)>>MAPBLOCKSHIFT
;
382 if (blockx
>=0 && blockx
< bmapwidth
383 && blocky
>=0 && blocky
<bmapheight
)
385 blocklinks
[blocky
*bmapwidth
+blockx
] = thing
->bnext
;
393 // P_SetThingPosition
394 // Links a thing into both a block and a subsector
395 // based on it's x y.
396 // Sets thing->subsector properly
399 P_SetThingPosition (mobj_t
* thing
)
408 // link into subsector
409 ss
= R_PointInSubsector (thing
->x
,thing
->y
);
410 thing
->subsector
= ss
;
412 if ( ! (thing
->flags
& MF_NOSECTOR
) )
414 // invisible things don't go into the sector links
418 thing
->snext
= sec
->thinglist
;
421 sec
->thinglist
->sprev
= thing
;
423 sec
->thinglist
= thing
;
427 // link into blockmap
428 if ( ! (thing
->flags
& MF_NOBLOCKMAP
) )
430 // inert things don't need to be in blockmap
431 blockx
= (thing
->x
- bmaporgx
)>>MAPBLOCKSHIFT
;
432 blocky
= (thing
->y
- bmaporgy
)>>MAPBLOCKSHIFT
;
435 && blockx
< bmapwidth
437 && blocky
< bmapheight
)
439 link
= &blocklinks
[blocky
*bmapwidth
+blockx
];
441 thing
->bnext
= *link
;
443 (*link
)->bprev
= thing
;
449 // thing is off the map
450 thing
->bnext
= thing
->bprev
= NULL
;
458 // BLOCK MAP ITERATORS
459 // For each line/thing in the given mapblock,
460 // call the passed PIT_* function.
461 // If the function returns false,
462 // exit with false without checking anything else.
467 // P_BlockLinesIterator
468 // The validcount flags are used to avoid checking lines
469 // that are marked in multiple mapblocks,
470 // so increment validcount before the first call
471 // to P_BlockLinesIterator, then make one or more calls
478 boolean(*func
)(line_t
*) )
492 offset
= y
*bmapwidth
+x
;
494 offset
= *(blockmap
+offset
);
496 for ( list
= blockmaplump
+offset
; *list
!= -1 ; list
++)
500 if (ld
->validcount
== validcount
)
501 continue; // line has already been checked
503 ld
->validcount
= validcount
;
508 return true; // everything was checked
513 // P_BlockThingsIterator
516 P_BlockThingsIterator
519 boolean(*func
)(mobj_t
*) )
532 for (mobj
= blocklinks
[y
*bmapwidth
+x
] ;
545 // INTERCEPT ROUTINES
547 intercept_t intercepts
[MAXINTERCEPTS
];
548 intercept_t
* intercept_p
;
555 // PIT_AddLineIntercepts.
556 // Looks for lines in the given block
557 // that intercept the given trace
558 // to add to the intercepts list.
560 // A line is crossed if its endpoints
561 // are on opposite sides of the trace.
562 // Returns true if earlyout and a solid line hit.
565 PIT_AddLineIntercepts (line_t
* ld
)
572 // avoid precision problems with two routines
573 if ( trace
.dx
> FRACUNIT
*16
574 || trace
.dy
> FRACUNIT
*16
575 || trace
.dx
< -FRACUNIT
*16
576 || trace
.dy
< -FRACUNIT
*16)
578 s1
= P_PointOnDivlineSide (ld
->v1
->x
, ld
->v1
->y
, &trace
);
579 s2
= P_PointOnDivlineSide (ld
->v2
->x
, ld
->v2
->y
, &trace
);
583 s1
= P_PointOnLineSide (trace
.x
, trace
.y
, ld
);
584 s2
= P_PointOnLineSide (trace
.x
+trace
.dx
, trace
.y
+trace
.dy
, ld
);
588 return true; // line isn't crossed
591 P_MakeDivline (ld
, &dl
);
592 frac
= P_InterceptVector (&trace
, &dl
);
595 return true; // behind source
597 // try to early out the check
602 return false; // stop checking
606 intercept_p
->frac
= frac
;
607 intercept_p
->isaline
= true;
608 intercept_p
->d
.line
= ld
;
611 return true; // continue
617 // PIT_AddThingIntercepts
619 boolean
PIT_AddThingIntercepts (mobj_t
* thing
)
629 boolean tracepositive
;
635 tracepositive
= (trace
.dx
^ trace
.dy
)>0;
637 // check a corner to corner crossection for hit
640 x1
= thing
->x
- thing
->radius
;
641 y1
= thing
->y
+ thing
->radius
;
643 x2
= thing
->x
+ thing
->radius
;
644 y2
= thing
->y
- thing
->radius
;
648 x1
= thing
->x
- thing
->radius
;
649 y1
= thing
->y
- thing
->radius
;
651 x2
= thing
->x
+ thing
->radius
;
652 y2
= thing
->y
+ thing
->radius
;
655 s1
= P_PointOnDivlineSide (x1
, y1
, &trace
);
656 s2
= P_PointOnDivlineSide (x2
, y2
, &trace
);
659 return true; // line isn't crossed
666 frac
= P_InterceptVector (&trace
, &dl
);
669 return true; // behind source
671 intercept_p
->frac
= frac
;
672 intercept_p
->isaline
= false;
673 intercept_p
->d
.thing
= thing
;
676 return true; // keep going
681 // P_TraverseIntercepts
682 // Returns true if the traverser function returns true
695 count
= intercept_p
- intercepts
;
697 in
= 0; // shut up compiler warning
702 for (scan
= intercepts
; scan
<intercept_p
; scan
++)
704 if (scan
->frac
< dist
)
712 return true; // checked everything in range
716 // don't check these yet, there may be others inserted
717 in
= scan
= intercepts
;
718 for ( scan
= intercepts
; scan
<intercept_p
; scan
++)
719 if (scan
->frac
> maxfrac
)
727 return false; // don't bother going farther
732 return true; // everything was traversed
740 // Traces a line from x1,y1 to x2,y2,
741 // calling the traverser function for each.
742 // Returns true if the traverser function returns true
752 boolean (*trav
) (intercept_t
*))
775 earlyout
= flags
& PT_EARLYOUT
;
778 intercept_p
= intercepts
;
780 if ( ((x1
-bmaporgx
)&(MAPBLOCKSIZE
-1)) == 0)
781 x1
+= FRACUNIT
; // don't side exactly on a line
783 if ( ((y1
-bmaporgy
)&(MAPBLOCKSIZE
-1)) == 0)
784 y1
+= FRACUNIT
; // don't side exactly on a line
793 xt1
= x1
>>MAPBLOCKSHIFT
;
794 yt1
= y1
>>MAPBLOCKSHIFT
;
798 xt2
= x2
>>MAPBLOCKSHIFT
;
799 yt2
= y2
>>MAPBLOCKSHIFT
;
804 partial
= FRACUNIT
- ((x1
>>MAPBTOFRAC
)&(FRACUNIT
-1));
805 ystep
= FixedDiv (y2
-y1
,iabs(x2
-x1
));
810 partial
= (x1
>>MAPBTOFRAC
)&(FRACUNIT
-1);
811 ystep
= FixedDiv (y2
-y1
,iabs(x2
-x1
));
817 ystep
= 256*FRACUNIT
;
820 yintercept
= (y1
>>MAPBTOFRAC
) + FixedMul (partial
, ystep
);
826 partial
= FRACUNIT
- ((y1
>>MAPBTOFRAC
)&(FRACUNIT
-1));
827 xstep
= FixedDiv (x2
-x1
,iabs(y2
-y1
));
832 partial
= (y1
>>MAPBTOFRAC
)&(FRACUNIT
-1);
833 xstep
= FixedDiv (x2
-x1
,iabs(y2
-y1
));
839 xstep
= 256*FRACUNIT
;
841 xintercept
= (x1
>>MAPBTOFRAC
) + FixedMul (partial
, xstep
);
843 // Step through map blocks.
844 // Count is present to prevent a round off error
845 // from skipping the break.
849 for (count
= 0 ; count
< 64 ; count
++)
851 if (flags
& PT_ADDLINES
)
853 if (!P_BlockLinesIterator (mapx
, mapy
,PIT_AddLineIntercepts
))
854 return false; // early out
857 if (flags
& PT_ADDTHINGS
)
859 if (!P_BlockThingsIterator (mapx
, mapy
,PIT_AddThingIntercepts
))
860 return false; // early out
869 if ( (yintercept
>> FRACBITS
) == mapy
)
874 else if ( (xintercept
>> FRACBITS
) == mapx
)
881 // go through the sorted list
882 return P_TraverseIntercepts ( trav
, FRACUNIT
);