A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 600 lines 20 kB view raw
1/* Emacs style mode select -*- C++ -*- 2 *----------------------------------------------------------------------------- 3 * 4 * 5 * PrBoom a Doom port merged with LxDoom and LSDLDoom 6 * based on BOOM, a modified and improved DOOM engine 7 * Copyright (C) 1999 by 8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman 9 * Copyright (C) 1999-2000 by 10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 25 * 02111-1307, USA. 26 * 27 * DESCRIPTION: 28 * BSP traversal, handling of LineSegs for rendering. 29 * 30 *-----------------------------------------------------------------------------*/ 31 32#include "doomstat.h" 33#include "m_bbox.h" 34#include "i_system.h" 35#include "r_main.h" 36#include "r_segs.h" 37#include "r_plane.h" 38#include "r_things.h" 39#include "r_bsp.h" // cph - sanity checking 40 41seg_t *curline; 42side_t *sidedef; 43line_t *linedef; 44sector_t *frontsector; 45sector_t *backsector; 46drawseg_t *ds_p; 47 48// killough 4/7/98: indicates doors closed wrt automap bugfix: 49// cph - replaced by linedef rendering flags - int doorclosed; 50 51// killough: New code which removes 2s linedef limit 52drawseg_t *drawsegs; 53unsigned maxdrawsegs; 54// drawseg_t drawsegs[MAXDRAWSEGS]; // old code -- killough 55 56// 57// R_ClearDrawSegs 58// 59 60void R_ClearDrawSegs(void) 61{ 62 ds_p = drawsegs; 63} 64 65// CPhipps - 66// Instead of clipsegs, let's try using an array with one entry for each column, 67// indicating whether it's blocked by a solid wall yet or not. 68 69byte solidcol[MAX_SCREENWIDTH] IBSS_ATTR; 70 71// CPhipps - 72// R_ClipWallSegment 73// 74// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those 75// columns which aren't solid, and updates the solidcol[] array appropriately 76 77void R_ClipWallSegment(int first, int last, boolean solid) 78{ 79 byte *p; 80 while (first < last) 81 { 82 if (solidcol[first]) 83 { 84 if (!(p = memchr(solidcol+first, 0, last-first))) 85 return; // All solid 86 first = p - solidcol; 87 } 88 else 89 { 90 int to; 91 if (!(p = memchr(solidcol+first, 1, last-first))) 92 to = last; 93 else 94 to = p - solidcol; 95 R_StoreWallRange(first, to-1); 96 if (solid) 97 { 98 memset(solidcol+first,1,to-first); 99 } 100 first = to; 101 } 102 } 103} 104 105// 106// R_ClearClipSegs 107// 108 109void R_ClearClipSegs (void) 110{ 111 memset(solidcol, 0, SCREENWIDTH); 112} 113 114// killough 1/18/98 -- This function is used to fix the automap bug which 115// showed lines behind closed doors simply because the door had a dropoff. 116// 117// cph - converted to R_RecalcLineFlags. This recalculates all the flags for 118// a line, including closure and texture tiling. 119 120static void R_RecalcLineFlags(void) 121{ 122 linedef->r_validcount = gametic; 123 124 /* First decide if the line is closed, normal, or invisible */ 125 if (!(linedef->flags & ML_TWOSIDED) 126 || backsector->ceilingheight <= frontsector->floorheight 127 || backsector->floorheight >= frontsector->ceilingheight 128 || ( 129 // if door is closed because back is shut: 130 backsector->ceilingheight <= backsector->floorheight 131 132 // preserve a kind of transparent door/lift special effect: 133 && (backsector->ceilingheight >= frontsector->ceilingheight || 134 curline->sidedef->toptexture) 135 136 && (backsector->floorheight <= frontsector->floorheight || 137 curline->sidedef->bottomtexture) 138 139 // properly render skies (consider door "open" if both ceilings are sky): 140 && (backsector->ceilingpic !=skyflatnum || 141 frontsector->ceilingpic!=skyflatnum) 142 ) 143 ) 144 linedef->r_flags = RF_CLOSED; 145 else 146 { 147 // Reject empty lines used for triggers 148 // and special events. 149 // Identical floor and ceiling on both sides, 150 // identical light levels on both sides, 151 // and no middle texture. 152 // CPhipps - recode for speed, not certain if this is portable though 153 if (backsector->ceilingheight != frontsector->ceilingheight 154 || backsector->floorheight != frontsector->floorheight 155 || curline->sidedef->midtexture 156 || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs, 157 sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) + 158 sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) + 159 sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) + 160 sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) + 161 sizeof(frontsector->ceilinglightsec))) 162 { 163 linedef->r_flags = 0; 164 return; 165 } 166 else 167 linedef->r_flags = RF_IGNORE; 168 } 169 170 /* cph - I'm too lazy to try and work with offsets in this */ 171 if (curline->sidedef->rowoffset) 172 return; 173 174 /* Now decide on texture tiling */ 175 if (linedef->flags & ML_TWOSIDED) 176 { 177 int c; 178 179 /* Does top texture need tiling */ 180 if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 && 181 (textureheight[texturetranslation[curline->sidedef->toptexture]] > c)) 182 linedef->r_flags |= RF_TOP_TILE; 183 184 /* Does bottom texture need tiling */ 185 if ((c = frontsector->floorheight - backsector->floorheight) > 0 && 186 (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c)) 187 linedef->r_flags |= RF_BOT_TILE; 188 } 189 else 190 { 191 int c; 192 /* Does middle texture need tiling */ 193 if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 && 194 (textureheight[texturetranslation[curline->sidedef->midtexture]] > c)) 195 linedef->r_flags |= RF_MID_TILE; 196 } 197} 198 199// 200// killough 3/7/98: Hack floor/ceiling heights for deep water etc. 201// 202// If player's view height is underneath fake floor, lower the 203// drawn ceiling to be just under the floor height, and replace 204// the drawn floor and ceiling textures, and light level, with 205// the control sector's. 206// 207// Similar for ceiling, only reflected. 208// 209// killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter 210// 211 212sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, 213 int *floorlightlevel, int *ceilinglightlevel, 214 boolean back) 215{ 216 if (floorlightlevel) 217 *floorlightlevel = sec->floorlightsec == -1 ? 218 sec->lightlevel : sectors[sec->floorlightsec].lightlevel; 219 220 if (ceilinglightlevel) 221 *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98 222 sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel; 223 224 if (sec->heightsec != -1) 225 { 226 const sector_t *s = &sectors[sec->heightsec]; 227 int heightsec = viewplayer->mo->subsector->sector->heightsec; 228 int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight; 229 230 // Replace sector being drawn, with a copy to be hacked 231 *tempsec = *sec; 232 233 // Replace floor and ceiling height with other sector's heights. 234 tempsec->floorheight = s->floorheight; 235 tempsec->ceilingheight = s->ceilingheight; 236 237 // killough 11/98: prevent sudden light changes from non-water sectors: 238 if (underwater && (tempsec-> floorheight = sec->floorheight, 239 tempsec->ceilingheight = s->floorheight-1, !back)) 240 { // head-below-floor hack 241 tempsec->floorpic = s->floorpic; 242 tempsec->floor_xoffs = s->floor_xoffs; 243 tempsec->floor_yoffs = s->floor_yoffs; 244 245 if (underwater) 246 { 247 if (s->ceilingpic == skyflatnum) 248 { 249 tempsec->floorheight = tempsec->ceilingheight+1; 250 tempsec->ceilingpic = tempsec->floorpic; 251 tempsec->ceiling_xoffs = tempsec->floor_xoffs; 252 tempsec->ceiling_yoffs = tempsec->floor_yoffs; 253 } 254 else 255 { 256 tempsec->ceilingpic = s->ceilingpic; 257 tempsec->ceiling_xoffs = s->ceiling_xoffs; 258 tempsec->ceiling_yoffs = s->ceiling_yoffs; 259 } 260 } 261 262 tempsec->lightlevel = s->lightlevel; 263 264 if (floorlightlevel) 265 *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : 266 sectors[s->floorlightsec].lightlevel; // killough 3/16/98 267 268 if (ceilinglightlevel) 269 *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : 270 sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 271 } 272 else 273 if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight && 274 sec->ceilingheight > s->ceilingheight) 275 { // Above-ceiling hack 276 tempsec->ceilingheight = s->ceilingheight; 277 tempsec->floorheight = s->ceilingheight + 1; 278 279 tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic; 280 tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs; 281 tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; 282 283 if (s->floorpic != skyflatnum) 284 { 285 tempsec->ceilingheight = sec->ceilingheight; 286 tempsec->floorpic = s->floorpic; 287 tempsec->floor_xoffs = s->floor_xoffs; 288 tempsec->floor_yoffs = s->floor_yoffs; 289 } 290 291 tempsec->lightlevel = s->lightlevel; 292 293 if (floorlightlevel) 294 *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : 295 sectors[s->floorlightsec].lightlevel; // killough 3/16/98 296 297 if (ceilinglightlevel) 298 *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : 299 sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 300 } 301 sec = tempsec; // Use other sector 302 } 303 return sec; 304} 305 306// 307// R_AddLine 308// Clips the given segment 309// and adds any visible pieces to the line list. 310// 311 312static void R_AddLine (seg_t *line) 313{ 314 int x1; 315 int x2; 316 angle_t angle1; 317 angle_t angle2; 318 angle_t span; 319 angle_t tspan; 320 static sector_t tempsec; // killough 3/8/98: ceiling/water hack 321 // boolean solid = true; 322 323 curline = line; 324 325 angle1 = R_PointToAngle (line->v1->x, line->v1->y); 326 angle2 = R_PointToAngle (line->v2->x, line->v2->y); 327 328 // Clip to view edges. 329 span = angle1 - angle2; 330 331 // Back side, i.e. backface culling 332 if (span >= ANG180) 333 return; 334 335 // Global angle needed by segcalc. 336 rw_angle1 = angle1; 337 angle1 -= viewangle; 338 angle2 -= viewangle; 339 340 tspan = angle1 + clipangle; 341 if (tspan > 2*clipangle) 342 { 343 tspan -= 2*clipangle; 344 345 // Totally off the left edge? 346 if (tspan >= span) 347 return; 348 349 angle1 = clipangle; 350 } 351 352 tspan = clipangle - angle2; 353 if (tspan > 2*clipangle) 354 { 355 tspan -= 2*clipangle; 356 357 // Totally off the left edge? 358 if (tspan >= span) 359 return; 360 angle2 = 0-clipangle; 361 } 362 363 // The seg is in the view range, 364 // but not necessarily visible. 365 366 angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; 367 angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; 368 369 // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur: 370 x1 = viewangletox[angle1]; 371 x2 = viewangletox[angle2]; 372 373 // Does not cross a pixel? 374 if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness 375 return; 376 377 backsector = line->backsector; 378 379 // Single sided line? 380 if (backsector) 381 // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water 382 backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true); 383 384 /* cph - roll up linedef properties in flags */ 385 if ((linedef = curline->linedef)->r_validcount != gametic) 386 R_RecalcLineFlags(); 387 388 if (linedef->r_flags & RF_IGNORE) 389 { 390 return; 391 } 392 else 393 R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED); 394} 395 396// 397// R_CheckBBox 398// Checks BSP node/subtree bounding box. 399// Returns true 400// if some part of the bbox might be visible. 401// 402 403static const int checkcoord[12][4] = // killough -- static const 404 { 405 { 406 3,0,2,1}, 407 {3,0,2,0}, 408 {3,1,2,0}, 409 {0}, 410 {2,0,2,1}, 411 {0,0,0,0}, 412 {3,1,3,0}, 413 {0}, 414 {2,0,3,1}, 415 {2,1,3,1}, 416 {2,1,3,0} 417 }; 418 419// killough 1/28/98: static // CPhipps - const parameter, reformatted 420static boolean R_CheckBBox(const fixed_t *bspcoord) 421{ 422 angle_t angle1, angle2; 423 424 { 425 int boxpos; 426 const int* check; 427 428 // Find the corners of the box 429 // that define the edges from current viewpoint. 430 boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) + 431 (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8); 432 433 if (boxpos == 5) 434 return true; 435 436 check = checkcoord[boxpos]; 437 angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle; 438 angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle; 439 } 440 441 // cph - replaced old code, which was unclear and badly commented 442 // Much more efficient code now 443 if ((signed)angle1 < (signed)angle2) 444 { /* it's "behind" us */ 445 /* Either angle1 or angle2 is behind us, so it doesn't matter if we 446 * change it to the corect sign 447 */ 448 if ((angle1 >= ANG180) && (angle1 < ANG270)) 449 angle1 = INT_MAX; /* which is ANG180-1 */ 450 else 451 angle2 = INT_MIN; 452 } 453 454 if ((signed)angle2 >= (signed)clipangle) 455 return false; // Both off left edge 456 if ((signed)angle1 <= -(signed)clipangle) 457 return false; // Both off right edge 458 if ((signed)angle1 >= (signed)clipangle) 459 angle1 = clipangle; // Clip at left edge 460 if ((signed)angle2 <= -(signed)clipangle) 461 angle2 = 0-clipangle; // Clip at right edge 462 463 // Find the first clippost 464 // that touches the source post 465 // (adjacent pixels are touching). 466 angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; 467 angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; 468 { 469 int sx1 = viewangletox[angle1]; 470 int sx2 = viewangletox[angle2]; 471 // const cliprange_t *start; 472 473 // Does not cross a pixel. 474 if (sx1 == sx2) 475 return false; 476 477 if (!memchr(solidcol+sx1, 0, sx2-sx1)) 478 return false; 479 // All columns it covers are already solidly covered 480 } 481 482 return true; 483} 484 485// 486// R_Subsector 487// Determine floor/ceiling planes. 488// Add sprites of things in sector. 489// Draw one or more line segments. 490// 491// killough 1/31/98 -- made static, polished 492 493// Had to move this out of the function - causes stack overflows in RockBox 494sector_t tempsec IBSS_ATTR; // killough 3/7/98: deep water hack 495static void R_Subsector(int num) 496{ 497 int count; 498 seg_t *line; 499 subsector_t *sub; 500 501 int floorlightlevel; // killough 3/16/98: set floor lightlevel 502 int ceilinglightlevel; // killough 4/11/98 503 504#ifdef RANGECHECK 505 506 if (num>=numsubsectors) 507 I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors); 508#endif 509 510 sub = &subsectors[num]; 511 frontsector = sub->sector; 512 count = sub->numlines; 513 line = &segs[sub->firstline]; 514 // sscount++; 515 516 // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect 517 frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, 518 &ceilinglightlevel, false); // killough 4/11/98 519 520 // killough 3/7/98: Add (x,y) offsets to flats, add deep water check 521 // killough 3/16/98: add floorlightlevel 522 // killough 10/98: add support for skies transferred from sidedefs 523 524 floorplane = frontsector->floorheight < viewz || // killough 3/7/98 525 (frontsector->heightsec != -1 && 526 sectors[frontsector->heightsec].ceilingpic == skyflatnum) ? 527 R_FindPlane(frontsector->floorheight, 528 frontsector->floorpic == skyflatnum && // kilough 10/98 529 frontsector->sky & PL_SKYFLAT ? frontsector->sky : 530 frontsector->floorpic, 531 floorlightlevel, // killough 3/16/98 532 frontsector->floor_xoffs, // killough 3/7/98 533 frontsector->floor_yoffs 534 ) : NULL; 535 536 ceilingplane = frontsector->ceilingheight > viewz || 537 frontsector->ceilingpic == skyflatnum || 538 (frontsector->heightsec != -1 && 539 sectors[frontsector->heightsec].floorpic == skyflatnum) ? 540 R_FindPlane(frontsector->ceilingheight, // killough 3/8/98 541 frontsector->ceilingpic == skyflatnum && // kilough 10/98 542 frontsector->sky & PL_SKYFLAT ? frontsector->sky : 543 frontsector->ceilingpic, 544 ceilinglightlevel, // killough 4/11/98 545 frontsector->ceiling_xoffs, // killough 3/7/98 546 frontsector->ceiling_yoffs 547 ) : NULL; 548 549 // killough 9/18/98: Fix underwater slowdown, by passing real sector 550 // instead of fake one. Improve sprite lighting by basing sprite 551 // lightlevels on floor & ceiling lightlevels in the surrounding area. 552 // 553 // 10/98 killough: 554 // 555 // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! 556 // That is part of the 242 effect!!! If you simply pass sub->sector to 557 // the old code you will not get correct lighting for underwater sprites!!! 558 // Either you must pass the fake sector and handle validcount here, on the 559 // real sector, or you must account for the lighting in some other way, 560 // like passing it as an argument. 561 562 R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2); 563 564 while (count--) 565 { 566 if (line->miniseg == false) 567 R_AddLine (line); 568 line++; 569 } 570 571} 572 573// 574// RenderBSPNode 575// Renders all subsectors below a given node, 576// traversing subtree recursively. 577// Just call with BSP root. 578// 579// killough 5/2/98: reformatted, removed tail recursion 580 581void R_RenderBSPNode(int bspnum) 582{ 583 while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? 584 { 585 const node_t *bsp = &nodes[bspnum]; 586 587 // Decide which side the view point is on. 588 int side = R_PointOnSide(viewx, viewy, bsp); 589 // Recursively divide front space. 590 R_RenderBSPNode(bsp->children[side]); 591 592 // Possibly divide back space. 593 594 if (!R_CheckBBox(bsp->bbox[side^1])) 595 return; 596 597 bspnum = bsp->children[side^1]; 598 } 599 R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); 600}