P_SIGHT.C 8.2 KB

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