// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. // // DESCRIPTION: // All the clipping: columns, horizontal spans, sky columns. // //----------------------------------------------------------------------------- #include "vpo_local.h" namespace vpo { // OPTIMIZE: closed two sided lines as single sided // True if any of the segs textures might be visible. boolean segtextured; // False if the back side is the same plane. boolean markfloor; boolean markceiling; boolean maskedtexture; int toptexture; int bottomtexture; int midtexture; angle_t rw_normalangle; // angle to line origin int rw_angle1; // // regular wall // int rw_x; int rw_stopx; angle_t rw_centerangle; fixed_t rw_offset; fixed_t rw_distance; fixed_t rw_scale; fixed_t rw_scalestep; fixed_t rw_midtexturemid; fixed_t rw_toptexturemid; fixed_t rw_bottomtexturemid; int worldtop; int worldbottom; int worldhigh; int worldlow; fixed_t pixhigh; fixed_t pixlow; fixed_t pixhighstep; fixed_t pixlowstep; fixed_t topfrac; fixed_t topstep; fixed_t bottomfrac; fixed_t bottomstep; short* maskedtexturecol; // R_DRAW bits int dc_x; int dc_yl; int dc_yh; fixed_t dc_iscale; fixed_t dc_texturemid; // // R_RenderSegLoop // Draws zero, one, or two textures (and possibly a masked // texture) for walls. // Can draw or mark the starting pixel of floor and ceiling // textures. // CALLED: CORE LOOPING ROUTINE. // #define HEIGHTBITS 12 #define HEIGHTUNIT (1<>HEIGHTBITS; // no space above wall? if (yl < ceilingclip[rw_x]+1) yl = ceilingclip[rw_x]+1; if (markceiling) { top = ceilingclip[rw_x]+1; bottom = yl-1; if (bottom >= floorclip[rw_x]) bottom = floorclip[rw_x]-1; if (top <= bottom) { ceilingplane->top[rw_x] = top; ceilingplane->bottom[rw_x] = bottom; } } yh = bottomfrac>>HEIGHTBITS; if (yh >= floorclip[rw_x]) yh = floorclip[rw_x]-1; if (markfloor) { top = yh+1; bottom = floorclip[rw_x]-1; if (top <= ceilingclip[rw_x]) top = ceilingclip[rw_x]+1; if (top <= bottom) { floorplane->top[rw_x] = top; floorplane->bottom[rw_x] = bottom; } } // texturecolumn and lighting are independent of wall tiers if (segtextured) { // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); texturecolumn >>= FRACBITS; dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; } else { // purely to shut up the compiler texturecolumn = 0; } // draw the wall tiers if (midtexture) { // single sided line dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; ///--- dc_source = R_GetColumn(midtexture,texturecolumn); ///--- colfunc (); ceilingclip[rw_x] = viewheight; floorclip[rw_x] = -1; } else { // two sided line if (toptexture) { // top wall mid = pixhigh>>HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x]-1; if (mid >= yl) { dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; ///--- dc_source = R_GetColumn(toptexture,texturecolumn); ///--- colfunc (); ceilingclip[rw_x] = mid; } else ceilingclip[rw_x] = yl-1; } else { // no top wall if (markceiling) ceilingclip[rw_x] = yl-1; } if (bottomtexture) { // bottom wall mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; pixlow += pixlowstep; // no space above wall? if (mid <= ceilingclip[rw_x]) mid = ceilingclip[rw_x]+1; if (mid <= yh) { dc_yl = mid; dc_yh = yh; dc_texturemid = rw_bottomtexturemid; ///--- dc_source = R_GetColumn(bottomtexture, texturecolumn); ///--- colfunc (); floorclip[rw_x] = mid; } else floorclip[rw_x] = yh+1; } else { // no bottom wall if (markfloor) floorclip[rw_x] = yh+1; } if (maskedtexture) { // save texturecol // for backdrawing of masked mid texture maskedtexturecol[rw_x] = texturecolumn; } } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } // // R_StoreWallRange // A wall segment will be drawn // between start and stop pixels (inclusive). // void R_StoreWallRange ( int start, int stop ) { fixed_t hyp; fixed_t sineval; angle_t distangle, offsetangle; fixed_t vtop; // don't overflow and crash total_drawsegs++; if (total_drawsegs >= MAXDRAWSEGS) throw overflow_exception(); #ifdef RANGECHECK if (start >=viewwidth || start > stop) I_Error ("Bad R_RenderWallRange: %i to %i", start , stop); #endif sidedef = curline->sidedef; linedef = curline->linedef; // mark the segment as visible for auto map linedef->flags |= ML_MAPPED; // calculate rw_distance for scale calculation rw_normalangle = curline->angle + ANG90; offsetangle = abs((int)rw_normalangle-rw_angle1); if (offsetangle > ANG90) offsetangle = ANG90; distangle = ANG90 - offsetangle; hyp = R_PointToDist (curline->v1->x, curline->v1->y); sineval = finesine[distangle>>ANGLETOFINESHIFT]; rw_distance = FixedMul (hyp, sineval); ds_p->x1 = rw_x = start; ds_p->x2 = stop; ds_p->curline = curline; rw_stopx = stop+1; // calculate scale at both ends and step ds_p->scale1 = rw_scale = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]); if (stop > start ) { ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]); ds_p->scalestep = rw_scalestep = (ds_p->scale2 - rw_scale) / (stop-start); } else { ds_p->scale2 = ds_p->scale1; } // calculate texture boundaries // and decide if floor / ceiling marks are needed worldtop = frontsector->ceilingheight - viewz; worldbottom = frontsector->floorheight - viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; if (!backsector) { // single sided line midtexture = sidedef->midtexture; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; if (linedef->flags & ML_DONTPEGBOTTOM) { vtop = frontsector->floorheight + 128; ///??? textureheight[sidedef->midtexture]; // bottom of texture at bottom rw_midtexturemid = vtop - viewz; } else { // top of texture at top rw_midtexturemid = worldtop; } rw_midtexturemid += sidedef->rowoffset; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->tsilheight = INT_MIN; } else { // two sided line ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; if (frontsector->floorheight > backsector->floorheight) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = frontsector->floorheight; } else if (backsector->floorheight > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT_MAX; // ds_p->sprbottomclip = negonearray; } if (frontsector->ceilingheight < backsector->ceilingheight) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = frontsector->ceilingheight; } else if (backsector->ceilingheight < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; // ds_p->sprtopclip = screenheightarray; } if (backsector->ceilingheight <= frontsector->floorheight) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (backsector->floorheight >= frontsector->ceilingheight) { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT_MIN; ds_p->silhouette |= SIL_TOP; } worldhigh = backsector->ceilingheight - viewz; worldlow = backsector->floorheight - viewz; // hack to allow height changes in outdoor areas if (frontsector->ceilingpic == skyflatnum && backsector->ceilingpic == skyflatnum) { worldtop = worldhigh; } if (worldlow != worldbottom || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel) { markfloor = true; } else { // same plane on both sides markfloor = false; } if (worldhigh != worldtop || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel) { markceiling = true; } else { // same plane on both sides markceiling = false; } if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) { // closed door markceiling = markfloor = true; } if (worldhigh < worldtop) { // top texture toptexture = sidedef->toptexture; if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; } else { vtop = backsector->ceilingheight + 128; ///??? textureheight[sidedef->toptexture]; // bottom of texture rw_toptexturemid = vtop - viewz; } } if (worldlow > worldbottom) { // bottom texture bottomtexture = sidedef->bottomtexture; if (linedef->flags & ML_DONTPEGBOTTOM ) { // bottom of texture at bottom // top of texture at top rw_bottomtexturemid = worldtop; } else // top of texture at top rw_bottomtexturemid = worldlow; } rw_toptexturemid += sidedef->rowoffset; rw_bottomtexturemid += sidedef->rowoffset; // allocate space for masked texture tables if (sidedef->midtexture) { // masked midtexture maskedtexture = true; ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; total_openings += (rw_stopx - rw_x); if (total_openings >= MAXOPENINGS) throw overflow_exception(); } } // calculate rw_offset (only needed for textured lines) segtextured = midtexture | toptexture | bottomtexture | maskedtexture; if (segtextured) { offsetangle = rw_normalangle-rw_angle1; if (offsetangle > ANG180) offsetangle = -offsetangle; if (offsetangle > ANG90) offsetangle = ANG90; sineval = finesine[offsetangle >>ANGLETOFINESHIFT]; rw_offset = FixedMul (hyp, sineval); if (rw_normalangle-rw_angle1 < ANG180) rw_offset = -rw_offset; rw_offset += sidedef->textureoffset + curline->offset; rw_centerangle = ANG90 + viewangle - rw_normalangle; } // if a floor / ceiling plane is on the wrong side // of the view plane, it is definitely invisible // and doesn't need to be marked. if (frontsector->floorheight >= viewz) { // above view plane markfloor = false; } if (frontsector->ceilingheight <= viewz && frontsector->ceilingpic != skyflatnum) { // below view plane markceiling = false; } // calculate incremental stepping values for texture edges worldtop >>= 4; worldbottom >>= 4; topstep = -FixedMul (rw_scalestep, worldtop); topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); bottomstep = -FixedMul (rw_scalestep,worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); if (backsector) { worldhigh >>= 4; worldlow >>= 4; if (worldhigh < worldtop) { pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = -FixedMul (rw_scalestep,worldhigh); } if (worldlow > worldbottom) { pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); pixlowstep = -FixedMul (rw_scalestep,worldlow); } } // andrewj: make sure floorplane/ceilingplane are not NULL (prevent a crash) if (! floorplane) markfloor = false; if (! ceilingplane) markceiling = false; // render it if (markceiling) ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); if (markfloor) floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); R_RenderSegLoop (); // save sprite clipping info if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start)); ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; total_openings += (rw_stopx - start); if (total_openings >= MAXOPENINGS) throw overflow_exception(); } if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) { memcpy (lastopening, floorclip+start, 2*(rw_stopx-start)); ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; total_openings += (rw_stopx - start); if (total_openings >= MAXOPENINGS) throw overflow_exception(); } if (maskedtexture && !(ds_p->silhouette&SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT_MIN; } if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = INT_MAX; } ds_p++; } } // namespace vpo