R_BSP.C 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. // R_bsp.c
  2. #include "DoomDef.h"
  3. #include "R_local.h"
  4. seg_t *curline;
  5. side_t *sidedef;
  6. line_t *linedef;
  7. sector_t *frontsector, *backsector;
  8. drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
  9. void R_StoreWallRange (int start, int stop);
  10. /*
  11. ====================
  12. =
  13. = R_ClearDrawSegs
  14. =
  15. ====================
  16. */
  17. void R_ClearDrawSegs (void)
  18. {
  19. ds_p = drawsegs;
  20. }
  21. //=============================================================================
  22. /*
  23. ===============================================================================
  24. =
  25. = ClipWallSegment
  26. =
  27. = Clips the given range of columns and includes it in the new clip list
  28. ===============================================================================
  29. */
  30. typedef struct
  31. {
  32. int first, last;
  33. } cliprange_t;
  34. #define MAXSEGS 32
  35. cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg
  36. void R_ClipSolidWallSegment (int first, int last)
  37. {
  38. cliprange_t *next, *start;
  39. // find the first range that touches the range (adjacent pixels are touching)
  40. start = solidsegs;
  41. while (start->last < first-1)
  42. start++;
  43. if (first < start->first)
  44. {
  45. if (last < start->first-1)
  46. { // post is entirely visible (above start), so insert a new clippost
  47. R_StoreWallRange (first, last);
  48. next = newend;
  49. newend++;
  50. while (next != start)
  51. {
  52. *next = *(next-1);
  53. next--;
  54. }
  55. next->first = first;
  56. next->last = last;
  57. return;
  58. }
  59. // there is a fragment above *start
  60. R_StoreWallRange (first, start->first - 1);
  61. start->first = first; // adjust the clip size
  62. }
  63. if (last <= start->last)
  64. return; // bottom contained in start
  65. next = start;
  66. while (last >= (next+1)->first-1)
  67. {
  68. // there is a fragment between two posts
  69. R_StoreWallRange (next->last + 1, (next+1)->first - 1);
  70. next++;
  71. if (last <= next->last)
  72. { // bottom is contained in next
  73. start->last = next->last; // adjust the clip size
  74. goto crunch;
  75. }
  76. }
  77. // there is a fragment after *next
  78. R_StoreWallRange (next->last + 1, last);
  79. start->last = last; // adjust the clip size
  80. // remove start+1 to next from the clip list,
  81. // because start now covers their area
  82. crunch:
  83. if (next == start)
  84. return; // post just extended past the bottom of one post
  85. while (next++ != newend) // remove a post
  86. *++start = *next;
  87. newend = start+1;
  88. }
  89. /*
  90. ===============================================================================
  91. =
  92. = R_ClipPassWallSegment
  93. =
  94. = Clips the given range of columns, but does not includes it in the clip list
  95. ===============================================================================
  96. */
  97. void R_ClipPassWallSegment (int first, int last)
  98. {
  99. cliprange_t *start;
  100. // find the first range that touches the range (adjacent pixels are touching)
  101. start = solidsegs;
  102. while (start->last < first-1)
  103. start++;
  104. if (first < start->first)
  105. {
  106. if (last < start->first-1)
  107. { // post is entirely visible (above start)
  108. R_StoreWallRange (first, last);
  109. return;
  110. }
  111. // there is a fragment above *start
  112. R_StoreWallRange (first, start->first - 1);
  113. }
  114. if (last <= start->last)
  115. return; // bottom contained in start
  116. while (last >= (start+1)->first-1)
  117. {
  118. // there is a fragment between two posts
  119. R_StoreWallRange (start->last + 1, (start+1)->first - 1);
  120. start++;
  121. if (last <= start->last)
  122. return;
  123. }
  124. // there is a fragment after *next
  125. R_StoreWallRange (start->last + 1, last);
  126. }
  127. /*
  128. ====================
  129. =
  130. = R_ClearClipSegs
  131. =
  132. ====================
  133. */
  134. void R_ClearClipSegs (void)
  135. {
  136. solidsegs[0].first = -0x7fffffff;
  137. solidsegs[0].last = -1;
  138. solidsegs[1].first = viewwidth;
  139. solidsegs[1].last = 0x7fffffff;
  140. newend = solidsegs+2;
  141. }
  142. //=============================================================================
  143. /*
  144. ======================
  145. =
  146. = R_AddLine
  147. =
  148. = Clips the given segment and adds any visible pieces to the line list
  149. =
  150. ======================
  151. */
  152. void R_AddLine (seg_t *line)
  153. {
  154. int x1, x2;
  155. angle_t angle1, angle2, span, tspan;
  156. #ifdef __NeXT__
  157. RD_DrawLineCheck (line);
  158. #endif
  159. curline = line;
  160. // OPTIMIZE: quickly reject orthogonal back sides
  161. angle1 = R_PointToAngle (line->v1->x, line->v1->y);
  162. angle2 = R_PointToAngle (line->v2->x, line->v2->y);
  163. //
  164. // clip to view edges
  165. // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW)
  166. span = angle1 - angle2;
  167. if (span >= ANG180)
  168. return; // back side
  169. rw_angle1 = angle1; // global angle needed by segcalc
  170. angle1 -= viewangle;
  171. angle2 -= viewangle;
  172. tspan = angle1 + clipangle;
  173. if (tspan > 2*clipangle)
  174. {
  175. tspan -= 2*clipangle;
  176. if (tspan >= span)
  177. return; // totally off the left edge
  178. angle1 = clipangle;
  179. }
  180. tspan = clipangle - angle2;
  181. if (tspan > 2*clipangle)
  182. {
  183. tspan -= 2*clipangle;
  184. if (tspan >= span)
  185. return; // totally off the left edge
  186. angle2 = -clipangle;
  187. }
  188. //
  189. // the seg is in the view range, but not necessarily visible
  190. //
  191. angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
  192. angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
  193. x1 = viewangletox[angle1];
  194. x2 = viewangletox[angle2];
  195. if (x1 == x2)
  196. return; // does not cross a pixel
  197. backsector = line->backsector;
  198. if (!backsector)
  199. goto clipsolid; // single sided line
  200. if (backsector->ceilingheight <= frontsector->floorheight
  201. || backsector->floorheight >= frontsector->ceilingheight)
  202. goto clipsolid; // closed door
  203. if (backsector->ceilingheight != frontsector->ceilingheight
  204. || backsector->floorheight != frontsector->floorheight)
  205. goto clippass; // window
  206. // reject empty lines used for triggers and special events
  207. if (backsector->ceilingpic == frontsector->ceilingpic
  208. && backsector->floorpic == frontsector->floorpic
  209. && backsector->lightlevel == frontsector->lightlevel
  210. && curline->sidedef->midtexture == 0)
  211. return;
  212. clippass:
  213. R_ClipPassWallSegment (x1, x2-1);
  214. return;
  215. clipsolid:
  216. R_ClipSolidWallSegment (x1, x2-1);
  217. }
  218. //============================================================================
  219. /*
  220. ===============================================================================
  221. =
  222. = R_CheckBBox
  223. =
  224. = Returns true if some part of the bbox might be visible
  225. =
  226. ===============================================================================
  227. */
  228. int checkcoord[12][4] = {
  229. {3,0, 2,1},
  230. {3,0, 2,0},
  231. {3,1, 2,0},
  232. {0},
  233. {2,0, 2,1},
  234. {0,0,0,0},
  235. {3,1, 3,0},
  236. {0},
  237. {2,0, 3,1},
  238. {2,1, 3,1},
  239. {2,1, 3,0} };
  240. boolean R_CheckBBox (fixed_t *bspcoord)
  241. {
  242. int boxx, boxy, boxpos;
  243. fixed_t x1, y1, x2, y2;
  244. angle_t angle1, angle2, span, tspan;
  245. cliprange_t *start;
  246. int sx1, sx2;
  247. #ifdef __NeXT__
  248. RD_DrawBBox (bspcoord);
  249. #endif
  250. // find the corners of the box that define the edges from current viewpoint
  251. if (viewx <= bspcoord[BOXLEFT])
  252. boxx = 0;
  253. else if (viewx < bspcoord[BOXRIGHT])
  254. boxx = 1;
  255. else
  256. boxx = 2;
  257. if (viewy >= bspcoord[BOXTOP])
  258. boxy = 0;
  259. else if (viewy > bspcoord[BOXBOTTOM])
  260. boxy = 1;
  261. else
  262. boxy = 2;
  263. boxpos = (boxy<<2)+boxx;
  264. if (boxpos == 5)
  265. return true;
  266. x1 = bspcoord[checkcoord[boxpos][0]];
  267. y1 = bspcoord[checkcoord[boxpos][1]];
  268. x2 = bspcoord[checkcoord[boxpos][2]];
  269. y2 = bspcoord[checkcoord[boxpos][3]];
  270. #ifdef __NeXT__
  271. // RD_DisplayLine (x1, y1, x2, y2, 0.1);
  272. #endif
  273. //
  274. // check clip list for an open space
  275. //
  276. angle1 = R_PointToAngle (x1, y1) - viewangle;
  277. angle2 = R_PointToAngle (x2, y2) - viewangle;
  278. span = angle1 - angle2;
  279. if (span >= ANG180)
  280. return true; // sitting on a line
  281. tspan = angle1 + clipangle;
  282. if (tspan > 2*clipangle)
  283. {
  284. tspan -= 2*clipangle;
  285. if (tspan >= span)
  286. return false; // totally off the left edge
  287. angle1 = clipangle;
  288. }
  289. tspan = clipangle - angle2;
  290. if (tspan > 2*clipangle)
  291. {
  292. tspan -= 2*clipangle;
  293. if (tspan >= span)
  294. return false; // totally off the left edge
  295. angle2 = -clipangle;
  296. }
  297. // find the first clippost that touches the source post (adjacent pixels are touching)
  298. angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
  299. angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
  300. sx1 = viewangletox[angle1];
  301. sx2 = viewangletox[angle2];
  302. if (sx1 == sx2)
  303. return false; // does not cross a pixel
  304. sx2--;
  305. start = solidsegs;
  306. while (start->last < sx2)
  307. start++;
  308. if (sx1 >= start->first && sx2 <= start->last)
  309. return false; // the clippost contains the new span
  310. return true;
  311. }
  312. /*
  313. ================
  314. =
  315. = R_Subsector
  316. =
  317. = Draw one or more segments
  318. ================
  319. */
  320. void R_Subsector (int num)
  321. {
  322. int count;
  323. seg_t *line;
  324. subsector_t *sub;
  325. #ifdef RANGECHECK
  326. if (num>=numsubsectors)
  327. I_Error ("R_Subsector: ss %i with numss = %i",num, numsubsectors);
  328. #endif
  329. sscount++;
  330. sub = &subsectors[num];
  331. frontsector = sub->sector;
  332. count = sub->numlines;
  333. line = &segs[sub->firstline];
  334. if (frontsector->floorheight < viewz)
  335. floorplane = R_FindPlane (frontsector->floorheight,
  336. frontsector->floorpic, frontsector->lightlevel,
  337. frontsector->special);
  338. else
  339. floorplane = NULL;
  340. if (frontsector->ceilingheight > viewz
  341. || frontsector->ceilingpic == skyflatnum)
  342. ceilingplane = R_FindPlane (frontsector->ceilingheight,
  343. frontsector->ceilingpic, frontsector->lightlevel, 0);
  344. else
  345. ceilingplane = NULL;
  346. R_AddSprites (frontsector);
  347. while (count--)
  348. {
  349. R_AddLine (line);
  350. line++;
  351. }
  352. }
  353. /*
  354. ===============================================================================
  355. =
  356. = RenderBSPNode
  357. =
  358. ===============================================================================
  359. */
  360. void R_RenderBSPNode (int bspnum)
  361. {
  362. node_t *bsp;
  363. int side;
  364. if (bspnum & NF_SUBSECTOR)
  365. {
  366. if (bspnum == -1)
  367. R_Subsector (0);
  368. else
  369. R_Subsector (bspnum&(~NF_SUBSECTOR));
  370. return;
  371. }
  372. bsp = &nodes[bspnum];
  373. #ifdef __NeXT__
  374. RD_DrawNodeLine (bsp);
  375. #endif
  376. //
  377. // decide which side the view point is on
  378. //
  379. side = R_PointOnSide (viewx, viewy, bsp);
  380. R_RenderBSPNode (bsp->children[side]); // recursively divide front space
  381. if (R_CheckBBox (bsp->bbox[side^1])) // possibly divide back space
  382. R_RenderBSPNode (bsp->children[side^1]);
  383. }