r_bsp.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "Precompiled.h"
  21. #include "globaldata.h"
  22. #include "doomdef.h"
  23. #include "m_bbox.h"
  24. #include "i_system.h"
  25. #include "r_main.h"
  26. #include "r_plane.h"
  27. #include "r_things.h"
  28. // State.
  29. #include "doomstat.h"
  30. #include "r_state.h"
  31. //#include "r_local.h"
  32. void
  33. R_StoreWallRange
  34. ( int start,
  35. int stop );
  36. //
  37. // R_ClearDrawSegs
  38. //
  39. void R_ClearDrawSegs (void)
  40. {
  41. ::g->ds_p = ::g->drawsegs;
  42. }
  43. //
  44. // ClipWallSegment
  45. // Clips the given range of columns
  46. // and includes it in the new clip list.
  47. //
  48. // ::g->newend is one past the last valid seg
  49. //
  50. // R_ClipSolidWallSegment
  51. // Does handle solid walls,
  52. // e.g. single sided LineDefs (middle texture)
  53. // that entirely block the view.
  54. //
  55. void
  56. R_ClipSolidWallSegment
  57. ( int first,
  58. int last )
  59. {
  60. cliprange_t* next;
  61. cliprange_t* start;
  62. // Find the first range that touches the range
  63. // (adjacent pixels are touching).
  64. start = ::g->solidsegs;
  65. while (start->last < first-1)
  66. start++;
  67. if (first < start->first)
  68. {
  69. if (last < start->first-1)
  70. {
  71. // Post is entirely visible (above start),
  72. // so insert a new clippost.
  73. R_StoreWallRange (first, last);
  74. next = ::g->newend;
  75. ::g->newend++;
  76. while (next != start)
  77. {
  78. *next = *(next-1);
  79. next--;
  80. }
  81. next->first = first;
  82. next->last = last;
  83. return;
  84. }
  85. // There is a fragment above *start.
  86. R_StoreWallRange (first, start->first - 1);
  87. // Now adjust the clip size.
  88. start->first = first;
  89. }
  90. // Bottom contained in start?
  91. if (last <= start->last)
  92. return;
  93. next = start;
  94. while (last >= (next+1)->first-1)
  95. {
  96. // There is a fragment between two posts.
  97. R_StoreWallRange (next->last + 1, (next+1)->first - 1);
  98. next++;
  99. if (last <= next->last)
  100. {
  101. // Bottom is contained in next.
  102. // Adjust the clip size.
  103. start->last = next->last;
  104. goto crunch;
  105. }
  106. }
  107. // There is a fragment after *next.
  108. R_StoreWallRange (next->last + 1, last);
  109. // Adjust the clip size.
  110. start->last = last;
  111. // Remove start+1 to next from the clip list,
  112. // because start now covers their area.
  113. crunch:
  114. if (next == start)
  115. {
  116. // Post just extended past the bottom of one post.
  117. return;
  118. }
  119. while (next++ != ::g->newend)
  120. {
  121. // Remove a post.
  122. *++start = *next;
  123. }
  124. ::g->newend = start+1;
  125. }
  126. //
  127. // R_ClipPassWallSegment
  128. // Clips the given range of columns,
  129. // but does not includes it in the clip list.
  130. // Does handle windows,
  131. // e.g. LineDefs with upper and lower texture.
  132. //
  133. void
  134. R_ClipPassWallSegment
  135. ( int first,
  136. int last )
  137. {
  138. cliprange_t* start;
  139. // Find the first range that touches the range
  140. // (adjacent pixels are touching).
  141. start = ::g->solidsegs;
  142. while (start->last < first-1)
  143. start++;
  144. if (first < start->first)
  145. {
  146. if (last < start->first-1)
  147. {
  148. // Post is entirely visible (above start).
  149. R_StoreWallRange (first, last);
  150. return;
  151. }
  152. // There is a fragment above *start.
  153. R_StoreWallRange (first, start->first - 1);
  154. }
  155. // Bottom contained in start?
  156. if (last <= start->last)
  157. return;
  158. while (last >= (start+1)->first-1)
  159. {
  160. // There is a fragment between two posts.
  161. R_StoreWallRange (start->last + 1, (start+1)->first - 1);
  162. start++;
  163. if (last <= start->last)
  164. return;
  165. }
  166. // There is a fragment after *next.
  167. R_StoreWallRange (start->last + 1, last);
  168. }
  169. //
  170. // R_ClearClipSegs
  171. //
  172. void R_ClearClipSegs (void)
  173. {
  174. ::g->solidsegs[0].first = -0x7fffffff;
  175. ::g->solidsegs[0].last = -1;
  176. ::g->solidsegs[1].first = ::g->viewwidth;
  177. ::g->solidsegs[1].last = 0x7fffffff;
  178. ::g->newend = ::g->solidsegs+2;
  179. }
  180. //
  181. // R_AddLine
  182. // Clips the given segment
  183. // and adds any visible pieces to the line list.
  184. //
  185. void R_AddLine (seg_t* line)
  186. {
  187. int x1;
  188. int x2;
  189. angle_t angle1;
  190. angle_t angle2;
  191. angle_t span;
  192. angle_t tspan;
  193. ::g->curline = line;
  194. // OPTIMIZE: quickly reject orthogonal back ::g->sides.
  195. angle1 = R_PointToAngle (line->v1->x, line->v1->y);
  196. angle2 = R_PointToAngle (line->v2->x, line->v2->y);
  197. // Clip to view edges.
  198. // OPTIMIZE: make constant out of 2*::g->clipangle (FIELDOFVIEW).
  199. span = angle1 - angle2;
  200. // Back side? I.e. backface culling?
  201. if (span >= ANG180)
  202. return;
  203. extern angle_t GetViewAngle();
  204. // Global angle needed by segcalc.
  205. ::g->rw_angle1 = angle1;
  206. angle1 -= GetViewAngle();
  207. angle2 -= GetViewAngle();
  208. tspan = angle1 + ::g->clipangle;
  209. if (tspan > 2*::g->clipangle)
  210. {
  211. tspan -= 2*::g->clipangle;
  212. // Totally off the left edge?
  213. if (tspan >= span)
  214. return;
  215. angle1 = ::g->clipangle;
  216. }
  217. tspan = ::g->clipangle - angle2;
  218. if (tspan > 2*::g->clipangle)
  219. {
  220. tspan -= 2*::g->clipangle;
  221. // Totally off the left edge?
  222. if (tspan >= span)
  223. return;
  224. angle2 = -::g->clipangle; // ALANHACK UNSIGNED
  225. }
  226. // The seg is in the view range,
  227. // but not necessarily visible.
  228. angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
  229. angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
  230. x1 = ::g->viewangletox[angle1];
  231. x2 = ::g->viewangletox[angle2];
  232. // Does not cross a pixel?
  233. if (x1 == x2)
  234. return;
  235. ::g->backsector = line->backsector;
  236. // Single sided line?
  237. if (!::g->backsector)
  238. goto clipsolid;
  239. // Closed door.
  240. if (::g->backsector->ceilingheight <= ::g->frontsector->floorheight
  241. || ::g->backsector->floorheight >= ::g->frontsector->ceilingheight)
  242. goto clipsolid;
  243. // Window.
  244. if (::g->backsector->ceilingheight != ::g->frontsector->ceilingheight
  245. || ::g->backsector->floorheight != ::g->frontsector->floorheight)
  246. goto clippass;
  247. // Reject empty ::g->lines used for triggers
  248. // and special ::g->events.
  249. // Identical floor and ceiling on both ::g->sides,
  250. // identical light levels on both ::g->sides,
  251. // and no middle texture.
  252. if (::g->backsector->ceilingpic == ::g->frontsector->ceilingpic
  253. && ::g->backsector->floorpic == ::g->frontsector->floorpic
  254. && ::g->backsector->lightlevel == ::g->frontsector->lightlevel
  255. && ::g->curline->sidedef->midtexture == 0)
  256. {
  257. return;
  258. }
  259. clippass:
  260. R_ClipPassWallSegment (x1, x2-1);
  261. return;
  262. clipsolid:
  263. R_ClipSolidWallSegment (x1, x2-1);
  264. }
  265. //
  266. // R_CheckBBox
  267. // Checks BSP node/subtree bounding box.
  268. // Returns true
  269. // if some part of the bbox might be visible.
  270. //
  271. qboolean R_CheckBBox (fixed_t* bspcoord)
  272. {
  273. int boxx;
  274. int boxy;
  275. int boxpos;
  276. fixed_t x1;
  277. fixed_t y1;
  278. fixed_t x2;
  279. fixed_t y2;
  280. angle_t angle1;
  281. angle_t angle2;
  282. angle_t span;
  283. angle_t tspan;
  284. cliprange_t* start;
  285. int sx1;
  286. int sx2;
  287. extern fixed_t GetViewX(); extern fixed_t GetViewY();
  288. // Find the corners of the box
  289. // that define the edges from current viewpoint.
  290. if (GetViewX() <= bspcoord[BOXLEFT])
  291. boxx = 0;
  292. else if (GetViewX() < bspcoord[BOXRIGHT])
  293. boxx = 1;
  294. else
  295. boxx = 2;
  296. if (GetViewY() >= bspcoord[BOXTOP])
  297. boxy = 0;
  298. else if (GetViewY() > bspcoord[BOXBOTTOM])
  299. boxy = 1;
  300. else
  301. boxy = 2;
  302. boxpos = (boxy<<2)+boxx;
  303. if (boxpos == 5)
  304. return true;
  305. x1 = bspcoord[::g->checkcoord[boxpos][0]];
  306. y1 = bspcoord[::g->checkcoord[boxpos][1]];
  307. x2 = bspcoord[::g->checkcoord[boxpos][2]];
  308. y2 = bspcoord[::g->checkcoord[boxpos][3]];
  309. // check clip list for an open space
  310. extern angle_t GetViewAngle();
  311. angle1 = R_PointToAngle (x1, y1) - GetViewAngle();
  312. angle2 = R_PointToAngle (x2, y2) - GetViewAngle();
  313. span = angle1 - angle2;
  314. // Sitting on a line?
  315. if (span >= ANG180)
  316. return true;
  317. tspan = angle1 + ::g->clipangle;
  318. if (tspan > 2*::g->clipangle)
  319. {
  320. tspan -= 2*::g->clipangle;
  321. // Totally off the left edge?
  322. if (tspan >= span)
  323. return false;
  324. angle1 = ::g->clipangle;
  325. }
  326. tspan = ::g->clipangle - angle2;
  327. if (tspan > 2*::g->clipangle)
  328. {
  329. tspan -= 2*::g->clipangle;
  330. // Totally off the left edge?
  331. if (tspan >= span)
  332. return false;
  333. angle2 = -::g->clipangle;// ALANHACK UNSIGNED
  334. }
  335. // Find the first clippost
  336. // that touches the source post
  337. // (adjacent pixels are touching).
  338. angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
  339. angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
  340. sx1 = ::g->viewangletox[angle1];
  341. sx2 = ::g->viewangletox[angle2];
  342. // Does not cross a pixel.
  343. if (sx1 == sx2)
  344. return false;
  345. sx2--;
  346. start = ::g->solidsegs;
  347. while (start->last < sx2)
  348. start++;
  349. if (sx1 >= start->first
  350. && sx2 <= start->last)
  351. {
  352. // The clippost contains the new span.
  353. return false;
  354. }
  355. return true;
  356. }
  357. //
  358. // R_Subsector
  359. // Determine floor/ceiling planes.
  360. // Add ::g->sprites of things in sector.
  361. // Draw one or more line segments.
  362. //
  363. void R_Subsector (int num)
  364. {
  365. int count;
  366. seg_t* line;
  367. subsector_t* sub;
  368. #ifdef RANGECHECK
  369. if (num>=::g->numsubsectors)
  370. I_Error ("R_Subsector: ss %i with numss = %i",
  371. num,
  372. ::g->numsubsectors);
  373. #endif
  374. ::g->sscount++;
  375. sub = &::g->subsectors[num];
  376. ::g->frontsector = sub->sector;
  377. count = sub->numlines;
  378. line = &::g->segs[sub->firstline];
  379. if (::g->frontsector->floorheight < ::g->viewz)
  380. {
  381. ::g->floorplane = R_FindPlane (::g->frontsector->floorheight,
  382. ::g->frontsector->floorpic,
  383. ::g->frontsector->lightlevel);
  384. }
  385. else
  386. ::g->floorplane = NULL;
  387. if (::g->frontsector->ceilingheight > ::g->viewz
  388. || ::g->frontsector->ceilingpic == ::g->skyflatnum)
  389. {
  390. ::g->ceilingplane = R_FindPlane (::g->frontsector->ceilingheight,
  391. ::g->frontsector->ceilingpic,
  392. ::g->frontsector->lightlevel);
  393. }
  394. else
  395. ::g->ceilingplane = NULL;
  396. R_AddSprites (::g->frontsector);
  397. while (count--)
  398. {
  399. R_AddLine (line);
  400. line++;
  401. }
  402. }
  403. //
  404. // RenderBSPNode
  405. // Renders all ::g->subsectors below a given node,
  406. // traversing subtree recursively.
  407. // Just call with BSP root.
  408. void R_RenderBSPNode (int bspnum)
  409. {
  410. node_t* bsp;
  411. int side;
  412. // Found a subsector?
  413. if (bspnum & NF_SUBSECTOR)
  414. {
  415. if (bspnum == -1)
  416. R_Subsector (0);
  417. else
  418. R_Subsector (bspnum&(~NF_SUBSECTOR));
  419. return;
  420. }
  421. bsp = &::g->nodes[bspnum];
  422. extern fixed_t GetViewX(); extern fixed_t GetViewY();
  423. // Decide which side the view point is on.
  424. side = R_PointOnSide (GetViewX(), GetViewY(), bsp);
  425. // Recursively divide front space.
  426. R_RenderBSPNode (bsp->children[side]);
  427. // Possibly divide back space.
  428. if (R_CheckBBox (bsp->bbox[side^1]))
  429. R_RenderBSPNode (bsp->children[side^1]);
  430. }