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