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