A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 = §ors[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}