DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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