/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom: a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2004 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * Copyright 2005, 2006 by * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko * * 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. * *-----------------------------------------------------------------------------*/ // // 4/25/98, 5/2/98 killough: reformatted, beautified #include "doomstat.h" #include "r_main.h" #include "r_bsp.h" #include "r_segs.h" #include "r_plane.h" #include "r_things.h" #include "r_draw.h" #include "w_wad.h" #include "v_video.h" #include "lprintf.h" // OPTIMIZE: closed two sided lines as single sided // killough 1/6/98: replaced globals with statics where appropriate // True if any of the segs textures might be visible. static boolean segtextured; static boolean markfloor; // False if the back side is the same plane. static boolean markceiling; static boolean maskedtexture; static int toptexture; static int bottomtexture; static int midtexture; static fixed_t toptexheight, midtexheight, bottomtexheight; // cph angle_t rw_normalangle; // angle to line origin int rw_angle1; fixed_t rw_distance; // // regular wall // static int rw_x; static int rw_stopx; static angle_t rw_centerangle; static fixed_t rw_offset; static fixed_t rw_scale; static fixed_t rw_scalestep; static fixed_t rw_midtexturemid; static fixed_t rw_toptexturemid; static fixed_t rw_bottomtexturemid; static int rw_lightlevel; static int worldtop; static int worldbottom; static int worldhigh; static int worldlow; static fixed_t pixhigh; static fixed_t pixlow; static fixed_t pixhighstep; static fixed_t pixlowstep; static fixed_t topfrac; static fixed_t topstep; static fixed_t bottomfrac; static fixed_t bottomstep; static int *maskedtexturecol; // dropoff overflow // // R_ScaleFromGlobalAngle // Returns the texture mapping scale // for the current line (horizontal span) // at the given angle. // rw_distance must be calculated first. // // killough 5/2/98: reformatted, cleaned up // CPhipps - moved here from r_main.c static fixed_t R_ScaleFromGlobalAngle(angle_t visangle) { int anglea = ANG90 + (visangle-viewangle); int angleb = ANG90 + (visangle-rw_normalangle); int den = FixedMul(rw_distance, finesine[anglea>>ANGLETOFINESHIFT]); // proff 11/06/98: Changed for high-res fixed_t num = FixedMul(projectiony, finesine[angleb>>ANGLETOFINESHIFT]); return den > num>>16 ? (num = FixedDiv(num, den)) > 64*FRACUNIT ? 64*FRACUNIT : num < 256 ? 256 : num : 64*FRACUNIT; } // // R_RenderMaskedSegRange // void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2) { int texnum; sector_t tempsec; // killough 4/13/98 const rpatch_t *patch; R_DrawColumn_f colfunc; draw_column_vars_t dcvars; angle_t angle; R_SetDefaultDrawColumnVars(&dcvars); // Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? curline = ds->curline; // OPTIMIZE: get rid of LIGHTSEGSHIFT globally // killough 4/11/98: draw translucent 2s normal textures colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz); if (curline->linedef->tranlump >= 0 && general_translucency) { colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, drawvars.filterwall, drawvars.filterz); tranmap = main_tranmap; if (curline->linedef->tranlump > 0) tranmap = W_CacheLumpNum(curline->linedef->tranlump-1); } // killough 4/11/98: end translucent 2s normal code frontsector = curline->frontsector; backsector = curline->backsector; // cph 2001/11/25 - middle textures did not animate in v1.2 texnum = curline->sidedef->midtexture; if (!comp[comp_maskedanim]) texnum = texturetranslation[texnum]; // killough 4/13/98: get correct lightlevel for 2s normal textures rw_lightlevel = R_FakeFlat(frontsector, &tempsec, NULL, NULL, false) ->lightlevel; maskedtexturecol = ds->maskedtexturecol; rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; // find positioning if (curline->linedef->flags & ML_DONTPEGBOTTOM) { dcvars.texturemid = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight; dcvars.texturemid = dcvars.texturemid + textureheight[texnum] - viewz; } else { dcvars.texturemid =frontsector->ceilingheightceilingheight ? frontsector->ceilingheight : backsector->ceilingheight; dcvars.texturemid = dcvars.texturemid - viewz; } dcvars.texturemid += curline->sidedef->rowoffset; if (fixedcolormap) { dcvars.colormap = fixedcolormap; dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE } patch = R_CacheTextureCompositePatchNum(texnum); // draw the columns for (dcvars.x = x1 ; dcvars.x <= x2 ; dcvars.x++, spryscale += rw_scalestep) if (maskedtexturecol[dcvars.x] != INT_MAX) // dropoff overflow { // calculate texture offset - POPE angle = (ds->rw_centerangle + xtoviewangle[dcvars.x]) >> ANGLETOFINESHIFT; dcvars.texu = ds->rw_offset - FixedMul(finetangent[angle], ds->rw_distance); if (drawvars.filterwall == RDRAW_FILTER_LINEAR) dcvars.texu -= (FRACUNIT>>1); if (!fixedcolormap) dcvars.z = spryscale; // for filtering -- POPE dcvars.colormap = R_ColourMap(rw_lightlevel,spryscale); dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,spryscale); // for filtering -- POPE // killough 3/2/98: // // This calculation used to overflow and cause crashes in Doom: // // sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid, spryscale); // // This code fixes it, by using double-precision intermediate // arithmetic and by skipping the drawing of 2s normals whose // mapping to screen coordinates is totally out of range: { int_64_t t = ((int_64_t) centeryfrac << FRACBITS) - (int_64_t) dcvars.texturemid * spryscale; if (t + (int_64_t) textureheight[texnum] * spryscale < 0 || t > (int_64_t) MAX_SCREENHEIGHT << FRACBITS*2) continue; // skip if the texture is out of screen's range sprtopscreen = (long)(t >> FRACBITS); } dcvars.iscale = 0xffffffffu / (unsigned) spryscale; // killough 1/25/98: here's where Medusa came in, because // it implicitly assumed that the column was all one patch. // Originally, Doom did not construct complete columns for // multipatched textures, so there were no header or trailer // bytes in the column referred to below, which explains // the Medusa effect. The fix is to construct true columns // when forming multipatched textures (see r_data.c). // draw the texture R_DrawMaskedColumn( patch, colfunc, &dcvars, R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]), R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]-1), R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]+1) ); maskedtexturecol[dcvars.x] = INT_MAX; // dropoff overflow } // Except for main_tranmap, mark others purgable at this point if (curline->linedef->tranlump > 0 && general_translucency) W_UnlockLumpNum(curline->linedef->tranlump-1); // cph - unlock it R_UnlockTextureCompositePatchNum(texnum); curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so R_ColourMap doesn't try using it for other things */ } // // 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; int yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS; // no space above wall? int bottom,top = ceilingclip[rw_x]+1; if (yl < top) yl = top; if (markceiling) { 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; } // SoM: this should be set here ceilingclip[rw_x] = bottom; } // yh = bottomfrac>>HEIGHTBITS; bottom = floorclip[rw_x]-1; if (yh > bottom) yh = bottom; if (markfloor) { top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; if (++top <= bottom) { floorplane->top[rw_x] = top; floorplane->bottom[rw_x] = bottom; } // SoM: This should be set here to prevent overdraw floorclip[rw_x] = top; } // texturecolumn and lighting are independent of wall tiers if (segtextured) { // calculate texture offset angle_t angle =(rw_centerangle+xtoviewangle[rw_x])>>ANGLETOFINESHIFT; texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); if (drawvars.filterwall == RDRAW_FILTER_LINEAR) texturecolumn -= (FRACUNIT>>1); dcvars.texu = texturecolumn; // for filtering -- POPE texturecolumn >>= FRACBITS; dcvars.colormap = R_ColourMap(rw_lightlevel,rw_scale); dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,rw_scale); // for filtering -- POPE dcvars.z = rw_scale; // for filtering -- POPE dcvars.x = rw_x; dcvars.iscale = 0xffffffffu / (unsigned)rw_scale; } // draw the wall tiers if (midtexture) { dcvars.yl = yl; // single sided line dcvars.yh = yh; dcvars.texturemid = rw_midtexturemid; tex_patch = R_CacheTextureCompositePatchNum(midtexture); dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn); dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1); dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1); dcvars.texheight = midtexheight; colfunc (&dcvars); R_UnlockTextureCompositePatchNum(midtexture); tex_patch = NULL; ceilingclip[rw_x] = viewheight; floorclip[rw_x] = -1; } else { // two sided line if (toptexture) { // top wall int mid = pixhigh>>HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x]-1; if (mid >= yl) { dcvars.yl = yl; dcvars.yh = mid; dcvars.texturemid = rw_toptexturemid; tex_patch = R_CacheTextureCompositePatchNum(toptexture); dcvars.source = R_GetTextureColumn(tex_patch,texturecolumn); dcvars.prevsource = R_GetTextureColumn(tex_patch,texturecolumn-1); dcvars.nextsource = R_GetTextureColumn(tex_patch,texturecolumn+1); dcvars.texheight = toptexheight; colfunc (&dcvars); R_UnlockTextureCompositePatchNum(toptexture); tex_patch = NULL; 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 { int mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; pixlow += pixlowstep; // no space above wall? if (mid <= ceilingclip[rw_x]) mid = ceilingclip[rw_x]+1; if (mid <= yh) { dcvars.yl = mid; dcvars.yh = yh; dcvars.texturemid = rw_bottomtexturemid; tex_patch = R_CacheTextureCompositePatchNum(bottomtexture); dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn); dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1); dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1); dcvars.texheight = bottomtexheight; colfunc (&dcvars); R_UnlockTextureCompositePatchNum(bottomtexture); tex_patch = NULL; floorclip[rw_x] = mid; } else floorclip[rw_x] = yh+1; } else // no bottom wall { if (markfloor) floorclip[rw_x] = yh+1; } // cph - if we completely blocked further sight through this column, // add this info to the solid columns array for r_bsp.c if ((markceiling || markfloor) && (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) { solidcol[rw_x] = 1; didsolidcol = 1; } // save texturecol for backdrawing of masked mid texture if (maskedtexture) maskedtexturecol[rw_x] = texturecolumn; } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } // killough 5/2/98: move from r_main.c, made static, simplified static fixed_t R_PointToDist(fixed_t x, fixed_t y) { fixed_t dx = D_abs(x - viewx); fixed_t dy = D_abs(y - viewy); if (dy > dx) { fixed_t t = dx; dx = dy; dy = t; } return FixedDiv(dx, finesine[(tantoangle[FixedDiv(dy,dx) >> DBITS] + ANG90) >> ANGLETOFINESHIFT]); } // // R_StoreWallRange // A wall segment will be drawn // between start and stop pixels (inclusive). // void R_StoreWallRange(const int start, const int stop) { fixed_t hyp; angle_t offsetangle; if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM { unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs)); ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a maxdrawsegs = newmax; } if(curline->miniseg == false) // figgi -- skip minisegs curline->linedef->flags |= ML_MAPPED; #ifdef GL_DOOM if (V_GetMode() == VID_MODEGL) { // proff 11/99: the rest of the calculations is not needed for OpenGL ds_p++->curline = curline; gld_AddWall(curline); return; } #endif #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 = rw_normalangle-rw_angle1; if (D_abs(offsetangle) > ANG90) offsetangle = ANG90; hyp = (viewx==curline->v1->x && viewy==curline->v1->y)? 0 : R_PointToDist (curline->v1->x, curline->v1->y); rw_distance = FixedMul(hyp, finecosine[offsetangle>>ANGLETOFINESHIFT]); ds_p->x1 = rw_x = start; ds_p->x2 = stop; ds_p->curline = curline; rw_stopx = stop+1; { // killough 1/6/98, 2/1/98: remove limit on openings extern int *openings; // dropoff overflow extern size_t maxopenings; size_t pos = lastopening - openings; size_t need = (rw_stopx - start)*4 + pos; if (need > maxopenings) { drawseg_t *ds; //jff 8/9/98 needed for fix from ZDoom int *oldopenings = openings; // dropoff overflow int *oldlast = lastopening; // dropoff overflow do maxopenings = maxopenings ? maxopenings*2 : 16384; while (need > maxopenings); openings = realloc(openings, maxopenings * sizeof(*openings)); lastopening = openings + pos; // jff 8/9/98 borrowed fix for openings from ZDOOM1.14 // [RH] We also need to adjust the openings pointers that // were already stored in drawsegs. for (ds = drawsegs; ds < ds_p; ds++) { #define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast)\ ds->p = ds->p - oldopenings + openings; ADJUST (maskedtexturecol); ADJUST (sprtopclip); ADJUST (sprbottomclip); } #undef ADJUST } } // killough: end of code to remove limits on openings // 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 = texturetranslation[sidedef->midtexture]; midtexheight = (linedef->r_flags & RF_MID_TILE) ? 0 : textureheight[midtexture] >> FRACBITS; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; if (linedef->flags & ML_DONTPEGBOTTOM) { // bottom of texture at bottom fixed_t vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; rw_midtexturemid = vtop - viewz; } else // top of texture at top rw_midtexturemid = worldtop; rw_midtexturemid += FixedMod(sidedef->rowoffset, textureheight[midtexture]); 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 (linedef->r_flags & RF_CLOSED) { /* cph - closed 2S line e.g. door */ // cph - killough's (outdated) comment follows - this deals with both // "automap fixes", his and mine // killough 1/17/98: this test is required if the fix // for the automap bug (r_bsp.c) is used, or else some // sprites will be displayed behind closed doors. That // fix prevents lines behind closed doors with dropoffs // from being displayed on the automap. ds_p->silhouette = SIL_BOTH; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT_MAX; ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT_MIN; } else { /* not solid - old code */ 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; } 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; } } 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; markfloor = worldlow != worldbottom || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel // killough 3/7/98: Add checks for (x,y) offsets || backsector->floor_xoffs != frontsector->floor_xoffs || backsector->floor_yoffs != frontsector->floor_yoffs // killough 4/15/98: prevent 2s normals // from bleeding through deep water || frontsector->heightsec != -1 // killough 4/17/98: draw floors if different light levels || backsector->floorlightsec != frontsector->floorlightsec ; markceiling = worldhigh != worldtop || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel // killough 3/7/98: Add checks for (x,y) offsets || backsector->ceiling_xoffs != frontsector->ceiling_xoffs || backsector->ceiling_yoffs != frontsector->ceiling_yoffs // killough 4/15/98: prevent 2s normals // from bleeding through fake ceilings || (frontsector->heightsec != -1 && frontsector->ceilingpic!=skyflatnum) // killough 4/17/98: draw ceilings if different light levels || backsector->ceilinglightsec != frontsector->ceilinglightsec ; if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight) markceiling = markfloor = true; // closed door if (worldhigh < worldtop) // top texture { toptexture = texturetranslation[sidedef->toptexture]; toptexheight = (linedef->r_flags & RF_TOP_TILE) ? 0 : textureheight[toptexture] >> FRACBITS; rw_toptexturemid = linedef->flags & ML_DONTPEGTOP ? worldtop : backsector->ceilingheight+textureheight[sidedef->toptexture]-viewz; rw_toptexturemid += FixedMod(sidedef->rowoffset, textureheight[toptexture]); } if (worldlow > worldbottom) // bottom texture { bottomtexture = texturetranslation[sidedef->bottomtexture]; bottomtexheight = (linedef->r_flags & RF_BOT_TILE) ? 0 : textureheight[bottomtexture] >> FRACBITS; rw_bottomtexturemid = linedef->flags & ML_DONTPEGBOTTOM ? worldtop : worldlow; rw_bottomtexturemid += FixedMod(sidedef->rowoffset, textureheight[bottomtexture]); } // 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; } } // calculate rw_offset (only needed for textured lines) segtextured = midtexture | toptexture | bottomtexture | maskedtexture; if (segtextured) { rw_offset = FixedMul (hyp, -finesine[offsetangle >>ANGLETOFINESHIFT]); rw_offset += sidedef->textureoffset + curline->offset; rw_centerangle = ANG90 + viewangle - rw_normalangle; rw_lightlevel = frontsector->lightlevel; } // Remember the vars used to determine fractional U texture // coords for later - POPE ds_p->rw_offset = rw_offset; ds_p->rw_distance = rw_distance; ds_p->rw_centerangle = rw_centerangle; // 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. // killough 3/7/98: add deep water check if (frontsector->heightsec == -1) { 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); } } // render it if (markceiling) { if (ceilingplane) // killough 4/11/98: add NULL ptr checks ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); else markceiling = 0; } if (markfloor) { if (floorplane) // killough 4/11/98: add NULL ptr checks /* cph 2003/04/18 - ceilingplane and floorplane might be the same * visplane (e.g. if both skies); R_CheckPlane doesn't know about * modifications to the plane that might happen in parallel with the check * being made, so we have to override it and split them anyway if that is * a possibility, otherwise the floor marking would overwrite the ceiling * marking, resulting in HOM. */ if (markceiling && ceilingplane == floorplane) floorplane = R_DupPlane (floorplane, rw_x, rw_stopx-1); else floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); else markfloor = 0; } didsolidcol = 0; R_RenderSegLoop(); /* cph - if a column was made solid by this wall, we _must_ save full clipping info */ if (backsector && didsolidcol) { if (!(ds_p->silhouette & SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = backsector->floorheight; } if (!(ds_p->silhouette & SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = backsector->ceilingheight; } } // save sprite clipping info if ((ds_p->silhouette & SIL_TOP || maskedtexture) && !ds_p->sprtopclip) { memcpy (lastopening, ceilingclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; } if ((ds_p->silhouette & SIL_BOTTOM || maskedtexture) && !ds_p->sprbottomclip) { memcpy (lastopening, floorclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; } 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++; }