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