P_SIGHT.C 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. // P_sight.c
  2. #include "DoomDef.h"
  3. #include "P_local.h"
  4. /*
  5. ==============================================================================
  6. P_CheckSight
  7. This uses specialized forms of the maputils routines for optimized performance
  8. ==============================================================================
  9. */
  10. fixed_t sightzstart; // eye z of looker
  11. fixed_t topslope, bottomslope; // slopes to top and bottom of target
  12. int sightcounts[3];
  13. /*
  14. ==============
  15. =
  16. = PTR_SightTraverse
  17. =
  18. ==============
  19. */
  20. boolean PTR_SightTraverse (intercept_t *in)
  21. {
  22. line_t *li;
  23. fixed_t slope;
  24. li = in->d.line;
  25. //
  26. // crosses a two sided line
  27. //
  28. P_LineOpening (li);
  29. if (openbottom >= opentop) // quick test for totally closed doors
  30. return false; // stop
  31. if (li->frontsector->floorheight != li->backsector->floorheight)
  32. {
  33. slope = FixedDiv (openbottom - sightzstart , in->frac);
  34. if (slope > bottomslope)
  35. bottomslope = slope;
  36. }
  37. if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  38. {
  39. slope = FixedDiv (opentop - sightzstart , in->frac);
  40. if (slope < topslope)
  41. topslope = slope;
  42. }
  43. if (topslope <= bottomslope)
  44. return false; // stop
  45. return true; // keep going
  46. }
  47. /*
  48. ==================
  49. =
  50. = P_SightBlockLinesIterator
  51. =
  52. ===================
  53. */
  54. boolean P_SightBlockLinesIterator (int x, int y )
  55. {
  56. int offset;
  57. short *list;
  58. line_t *ld;
  59. int s1, s2;
  60. divline_t dl;
  61. offset = y*bmapwidth+x;
  62. offset = *(blockmap+offset);
  63. for ( list = blockmaplump+offset ; *list != -1 ; list++)
  64. {
  65. ld = &lines[*list];
  66. if (ld->validcount == validcount)
  67. continue; // line has already been checked
  68. ld->validcount = validcount;
  69. s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
  70. s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
  71. if (s1 == s2)
  72. continue; // line isn't crossed
  73. P_MakeDivline (ld, &dl);
  74. s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
  75. s2 = P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl);
  76. if (s1 == s2)
  77. continue; // line isn't crossed
  78. // try to early out the check
  79. if (!ld->backsector)
  80. return false; // stop checking
  81. // store the line for later intersection testing
  82. intercept_p->d.line = ld;
  83. intercept_p++;
  84. }
  85. return true; // everything was checked
  86. }
  87. /*
  88. ====================
  89. =
  90. = P_SightTraverseIntercepts
  91. =
  92. = Returns true if the traverser function returns true for all lines
  93. ====================
  94. */
  95. boolean P_SightTraverseIntercepts ( void )
  96. {
  97. int count;
  98. fixed_t dist;
  99. intercept_t *scan, *in;
  100. divline_t dl;
  101. count = intercept_p - intercepts;
  102. //
  103. // calculate intercept distance
  104. //
  105. for (scan = intercepts ; scan<intercept_p ; scan++)
  106. {
  107. P_MakeDivline (scan->d.line, &dl);
  108. scan->frac = P_InterceptVector (&trace, &dl);
  109. }
  110. //
  111. // go through in order
  112. //
  113. in = 0; // shut up compiler warning
  114. while (count--)
  115. {
  116. dist = MAXINT;
  117. for (scan = intercepts ; scan<intercept_p ; scan++)
  118. if (scan->frac < dist)
  119. {
  120. dist = scan->frac;
  121. in = scan;
  122. }
  123. if ( !PTR_SightTraverse (in) )
  124. return false; // don't bother going farther
  125. in->frac = MAXINT;
  126. }
  127. return true; // everything was traversed
  128. }
  129. /*
  130. ==================
  131. =
  132. = P_SightPathTraverse
  133. =
  134. = Traces a line from x1,y1 to x2,y2, calling the traverser function for each
  135. = Returns true if the traverser function returns true for all lines
  136. ==================
  137. */
  138. boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
  139. {
  140. fixed_t xt1,yt1,xt2,yt2;
  141. fixed_t xstep,ystep;
  142. fixed_t partial;
  143. fixed_t xintercept, yintercept;
  144. int mapx, mapy, mapxstep, mapystep;
  145. int count;
  146. validcount++;
  147. intercept_p = intercepts;
  148. if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
  149. x1 += FRACUNIT; // don't side exactly on a line
  150. if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
  151. y1 += FRACUNIT; // don't side exactly on a line
  152. trace.x = x1;
  153. trace.y = y1;
  154. trace.dx = x2 - x1;
  155. trace.dy = y2 - y1;
  156. x1 -= bmaporgx;
  157. y1 -= bmaporgy;
  158. xt1 = x1>>MAPBLOCKSHIFT;
  159. yt1 = y1>>MAPBLOCKSHIFT;
  160. x2 -= bmaporgx;
  161. y2 -= bmaporgy;
  162. xt2 = x2>>MAPBLOCKSHIFT;
  163. yt2 = y2>>MAPBLOCKSHIFT;
  164. // points should never be out of bounds, but check once instead of
  165. // each block
  166. if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight
  167. || xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight)
  168. return false;
  169. if (xt2 > xt1)
  170. {
  171. mapxstep = 1;
  172. partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
  173. ystep = FixedDiv (y2-y1,abs(x2-x1));
  174. }
  175. else if (xt2 < xt1)
  176. {
  177. mapxstep = -1;
  178. partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
  179. ystep = FixedDiv (y2-y1,abs(x2-x1));
  180. }
  181. else
  182. {
  183. mapxstep = 0;
  184. partial = FRACUNIT;
  185. ystep = 256*FRACUNIT;
  186. }
  187. yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
  188. if (yt2 > yt1)
  189. {
  190. mapystep = 1;
  191. partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
  192. xstep = FixedDiv (x2-x1,abs(y2-y1));
  193. }
  194. else if (yt2 < yt1)
  195. {
  196. mapystep = -1;
  197. partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
  198. xstep = FixedDiv (x2-x1,abs(y2-y1));
  199. }
  200. else
  201. {
  202. mapystep = 0;
  203. partial = FRACUNIT;
  204. xstep = 256*FRACUNIT;
  205. }
  206. xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
  207. //
  208. // step through map blocks
  209. // Count is present to prevent a round off error from skipping the break
  210. mapx = xt1;
  211. mapy = yt1;
  212. for (count = 0 ; count < 64 ; count++)
  213. {
  214. if (!P_SightBlockLinesIterator (mapx, mapy))
  215. {
  216. sightcounts[1]++;
  217. return false; // early out
  218. }
  219. if (mapx == xt2 && mapy == yt2)
  220. break;
  221. if ( (yintercept >> FRACBITS) == mapy)
  222. {
  223. yintercept += ystep;
  224. mapx += mapxstep;
  225. }
  226. else if ( (xintercept >> FRACBITS) == mapx)
  227. {
  228. xintercept += xstep;
  229. mapy += mapystep;
  230. }
  231. }
  232. //
  233. // couldn't early out, so go through the sorted list
  234. //
  235. sightcounts[2]++;
  236. return P_SightTraverseIntercepts ( );
  237. }
  238. /*
  239. =====================
  240. =
  241. = P_CheckSight
  242. =
  243. = Returns true if a straight line between t1 and t2 is unobstructed
  244. = look from eyes of t1 to any part of t2
  245. =
  246. =====================
  247. */
  248. boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
  249. {
  250. int s1, s2;
  251. int pnum, bytenum, bitnum;
  252. //
  253. // check for trivial rejection
  254. //
  255. s1 = (t1->subsector->sector - sectors);
  256. s2 = (t2->subsector->sector - sectors);
  257. pnum = s1*numsectors + s2;
  258. bytenum = pnum>>3;
  259. bitnum = 1 << (pnum&7);
  260. if (rejectmatrix[bytenum]&bitnum)
  261. {
  262. sightcounts[0]++;
  263. return false; // can't possibly be connected
  264. }
  265. //
  266. // check precisely
  267. //
  268. sightzstart = t1->z + t1->height - (t1->height>>2);
  269. topslope = (t2->z+t2->height) - sightzstart;
  270. bottomslope = (t2->z) - sightzstart;
  271. return P_SightPathTraverse ( t1->x, t1->y, t2->x, t2->y );
  272. }