// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1999-2023 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file r_segs.c /// \brief All the clipping: columns, horizontal spans, sky columns #include "doomdef.h" #include "r_local.h" #include "r_sky.h" #include "r_portal.h" #include "w_wad.h" #include "z_zone.h" #include "p_slopes.h" #include "taglist.h" // OPTIMIZE: closed two sided lines as single sided // 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 INT32 toptexture, bottomtexture, midtexture; static INT32 numthicksides, numbackffloors; angle_t rw_normalangle; // angle to line origin angle_t rw_angle1; fixed_t rw_distance; // // regular wall // static INT32 rw_x, rw_stopx; static angle_t rw_centerangle; static fixed_t rw_offset, rw_offsetx; static fixed_t rw_offset_top, rw_offset_mid, rw_offset_bottom; static fixed_t rw_scale, rw_scalestep; static fixed_t rw_midtexturemid, rw_toptexturemid, rw_bottomtexturemid; static INT32 worldtop, worldbottom, worldhigh, worldlow; static INT32 worldtopslope, worldbottomslope, worldhighslope, worldlowslope; // worldtop/bottom at end of slope static fixed_t rw_toptextureslide, rw_midtextureslide, rw_bottomtextureslide; // Defines how to adjust Y offsets along the wall for slopes static fixed_t rw_midtextureback, rw_midtexturebackslide; // Values for masked midtexture height calculation static fixed_t rw_midtexturescalex, rw_midtexturescaley; static fixed_t rw_toptexturescalex, rw_toptexturescaley; static fixed_t rw_bottomtexturescalex, rw_bottomtexturescaley; static fixed_t rw_invmidtexturescalex, rw_invtoptexturescalex, rw_invbottomtexturescalex; // Lactozilla: 3D floor clipping static boolean rw_floormarked = false; static boolean rw_ceilingmarked = false; static INT32 *rw_silhouette = NULL; static fixed_t *rw_tsilheight = NULL; static fixed_t *rw_bsilheight = NULL; static fixed_t pixhigh, pixlow, pixhighstep, pixlowstep; static fixed_t topfrac, topstep; static fixed_t bottomfrac, bottomstep; static lighttable_t **walllights; static fixed_t *maskedtexturecol = NULL; static fixed_t *maskedtextureheight = NULL; static fixed_t *thicksidecol = NULL; static fixed_t *invscale = NULL; static boolean texcoltables; //SoM: 3/23/2000: Use boom opening limit removal static size_t numopenings; static INT16 *openings, *lastopening; static size_t texturecolumntablesize; static fixed_t *texturecolumntable, *curtexturecolumntable; void R_ClearSegTables(void) { lastopening = openings; curtexturecolumntable = texturecolumntable; } transnum_t R_GetLinedefTransTable(fixed_t alpha) { return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1); } void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { size_t pindex; column_t *col; INT32 lightnum, texnum, i; fixed_t height, realbot; lightlist_t *light; r_lightlist_t *rlight; void (*colfunc_2s)(column_t *, unsigned); line_t *ldef; sector_t *front, *back; INT32 times, repeats; INT64 overflow_test; INT32 range; UINT8 vertflip; unsigned lengthcol; fixed_t wall_scaley; fixed_t scalestep; fixed_t scale1; // Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; frontsector = curline->frontsector; backsector = curline->backsector; sidedef = curline->sidedef; texnum = R_GetTextureNum(sidedef->midtexture); windowbottom = windowtop = sprbotscreen = INT32_MAX; ldef = curline->linedef; if (!ldef->alpha) return; if (ldef->blendmode == AST_FOG) { colfunc = colfuncs[COLDRAWFUNC_FOG]; windowtop = frontsector->ceilingheight; windowbottom = frontsector->floorheight; } else if (ldef->blendmode) { if (ldef->alpha == NUMTRANSMAPS || ldef->blendmode == AST_MODULATE) dc_transmap = R_GetBlendTable(ldef->blendmode, 0); else dc_transmap = R_GetBlendTable(ldef->blendmode, R_GetLinedefTransTable(ldef->alpha)); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } else if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) { dc_transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } else colfunc = colfuncs[BASEDRAWFUNC]; if (curline->polyseg && curline->polyseg->translucency > 0) { if (curline->polyseg->translucency >= NUMTRANSMAPS) return; dc_transmap = R_GetTranslucencyTable(curline->polyseg->translucency); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } vertflip = textures[texnum]->flip & 2; wall_scaley = sidedef->scaley_mid; if (wall_scaley < 0) { wall_scaley = -wall_scaley; vertflip = !vertflip; } scalestep = FixedDiv(ds->scalestep, wall_scaley); scale1 = FixedDiv(ds->scale1, wall_scaley); range = max(ds->x2-ds->x1, 1); rw_scalestep = scalestep; spryscale = scale1 + (x1 - ds->x1)*rw_scalestep; // Texture must be cached R_CheckTextureCache(texnum); if (vertflip) // vertically flipped? colfunc_2s = R_DrawFlippedMaskedColumn; else colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture lengthcol = textures[texnum]->height; // Setup lighting based on the presence/lack-of 3D floors. dc_numlights = 0; if (frontsector->numlights) { dc_numlights = frontsector->numlights; if (dc_numlights >= dc_maxlights) { dc_maxlights = dc_numlights; dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL); } for (i = 0; i < dc_numlights; i++) { fixed_t leftheight, rightheight; light = &frontsector->lightlist[i]; rlight = &dc_lightlist[i]; leftheight = P_GetLightZAt(light, ds-> leftpos.x, ds-> leftpos.y); rightheight = P_GetLightZAt(light, ds->rightpos.x, ds->rightpos.y); leftheight -= viewz; rightheight -= viewz; rlight->height = (centeryfrac) - FixedMul(leftheight , ds->scale1); rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2); rlight->heightstep = (rlight->heightstep-rlight->height)/(range); //if (x1 > ds->x1) //rlight->height -= (x1 - ds->x1)*rlight->heightstep; rlight->startheight = rlight->height; // keep starting value here to reset for each repeat rlight->lightlevel = *light->lightlevel; rlight->extra_colormap = *light->extra_colormap; rlight->flags = light->flags; if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY]) || (rlight->flags & FOF_FOG) || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))) lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT); else lightnum = LIGHTLEVELS - 1; if (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)) ; else if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; rlight->lightnum = lightnum; } } else { if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY]) || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); else lightnum = LIGHTLEVELS - 1; if (colfunc == colfuncs[COLDRAWFUNC_FOG] || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) ; else if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS - 1]; else walllights = scalelight[lightnum]; } maskedtexturecol = ds->maskedtexturecol; mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; if (frontsector->heightsec != -1) front = §ors[frontsector->heightsec]; else front = frontsector; if (backsector->heightsec != -1) back = §ors[backsector->heightsec]; else back = backsector; if (sidedef->repeatcnt) repeats = 1 + sidedef->repeatcnt; else if (ldef->flags & ML_WRAPMIDTEX) { fixed_t high, low; if (front->ceilingheight > back->ceilingheight) high = back->ceilingheight; else high = front->ceilingheight; if (front->floorheight > back->floorheight) low = front->floorheight; else low = back->floorheight; repeats = (high - low)/textureheight[texnum]; if ((high-low)%textureheight[texnum]) repeats++; // tile an extra time to fill the gap -- Monster Iestyn } else repeats = 1; for (times = 0; times < repeats; times++) { if (times > 0) { rw_scalestep = scalestep; spryscale = scale1 + (x1 - ds->x1)*rw_scalestep; // reset all lights to their starting heights for (i = 0; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; rlight->height = rlight->startheight; } } dc_texheight = textureheight[texnum]>>FRACBITS; // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { dc_texturemid = ds->maskedtextureheight[dc_x]; if (curline->linedef->flags & ML_MIDPEG) dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; else dc_texturemid -= (textureheight[texnum])*times; // Check for overflows first overflow_test = (INT64)centeryfrac - (((INT64)dc_texturemid*spryscale)>>FRACBITS); if (overflow_test < 0) overflow_test = -overflow_test; if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) { // Eh, no, go away, don't waste our time if (dc_numlights) { for (i = 0; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; rlight->height += rlight->heightstep; } } spryscale += rw_scalestep; continue; } // calculate lighting if (dc_numlights) { lighttable_t **xwalllights; sprbotscreen = INT32_MAX; sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale)); realbot = FixedMul(textureheight[texnum], spryscale) + sprtopscreen; dc_iscale = FixedMul(ds->invscale[dc_x], wall_scaley); windowbottom = realbot; // draw the texture col = R_GetColumn(texnum, maskedtexturecol[dc_x] >> FRACBITS); for (i = 0; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; if ((rlight->flags & FOF_NOSHADE)) continue; if (rlight->lightnum < 0) xwalllights = scalelight[0]; else if (rlight->lightnum >= LIGHTLEVELS) xwalllights = scalelight[LIGHTLEVELS-1]; else xwalllights = scalelight[rlight->lightnum]; pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; if (rlight->extra_colormap) rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); else rlight->rcolormap = xwalllights[pindex]; height = rlight->height; rlight->height += rlight->heightstep; if (height <= windowtop) { dc_colormap = rlight->rcolormap; continue; } windowbottom = height; if (windowbottom >= realbot) { windowbottom = realbot; colfunc_2s(col, lengthcol); for (i++; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; rlight->height += rlight->heightstep; } continue; } colfunc_2s(col, lengthcol); windowtop = windowbottom + 1; dc_colormap = rlight->rcolormap; } windowbottom = realbot; if (windowtop < windowbottom) colfunc_2s(col, lengthcol); spryscale += rw_scalestep; continue; } // calculate lighting pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); dc_iscale = FixedMul(ds->invscale[dc_x], wall_scaley); // draw the texture col = R_GetColumn(texnum, maskedtexturecol[dc_x] >> FRACBITS); colfunc_2s(col, lengthcol); spryscale += rw_scalestep; } } colfunc = colfuncs[BASEDRAWFUNC]; } // Loop through R_DrawMaskedColumn calls static void R_DrawRepeatMaskedColumn(column_t *col, unsigned lengthcol) { while (sprtopscreen < sprbotscreen) { R_DrawMaskedColumn(col, lengthcol); if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow sprtopscreen = INT32_MAX; else sprtopscreen += dc_texheight*spryscale; } } static void R_DrawRepeatFlippedMaskedColumn(column_t *col, unsigned lengthcol) { do { R_DrawFlippedMaskedColumn(col, lengthcol); sprtopscreen += dc_texheight*spryscale; } while (sprtopscreen < sprbotscreen); } // Returns true if a fake floor is translucent. static boolean R_IsFFloorTranslucent(visffloor_t *pfloor) { if (pfloor->polyobj) return (pfloor->polyobj->translucency > 0); // Polyobjects have no ffloors, and they're handled in the conditional above. if (pfloor->ffloor != NULL) return (pfloor->ffloor->fofflags & (FOF_TRANSLUCENT|FOF_FOG)); return false; } static fixed_t R_GetSlopeTextureSlide(pslope_t *slope, angle_t lineangle) { return FixedMul(slope->zdelta, FINECOSINE((lineangle-slope->xydirection)>>ANGLETOFINESHIFT)); } // // R_RenderThickSideRange // Renders all the thick sides in the given range. static fixed_t ffloortexturecolumn[MAXVIDWIDTH]; void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { size_t pindex; column_t * col; INT32 lightnum; INT32 texnum; sector_t tempsec; INT32 templight; INT32 i, p; fixed_t offsetvalue; lightlist_t *light; r_lightlist_t *rlight; INT32 range; // Render FOF sides kinda like normal sides, with the frac and step and everything // NOTE: INT64 instead of fixed_t because overflow concerns INT64 top_frac, top_step, bottom_frac, bottom_step; // skew FOF walls with slopes? fixed_t ffloortextureslide = 0; fixed_t oldtexturecolumn = -1; fixed_t left_top, left_bottom; // needed here for slope skewing pslope_t *skewslope = NULL; boolean do_texture_skew; boolean dont_peg_bottom; fixed_t wall_offsetx; fixed_t wall_scalex, wall_scaley; UINT8 vertflip; unsigned lengthcol; void (*colfunc_2s) (column_t *, unsigned); // Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; backsector = pfloor->target; frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector; sidedef = R_GetFFloorSide(curline, pfloor); colfunc = colfuncs[BASEDRAWFUNC]; if (pfloor->master->flags & ML_TFERLINE) { line_t *newline = R_GetFFloorLine(curline, pfloor); do_texture_skew = newline->flags & ML_SKEWTD; dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM; } else { do_texture_skew = pfloor->master->flags & ML_SKEWTD; dont_peg_bottom = curline->linedef->flags & ML_DONTPEGBOTTOM; } texnum = R_GetTextureNum(sidedef->midtexture); vertflip = textures[texnum]->flip & 2; if (pfloor->fofflags & FOF_TRANSLUCENT) { boolean fuzzy = true; // Hacked up support for alpha value in software mode Tails 09-24-2002 // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 { INT32 trans = (10*((256+12) - pfloor->alpha))/255; if (trans >= 10) return; // Don't even draw it if (pfloor->blend) // additive, (reverse) subtractive, modulative dc_transmap = R_GetBlendTable(pfloor->blend, trans); else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0) fuzzy = false; // Opaque } if (fuzzy) colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } else if (pfloor->fofflags & FOF_FOG) colfunc = colfuncs[COLDRAWFUNC_FOG]; range = max(ds->x2-ds->x1, 1); //SoM: Moved these up here so they are available for my lightlist calculations rw_scalestep = ds->scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; dc_numlights = 0; if (frontsector->numlights) { dc_numlights = frontsector->numlights; if (dc_numlights > dc_maxlights) { dc_maxlights = dc_numlights; dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL); } for (i = p = 0; i < dc_numlights; i++) { fixed_t leftheight, rightheight; fixed_t pfloorleft, pfloorright; INT64 overflow_test; light = &frontsector->lightlist[i]; rlight = &dc_lightlist[p]; #define SLOPEPARAMS(slope, end1, end2, normalheight) \ end1 = P_GetZAt(slope, ds-> leftpos.x, ds-> leftpos.y, normalheight); \ end2 = P_GetZAt(slope, ds->rightpos.x, ds->rightpos.y, normalheight); SLOPEPARAMS(light->slope, leftheight, rightheight, light->height) SLOPEPARAMS(*pfloor->b_slope, pfloorleft, pfloorright, *pfloor->bottomheight) if (leftheight < pfloorleft && rightheight < pfloorright) continue; SLOPEPARAMS(*pfloor->t_slope, pfloorleft, pfloorright, *pfloor->topheight) if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights) { lightlist_t *nextlight = &frontsector->lightlist[i+1]; if (P_GetZAt(nextlight->slope, ds-> leftpos.x, ds-> leftpos.y, nextlight->height) > pfloorleft && P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y, nextlight->height) > pfloorright) continue; } leftheight -= viewz; rightheight -= viewz; #define CLAMPMAX INT32_MAX #define CLAMPMIN (-INT32_MAX) // This is not INT32_MIN on purpose! INT32_MIN makes the drawers freak out. // Monster Iestyn (25/03/18): do not skip these lights if they fail overflow test, just clamp them instead so they behave. overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS); if (overflow_test > (INT64)CLAMPMAX) rlight->height = CLAMPMAX; else if (overflow_test > (INT64)CLAMPMIN) rlight->height = (fixed_t)overflow_test; else rlight->height = CLAMPMIN; overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS); if (overflow_test > (INT64)CLAMPMAX) rlight->heightstep = CLAMPMAX; else if (overflow_test > (INT64)CLAMPMIN) rlight->heightstep = (fixed_t)overflow_test; else rlight->heightstep = CLAMPMIN; rlight->heightstep = (rlight->heightstep-rlight->height)/(range); rlight->flags = light->flags; if (light->flags & FOF_CUTLEVEL) { SLOPEPARAMS(*light->caster->b_slope, leftheight, rightheight, *light->caster->bottomheight) #undef SLOPEPARAMS leftheight -= viewz; rightheight -= viewz; // Monster Iestyn (25/03/18): do not skip these lights if they fail overflow test, just clamp them instead so they behave. overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS); if (overflow_test > (INT64)CLAMPMAX) rlight->botheight = CLAMPMAX; else if (overflow_test > (INT64)CLAMPMIN) rlight->botheight = (fixed_t)overflow_test; else rlight->botheight = CLAMPMIN; overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS); if (overflow_test > (INT64)CLAMPMAX) rlight->botheightstep = CLAMPMAX; else if (overflow_test > (INT64)CLAMPMIN) rlight->botheightstep = (fixed_t)overflow_test; else rlight->botheightstep = CLAMPMIN; rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range); } rlight->lightlevel = *light->lightlevel; rlight->extra_colormap = *light->extra_colormap; // Check if the current light effects the colormap/lightlevel if (pfloor->fofflags & FOF_FOG) rlight->lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT); else rlight->lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT); if (pfloor->fofflags & FOF_FOG || rlight->flags & FOF_FOG || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))) ; else if (curline->v1->y == curline->v2->y) rlight->lightnum--; else if (curline->v1->x == curline->v2->x) rlight->lightnum++; p++; } dc_numlights = p; } else { // Get correct light level! if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); else if (pfloor->fofflags & FOF_FOG) lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT); else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY]) lightnum = LIGHTLEVELS-1; else lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false) ->lightlevel >> LIGHTSEGSHIFT; if (pfloor->fofflags & FOF_FOG || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))); else if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS-1]; else walllights = scalelight[lightnum]; } wall_scalex = FixedDiv(FRACUNIT, sidedef->scalex_mid); wall_scaley = sidedef->scaley_mid; if (wall_scaley < 0) { wall_scaley = -wall_scaley; vertflip = !vertflip; } thicksidecol = ffloortexturecolumn; wall_offsetx = ds->offsetx + sidedef->offsetx_mid; if (wall_scalex == FRACUNIT) { for (INT32 x = x1; x <= x2; x++) thicksidecol[x] = ds->thicksidecol[x]; } else { for (INT32 x = x1; x <= x2; x++) thicksidecol[x] = FixedDiv(ds->thicksidecol[x], wall_scalex); } mfloorclip = ds->sprbottomclip; mceilingclip = ds->sprtopclip; dc_texheight = textureheight[texnum]>>FRACBITS; // calculate both left ends left_top = P_GetFFloorTopZAt (pfloor, ds->leftpos.x, ds->leftpos.y) - viewz; left_bottom = P_GetFFloorBottomZAt(pfloor, ds->leftpos.x, ds->leftpos.y) - viewz; if (do_texture_skew) { skewslope = *pfloor->t_slope; // skew using top slope by default dc_texturemid = FixedMul(left_top, wall_scaley); } else dc_texturemid = FixedMul(*pfloor->topheight - viewz, wall_scaley); offsetvalue = sidedef->rowoffset + sidedef->offsety_mid; if (dont_peg_bottom) { if (do_texture_skew) { skewslope = *pfloor->b_slope; // skew using bottom slope dc_texturemid = FixedMul(left_bottom, wall_scaley); } else offsetvalue -= FixedMul(*pfloor->topheight - *pfloor->bottomheight, wall_scaley); } if (skewslope) { angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); ffloortextureslide = FixedMul(R_GetSlopeTextureSlide(skewslope, lineangle), wall_scaley); } dc_texturemid += offsetvalue; // Texture must be cached R_CheckTextureCache(texnum); if (vertflip) // vertically flipped? colfunc_2s = R_DrawRepeatFlippedMaskedColumn; else colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture lengthcol = textures[texnum]->height; // Set heights according to plane, or slope, whichever { fixed_t right_top, right_bottom; // calculate right ends now right_top = P_GetFFloorTopZAt (pfloor, ds->rightpos.x, ds->rightpos.y) - viewz; right_bottom = P_GetFFloorBottomZAt(pfloor, ds->rightpos.x, ds->rightpos.y) - viewz; // using INT64 to avoid 32bit overflow top_frac = (INT64)centeryfrac - (((INT64)left_top * ds->scale1) >> FRACBITS); bottom_frac = (INT64)centeryfrac - (((INT64)left_bottom * ds->scale1) >> FRACBITS); top_step = (INT64)centeryfrac - (((INT64)right_top * ds->scale2) >> FRACBITS); bottom_step = (INT64)centeryfrac - (((INT64)right_bottom * ds->scale2) >> FRACBITS); top_step = (top_step-top_frac)/(range); bottom_step = (bottom_step-bottom_frac)/(range); top_frac += top_step * (x1 - ds->x1); bottom_frac += bottom_step * (x1 - ds->x1); } // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { // skew FOF walls if (ffloortextureslide) { if (oldtexturecolumn != -1) dc_texturemid += FixedMul(ffloortextureslide, oldtexturecolumn-ds->thicksidecol[dc_x]); oldtexturecolumn = ds->thicksidecol[dc_x]; } // Calculate bounds // clamp the values if necessary to avoid overflows and rendering glitches caused by them if (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX; else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac; else sprtopscreen = windowtop = CLAMPMIN; if (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX; else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac; else sprbotscreen = windowbottom = CLAMPMIN; top_frac += top_step; bottom_frac += bottom_step; // SoM: If column is out of range, why bother with it?? if (windowbottom < 0 || windowtop > (viewheight << FRACBITS)) { if (dc_numlights) { for (i = 0; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; rlight->height += rlight->heightstep; if (rlight->flags & FOF_CUTLEVEL) rlight->botheight += rlight->botheightstep; } } spryscale += rw_scalestep; continue; } dc_iscale = FixedMul(0xffffffffu / (unsigned)spryscale, wall_scaley); // Get data for the column col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS)); // SoM: New code does not rely on R_DrawColumnShadowed_8 which // will (hopefully) put less strain on the stack. if (dc_numlights) { lighttable_t **xwalllights; fixed_t height; fixed_t bheight = 0; INT32 solid = 0; INT32 lighteffect = 0; for (i = 0; i < dc_numlights; i++) { // Check if the current light effects the colormap/lightlevel rlight = &dc_lightlist[i]; lighteffect = !(dc_lightlist[i].flags & FOF_NOSHADE); if (lighteffect) { lightnum = rlight->lightnum; if (lightnum < 0) xwalllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) xwalllights = scalelight[LIGHTLEVELS-1]; else xwalllights = scalelight[lightnum]; pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE-1; if (pfloor->fofflags & FOF_FOG) { if (pfloor->master->frontsector->extra_colormap) rlight->rcolormap = pfloor->master->frontsector->extra_colormap->colormap + (xwalllights[pindex] - colormaps); else rlight->rcolormap = xwalllights[pindex]; } else { if (rlight->extra_colormap) rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); else rlight->rcolormap = xwalllights[pindex]; } } solid = 0; // don't carry over solid-cutting flag from the previous light // Check if the current light can cut the current 3D floor. if (rlight->flags & FOF_CUTSOLIDS && !(pfloor->fofflags & FOF_EXTRA)) solid = 1; else if (rlight->flags & FOF_CUTEXTRA && pfloor->fofflags & FOF_EXTRA) { if (rlight->flags & FOF_EXTRA) { // The light is from an extra 3D floor... Check the flags so // there are no undesired cuts. if ((rlight->flags & (FOF_FOG|FOF_SWIMMABLE)) == (pfloor->fofflags & (FOF_FOG|FOF_SWIMMABLE))) solid = 1; } else solid = 1; } else solid = 0; height = rlight->height; rlight->height += rlight->heightstep; if (solid) { bheight = rlight->botheight - (FRACUNIT >> 1); rlight->botheight += rlight->botheightstep; } if (height <= windowtop) { if (lighteffect) dc_colormap = rlight->rcolormap; if (solid && windowtop < bheight) windowtop = bheight; continue; } windowbottom = height; if (windowbottom >= sprbotscreen) { windowbottom = sprbotscreen; // draw the texture colfunc_2s (col, lengthcol); for (i++; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; rlight->height += rlight->heightstep; if (rlight->flags & FOF_CUTLEVEL) rlight->botheight += rlight->botheightstep; } continue; } // draw the texture colfunc_2s (col, lengthcol); if (solid) windowtop = bheight; else windowtop = windowbottom + 1; if (lighteffect) dc_colormap = rlight->rcolormap; } windowbottom = sprbotscreen; // draw the texture, if there is any space left if (windowtop < windowbottom) colfunc_2s (col, lengthcol); spryscale += rw_scalestep; continue; } // calculate lighting pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; if (pfloor->fofflags & FOF_FOG && pfloor->master->frontsector->extra_colormap) dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps); else if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); // draw the texture colfunc_2s (col, lengthcol); spryscale += rw_scalestep; } colfunc = colfuncs[BASEDRAWFUNC]; #undef CLAMPMAX #undef CLAMPMIN } // R_ExpandPlaneY // // A simple function to modify a visplane's top and bottom for a particular column // Sort of like R_ExpandPlane in r_plane.c, except this is vertical expansion static inline void R_ExpandPlaneY(visplane_t *pl, INT32 x, INT16 top, INT16 bottom) { // Expand the plane, don't shrink it! // note: top and bottom default to 0xFFFF and 0x0000 respectively, which is totally compatible with this if (pl->top[x] > top) pl->top[x] = top; if (pl->bottom[x] < bottom) pl->bottom[x] = bottom; } // R_FFloorCanClip // // Returns true if a fake floor can clip a column away. static boolean R_FFloorCanClip(visffloor_t *pfloor) { return (cv_ffloorclip.value && !R_IsFFloorTranslucent(pfloor) && !pfloor->polyobj); } // // 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; top = ceilingclip[rw_x]+1; // no space above wall? if (yl < top) yl = top; if (markceiling) { #if 0 bottom = yl-1; if (bottom >= floorclip[rw_x]) bottom = floorclip[rw_x]-1; if (top <= bottom) #else bottom = yl > floorclip[rw_x] ? floorclip[rw_x] : yl; if (top <= --bottom && ceilingplane) #endif R_ExpandPlaneY(ceilingplane, rw_x, top, 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) R_ExpandPlaneY(floorplane, rw_x, top, bottom); } rw_floormarked = false; rw_ceilingmarked = false; if (numffloors) { INT16 fftop, ffbottom; firstseg->frontscale[rw_x] = frontscale[rw_x]; top = ceilingclip[rw_x]+1; // PRBoom bottom = floorclip[rw_x]-1; // PRBoom for (i = 0; i < numffloors; i++) { if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg)) continue; if (ffloor[i].height < viewz) { INT32 top_w = (ffloor[i].f_frac >> HEIGHTBITS) + 1; INT32 bottom_w = ffloor[i].f_clip[rw_x]; if (top_w < top) top_w = top; if (bottom_w > bottom) bottom_w = bottom; // Polyobject-specific hack to fix plane leaking -Red if (ffloor[i].polyobj && top_w >= bottom_w) { ffloor[i].plane->top[rw_x] = 0xFFFF; ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 } else { if (top_w <= bottom_w) { fftop = (INT16)top_w; ffbottom = (INT16)bottom_w; ffloor[i].plane->top[rw_x] = fftop; ffloor[i].plane->bottom[rw_x] = ffbottom; // Lactozilla: Cull part of the column by the 3D floor if it can't be seen // "bottom" is the top pixel of the floor column if (ffbottom >= bottom-1 && R_FFloorCanClip(&ffloor[i]) && !curline->polyseg) { rw_floormarked = true; floorclip[rw_x] = fftop; if (yh > fftop) yh = fftop; if (markfloor && floorplane) floorplane->top[rw_x] = bottom; if (rw_silhouette) { (*rw_silhouette) |= SIL_BOTTOM; (*rw_bsilheight) = INT32_MAX; } } } } } else if (ffloor[i].height > viewz) { INT32 top_w = ffloor[i].c_clip[rw_x] + 1; INT32 bottom_w = (ffloor[i].f_frac >> HEIGHTBITS); if (top_w < top) top_w = top; if (bottom_w > bottom) bottom_w = bottom; // Polyobject-specific hack to fix plane leaking -Red if (ffloor[i].polyobj && top_w >= bottom_w) { ffloor[i].plane->top[rw_x] = 0xFFFF; ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 } else { if (top_w <= bottom_w) { fftop = (INT16)top_w; ffbottom = (INT16)bottom_w; ffloor[i].plane->top[rw_x] = fftop; ffloor[i].plane->bottom[rw_x] = ffbottom; // Lactozilla: Cull part of the column by the 3D floor if it can't be seen // "top" is the height of the ceiling column if (fftop <= top+1 && R_FFloorCanClip(&ffloor[i]) && !curline->polyseg) { rw_ceilingmarked = true; ceilingclip[rw_x] = ffbottom; if (yl < ffbottom) yl = ffbottom; if (markceiling && ceilingplane) ceilingplane->bottom[rw_x] = top; if (rw_silhouette) { (*rw_silhouette) |= SIL_TOP; (*rw_tsilheight) = INT32_MIN; } } } } } } } //SoM: Calculate offsets for Thick fake floors. // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; textureoffset = rw_offset - FixedMul(FINETANGENT(angle), rw_distance); texturecolumn = FixedDiv(textureoffset, rw_invmidtexturescalex); // texturecolumn and lighting are independent of wall tiers if (segtextured) { // calculate lighting pindex = FixedMul(rw_scale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE-1; dc_colormap = walllights[pindex]; dc_x = rw_x; if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); } if (dc_numlights) { lighttable_t **xwalllights; for (i = 0; i < dc_numlights; i++) { INT32 lightnum; lightnum = (dc_lightlist[i].lightlevel >> LIGHTSEGSHIFT); if (dc_lightlist[i].extra_colormap) ; else if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) xwalllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) xwalllights = scalelight[LIGHTLEVELS-1]; else xwalllights = scalelight[lightnum]; pindex = FixedMul(rw_scale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE-1; if (dc_lightlist[i].extra_colormap) dc_lightlist[i].rcolormap = dc_lightlist[i].extra_colormap->colormap + (xwalllights[pindex] - colormaps); else dc_lightlist[i].rcolormap = xwalllights[pindex]; } } frontscale[rw_x] = rw_scale; // draw the wall tiers if (midtexture) { // single sided line if (yl <= yh && yh >= 0 && yl < viewheight) { fixed_t offset = texturecolumn + rw_offsetx; dc_yl = yl; dc_yh = yh; dc_texturemid = rw_midtexturemid; dc_texheight = textureheight[midtexture]>>FRACBITS; dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, midscaley); drawmiddle(R_GetColumn(midtexture, offset >> FRACBITS)->pixels, dc_texheight); // dont draw anything more for this column, since // a midtexture blocks the view if (!rw_ceilingmarked) ceilingclip[rw_x] = (INT16)viewheight; if (!rw_floormarked) floorclip[rw_x] = -1; } else { // note: don't use min/max macros, since casting from INT32 to INT16 is involved here if (markceiling && (!rw_ceilingmarked)) ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; if (markfloor && (!rw_floormarked)) floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; } } else { INT16 topclip = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; INT16 bottomclip = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; // two sided line if (toptexture) { // top wall mid = pixhigh>>HEIGHTBITS; pixhigh += pixhighstep; if (mid >= floorclip[rw_x]) mid = floorclip[rw_x]-1; toptexturecolumn = FixedDiv(textureoffset, rw_invtoptexturescalex); if (mid >= yl) // back ceiling lower than front ceiling ? { if (yl >= viewheight) // entirely off bottom of screen { if (!rw_ceilingmarked) ceilingclip[rw_x] = (INT16)viewheight; } else if (mid >= 0) // safe to draw top texture { fixed_t offset = rw_offset_top; if (rw_toptexturescalex < 0) offset = -offset; offset = toptexturecolumn + offset; dc_yl = yl; dc_yh = mid; dc_texturemid = rw_toptexturemid; dc_texheight = textureheight[toptexture]>>FRACBITS; dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, topscaley); drawtop(R_GetColumn(toptexture, offset >> FRACBITS)->pixels, dc_texheight); ceilingclip[rw_x] = (INT16)mid; } else if (!rw_ceilingmarked) // entirely off top of screen ceilingclip[rw_x] = -1; } else if (!rw_ceilingmarked) ceilingclip[rw_x] = topclip; if (oldtexturecolumn_top != -1) rw_toptexturemid += FixedMul(rw_toptextureslide, oldtexturecolumn_top-textureoffset); oldtexturecolumn_top = textureoffset; } else if (markceiling && (!rw_ceilingmarked)) // no top wall ceilingclip[rw_x] = topclip; 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; bottomtexturecolumn = FixedDiv(textureoffset, rw_invbottomtexturescalex); if (mid <= yh) // back floor higher than front floor ? { if (yh < 0) // entirely off top of screen { if (!rw_floormarked) floorclip[rw_x] = -1; } else if (mid < viewheight) // safe to draw bottom texture { fixed_t offset = rw_offset_bottom; if (rw_bottomtexturescalex < 0) offset = -offset; offset = bottomtexturecolumn + offset; dc_yl = mid; dc_yh = yh; dc_texturemid = rw_bottomtexturemid; dc_texheight = textureheight[bottomtexture]>>FRACBITS; dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, bottomscaley); drawbottom(R_GetColumn(bottomtexture, offset >> FRACBITS)->pixels, dc_texheight); floorclip[rw_x] = (INT16)mid; } else if (!rw_floormarked) // entirely off bottom of screen floorclip[rw_x] = (INT16)viewheight; } else if (!rw_floormarked) floorclip[rw_x] = bottomclip; if (oldtexturecolumn_bottom != -1) rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn_bottom-textureoffset); oldtexturecolumn_bottom = textureoffset; } else if (markfloor && (!rw_floormarked)) // no bottom wall floorclip[rw_x] = bottomclip; } if (maskedtexturecol) maskedtexturecol[rw_x] = texturecolumn + rw_offsetx; if (thicksidecol) thicksidecol[rw_x] = textureoffset; if (maskedtextureheight) { if (curline->linedef->flags & ML_MIDPEG) maskedtextureheight[rw_x] = max(rw_midtexturemid, rw_midtextureback); else maskedtextureheight[rw_x] = min(rw_midtexturemid, rw_midtextureback); } if (midtexture || maskedtextureheight) { if (oldtexturecolumn != -1) { INT32 diff = oldtexturecolumn-textureoffset; if (rw_invmidtexturescalex < 0) diff = -diff; rw_midtexturemid += FixedMul(rw_midtextureslide, diff); rw_midtextureback += FixedMul(rw_midtexturebackslide, diff); } oldtexturecolumn = textureoffset; } if (invscale) invscale[rw_x] = 0xffffffffu / (unsigned)rw_scale; if (dc_numlights) { for (i = 0; i < dc_numlights; i++) { dc_lightlist[i].height += dc_lightlist[i].heightstep; if (dc_lightlist[i].flags & FOF_CUTSOLIDS) dc_lightlist[i].botheight += dc_lightlist[i].botheightstep; } } for (i = 0; i < numffloors; i++) { if (curline->polyseg && (ffloor[i].polyobj != curline->polyseg)) continue; ffloor[i].f_frac += ffloor[i].f_step; } for (i = 0; i < numbackffloors; i++) { if (curline->polyseg && (ffloor[i].polyobj != curline->polyseg)) continue; ffloor[i].f_clip[rw_x] = ffloor[i].c_clip[rw_x] = (INT16)((ffloor[i].b_frac >> HEIGHTBITS) & 0xFFFF); ffloor[i].b_frac += ffloor[i].b_step; } rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; } } // Uses precalculated seg->length static INT64 R_CalcSegDist(seg_t* seg, INT64 x2, INT64 y2) { if (!seg->linedef->dy) return llabs(y2 - seg->v1->y); else if (!seg->linedef->dx) return llabs(x2 - seg->v1->x); else { INT64 dx = (seg->v2->x)-(seg->v1->x); INT64 dy = (seg->v2->y)-(seg->v1->y); INT64 vdx = x2-(seg->v1->x); INT64 vdy = y2-(seg->v1->y); return ((dy*vdx)-(dx*vdy))/(seg->length); } } //SoM: Code to remove limits on openings. static void R_AllocClippingTables(size_t range) { size_t pos = lastopening - openings; size_t need = range * 2; // for both sprtopclip and sprbottomclip if (pos + need < numopenings) return; INT16 *oldopenings = openings; INT16 *oldlast = lastopening; if (numopenings == 0) numopenings = 16384; numopenings += need; openings = Z_Realloc(openings, numopenings * sizeof (*openings), PU_STATIC, NULL); lastopening = openings + pos; if (oldopenings == NULL) return; // borrowed fix from *cough* zdoom *cough* // [RH] We also need to adjust the openings pointers that // were already stored in drawsegs. for (drawseg_t *ds = drawsegs; ds < ds_p; ds++) { // Check if it's in range of the openings if (ds->sprtopclip + ds->x1 >= oldopenings && ds->sprtopclip + ds->x1 <= oldlast) ds->sprtopclip = (ds->sprtopclip - oldopenings) + openings; if (ds->sprbottomclip + ds->x1 >= oldopenings && ds->sprbottomclip + ds->x1 <= oldlast) ds->sprbottomclip = (ds->sprbottomclip - oldopenings) + openings; } } static void R_AllocTextureColumnTables(size_t range) { size_t pos = curtexturecolumntable - texturecolumntable; size_t need = range * 4; if (pos + need < texturecolumntablesize) return; fixed_t *oldtable = texturecolumntable; fixed_t *oldlast = curtexturecolumntable; if (texturecolumntablesize == 0) texturecolumntablesize = 16384; texturecolumntablesize += need; texturecolumntable = Z_Realloc(texturecolumntable, texturecolumntablesize * sizeof (*texturecolumntable), PU_STATIC, NULL); curtexturecolumntable = texturecolumntable + pos; if (oldtable == NULL) return; for (drawseg_t *ds = drawsegs; ds < ds_p; ds++) { // Check if it's in range of the tables #define CHECK(which) \ if (which + ds->x1 >= oldtable && which + ds->x1 <= oldlast) \ which = (which - oldtable) + texturecolumntable CHECK(ds->maskedtexturecol); CHECK(ds->maskedtextureheight); CHECK(ds->thicksidecol); CHECK(ds->invscale); #undef CHECK } } // // 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 // // note: THIS IS USED ONLY FOR WALLS! static fixed_t R_ScaleFromGlobalAngle(angle_t visangle) { angle_t anglea = ANGLE_90 + (visangle-viewangle); angle_t angleb = ANGLE_90 + (visangle-rw_normalangle); fixed_t den = FixedMul(rw_distance, FINESINE(anglea>>ANGLETOFINESHIFT)); // proff 11/06/98: Changed for high-res fixed_t num = FixedMul(projectiony, FINESINE(angleb>>ANGLETOFINESHIFT)); if (den > num>>16) { num = FixedDiv(num, den); if (num > 64*FRACUNIT) return 64*FRACUNIT; if (num < 256) return 256; return num; } return 64*FRACUNIT; } // // R_StoreWallRange // A wall segment will be drawn // between start and stop pixels (inclusive). // void R_StoreWallRange(INT32 start, INT32 stop) { fixed_t hyp; fixed_t sineval; angle_t distangle, offsetangle; boolean longboi; INT32 lightnum; INT32 i, p; lightlist_t *light; r_lightlist_t *rlight; INT32 range; vertex_t segleft, segright; fixed_t ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide; static size_t maxdrawsegs = 0; maskedtexturecol = NULL; maskedtextureheight = NULL; thicksidecol = NULL; invscale = NULL; //initialize segleft and segright memset(&segleft, 0x00, sizeof(segleft)); memset(&segright, 0x00, sizeof(segright)); colfunc = colfuncs[BASEDRAWFUNC]; if (ds_p == drawsegs+maxdrawsegs) { size_t curpos = curdrawsegs - drawsegs; size_t pos = ds_p - drawsegs; size_t newmax = maxdrawsegs ? maxdrawsegs*2 : 128; if (firstseg) firstseg = (drawseg_t *)(firstseg - drawsegs); drawsegs = Z_Realloc(drawsegs, newmax*sizeof (*drawsegs), PU_STATIC, NULL); ds_p = drawsegs + pos; maxdrawsegs = newmax; curdrawsegs = drawsegs + curpos; if (firstseg) firstseg = drawsegs + (size_t)firstseg; } sidedef = curline->sidedef; linedef = curline->linedef; // calculate rw_distance for scale calculation rw_normalangle = curline->angle + ANGLE_90; offsetangle = abs((INT32)(rw_normalangle-rw_angle1)); if (offsetangle > ANGLE_90) offsetangle = ANGLE_90; distangle = ANGLE_90 - offsetangle; sineval = FINESINE(distangle>>ANGLETOFINESHIFT); hyp = R_PointToDist(curline->v1->x, curline->v1->y); rw_distance = FixedMul(hyp, sineval); longboi = (hyp >= INT32_MAX); // big room fix if (longboi) rw_distance = (fixed_t)R_CalcSegDist(curline,viewx,viewy); 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]); range = stop-start; } else { // UNUSED: try to fix the stretched line bug #if 0 if (rw_distance < FRACUNIT/2) { fixed_t tr_x,tr_y; fixed_t gxt,gyt; CONS_Debug(DBG_RENDER, "TRYING TO FIX THE STRETCHED ETC\n"); tr_x = curline->v1->x - viewx; tr_y = curline->v1->y - viewy; gxt = FixedMul(tr_x, viewcos); gyt = -FixedMul(tr_y, viewsin); ds_p->scale1 = FixedDiv(projection, gxt - gyt); } #endif ds_p->scale2 = ds_p->scale1; range = 1; } ds_p->scalestep = rw_scalestep = (ds_p->scale2 - rw_scale) / (range); // calculate texture boundaries // and decide if floor / ceiling marks are needed // Figure out map coordinates of where start and end are mapping to on seg, so we can clip right for slope bullshit if (frontsector->hasslope || (backsector && backsector->hasslope)) // Commenting this out for FOFslop. -Red { angle_t temp; // left temp = xtoviewangle[start]+viewangle; { // Both lines can be written in slope-intercept form, so figure out line intersection double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... ///TODO: convert to fixed point a1 = FixedToDouble(curline->v2->y-curline->v1->y); b1 = FixedToDouble(curline->v1->x-curline->v2->x); c1 = a1*FixedToDouble(curline->v1->x) + b1*FixedToDouble(curline->v1->y); a2 = -FixedToDouble(FINESINE(temp>>ANGLETOFINESHIFT)); b2 = FixedToDouble(FINECOSINE(temp>>ANGLETOFINESHIFT)); c2 = a2*FixedToDouble(viewx) + b2*FixedToDouble(viewy); det = a1*b2 - a2*b1; ds_p->leftpos.x = segleft.x = DoubleToFixed((b2*c1 - b1*c2)/det); ds_p->leftpos.y = segleft.y = DoubleToFixed((a1*c2 - a2*c1)/det); } // right temp = xtoviewangle[stop]+viewangle; { // Both lines can be written in slope-intercept form, so figure out line intersection double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... ///TODO: convert to fixed point a1 = FixedToDouble(curline->v2->y-curline->v1->y); b1 = FixedToDouble(curline->v1->x-curline->v2->x); c1 = a1*FixedToDouble(curline->v1->x) + b1*FixedToDouble(curline->v1->y); a2 = -FixedToDouble(FINESINE(temp>>ANGLETOFINESHIFT)); b2 = FixedToDouble(FINECOSINE(temp>>ANGLETOFINESHIFT)); c2 = a2*FixedToDouble(viewx) + b2*FixedToDouble(viewy); det = a1*b2 - a2*b1; ds_p->rightpos.x = segright.x = DoubleToFixed((b2*c1 - b1*c2)/det); ds_p->rightpos.y = segright.y = DoubleToFixed((a1*c2 - a2*c1)/det); } } #define SLOPEPARAMS(slope, end1, end2, normalheight) \ end1 = P_GetZAt(slope, segleft.x, segleft.y, normalheight); \ end2 = P_GetZAt(slope, segright.x, segright.y, normalheight); SLOPEPARAMS(frontsector->c_slope, worldtop, worldtopslope, frontsector->ceilingheight) SLOPEPARAMS(frontsector->f_slope, worldbottom, worldbottomslope, frontsector->floorheight) // subtract viewz from these to turn them into // positions relative to the camera's z position worldtop -= viewz; worldtopslope -= viewz; worldbottom -= viewz; worldbottomslope -= viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; ds_p->maskedtexturecol = NULL; ds_p->maskedtextureheight = NULL; ds_p->numthicksides = numthicksides = 0; ds_p->thicksidecol = NULL; ds_p->invscale = NULL; ds_p->tsilheight = 0; texcoltables = false; numbackffloors = 0; for (i = 0; i < MAXFFLOORS; i++) ds_p->thicksides[i] = NULL; if (numffloors) { for (i = 0; i < numffloors; i++) { if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg)) continue; ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft .x, segleft .y, ffloor[i].height) - viewz; ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y, ffloor[i].height) - viewz; } } // Set up texture Y offset slides for sloped walls rw_toptextureslide = rw_midtextureslide = rw_bottomtextureslide = 0; ceilingfrontslide = floorfrontslide = ceilingbackslide = floorbackslide = 0; { angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); if (frontsector->f_slope) floorfrontslide = R_GetSlopeTextureSlide(frontsector->f_slope, lineangle); if (frontsector->c_slope) ceilingfrontslide = R_GetSlopeTextureSlide(frontsector->c_slope, lineangle); if (backsector) { if (backsector->f_slope) floorbackslide = R_GetSlopeTextureSlide(backsector->f_slope, lineangle); if (backsector->c_slope) ceilingbackslide = R_GetSlopeTextureSlide(backsector->c_slope, lineangle); } } rw_midtexturescalex = sidedef->scalex_mid; rw_midtexturescaley = sidedef->scaley_mid; rw_invmidtexturescalex = FixedDiv(FRACUNIT, rw_midtexturescalex); if (!backsector) { midtexture = R_GetTextureNum(sidedef->midtexture); // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; fixed_t rowoffset = sidedef->rowoffset + sidedef->offsety_mid; fixed_t texheight = textureheight[midtexture]; fixed_t scaley = abs(rw_midtexturescaley); if (rw_midtexturescaley > 0) { if (linedef->flags & ML_NOSKEW) { if (linedef->flags & ML_DONTPEGBOTTOM) rw_midtexturemid = FixedMul(frontsector->floorheight - viewz, scaley) + texheight; else rw_midtexturemid = FixedMul(frontsector->ceilingheight - viewz, scaley); } else if (linedef->flags & ML_DONTPEGBOTTOM) { rw_midtexturemid = FixedMul(worldbottom, scaley) + texheight; rw_midtextureslide = FixedMul(floorfrontslide, scaley); } else { // top of texture at top rw_midtexturemid = FixedMul(worldtop, scaley); rw_midtextureslide = FixedMul(ceilingfrontslide, scaley); } } else { // Upside down rowoffset = -rowoffset; if (linedef->flags & ML_NOSKEW) { if (linedef->flags & ML_DONTPEGBOTTOM) rw_midtexturemid = FixedMul(frontsector->floorheight - viewz, scaley); else rw_midtexturemid = FixedMul(frontsector->ceilingheight - viewz, scaley) + texheight; } else if (linedef->flags & ML_DONTPEGBOTTOM) { rw_midtexturemid = FixedMul(worldbottom, scaley); rw_midtextureslide = FixedMul(floorfrontslide, scaley); } else { // top of texture at top rw_midtexturemid = FixedMul(worldtop, scaley) + texheight; rw_midtextureslide = FixedMul(ceilingfrontslide, scaley); } } rw_midtexturemid += rowoffset; ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->tsilheight = INT32_MIN; } else { // two sided line SLOPEPARAMS(backsector->c_slope, worldhigh, worldhighslope, backsector->ceilingheight) SLOPEPARAMS(backsector->f_slope, worldlow, worldlowslope, backsector->floorheight) worldhigh -= viewz; worldhighslope -= viewz; worldlow -= viewz; worldlowslope -= viewz; ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; if (!bothfloorssky) { if (worldbottomslope > worldlowslope || worldbottom > worldlow) { ds_p->silhouette = SIL_BOTTOM; if (P_GetSectorFloorZAt(backsector, viewx, viewy) > viewz) ds_p->bsilheight = INT32_MAX; else ds_p->bsilheight = (frontsector->f_slope ? INT32_MAX : frontsector->floorheight); } else if (P_GetSectorFloorZAt(backsector, viewx, viewy) > viewz) { ds_p->silhouette = SIL_BOTTOM; ds_p->bsilheight = INT32_MAX; // ds_p->sprbottomclip = negonearray; } } if (!bothceilingssky) { if (worldtopslope < worldhighslope || worldtop < worldhigh) { ds_p->silhouette |= SIL_TOP; if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) ds_p->tsilheight = INT32_MIN; else ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight); } else if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT32_MIN; // ds_p->sprtopclip = screenheightarray; } } if (!bothceilingssky && !bothfloorssky) { if (worldhigh <= worldbottom && worldhighslope <= worldbottomslope) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (worldlow >= worldtop && worldlowslope >= worldtopslope) { ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT32_MIN; ds_p->silhouette |= SIL_TOP; } } //SoM: 3/25/2000: This code fixes an automap bug that didn't check // frontsector->ceiling and backsector->floor to see if a door was closed. // Without the following code, sprites get displayed behind closed doors. if (!bothceilingssky && !bothfloorssky) { if (doorclosed || (worldhigh <= worldbottom && worldhighslope <= worldbottomslope)) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (doorclosed || (worldlow >= worldtop && worldlowslope >= worldtopslope)) { // killough 1/17/98, 2/8/98 ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT32_MIN; ds_p->silhouette |= SIL_TOP; } } if (bothfloorssky) { // see double ceiling skies comment // this is the same but for upside down thok barriers where the floor is sky and the ceiling is normal markfloor = false; } else if (worldlow != worldbottom || worldlowslope != worldbottomslope || backsector->f_slope != frontsector->f_slope || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. || backsector->floorxoffset != frontsector->floorxoffset || backsector->flooryoffset != frontsector->flooryoffset || backsector->floorxscale != frontsector->floorxscale || backsector->flooryscale != frontsector->flooryscale || backsector->floorangle != frontsector->floorangle //SoM: 3/22/2000: Prevents bleeding. || (frontsector->heightsec != -1 && frontsector->floorpic != skyflatnum) || backsector->floorlightlevel != frontsector->floorlightlevel || backsector->floorlightabsolute != frontsector->floorlightabsolute || backsector->floorlightsec != frontsector->floorlightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap || !P_CompareSectorPortals(P_SectorGetFloorPortal(frontsector), P_SectorGetFloorPortal(backsector)) || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markfloor = true; } else { // same plane on both sides markfloor = false; } if (bothceilingssky) { // double ceiling skies are special // we don't want to lower the ceiling clipping, (no new plane is drawn anyway) // so we can see the floor of thok barriers always regardless of sector properties markceiling = false; } else if (worldhigh != worldtop || worldhighslope != worldtopslope || backsector->c_slope != frontsector->c_slope || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. || backsector->ceilingxoffset != frontsector->ceilingxoffset || backsector->ceilingyoffset != frontsector->ceilingyoffset || backsector->ceilingxscale != frontsector->ceilingxscale || backsector->ceilingyscale != frontsector->ceilingyscale || backsector->ceilingangle != frontsector->ceilingangle //SoM: 3/22/2000: Prevents bleeding. || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum) || backsector->ceilinglightlevel != frontsector->ceilinglightlevel || backsector->ceilinglightabsolute != frontsector->ceilinglightabsolute || backsector->ceilinglightsec != frontsector->ceilinglightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap || !P_CompareSectorPortals(P_SectorGetCeilingPortal(frontsector), P_SectorGetCeilingPortal(backsector)) || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markceiling = true; } else { // same plane on both sides markceiling = false; } if (!bothceilingssky && !bothfloorssky) { if ((worldhigh <= worldbottom && worldhighslope <= worldbottomslope) || (worldlow >= worldtop && worldlowslope >= worldtopslope)) { // closed door markceiling = markfloor = true; } } fixed_t toprowoffset = sidedef->rowoffset + sidedef->offsety_top; fixed_t botrowoffset = sidedef->rowoffset + sidedef->offsety_bottom; // check TOP TEXTURE if (!bothceilingssky // never draw the top texture if on && (worldhigh < worldtop || worldhighslope < worldtopslope)) { toptexture = R_GetTextureNum(sidedef->toptexture); rw_toptexturescalex = sidedef->scalex_top; rw_toptexturescaley = sidedef->scaley_top; rw_invtoptexturescalex = FixedDiv(FRACUNIT, rw_toptexturescalex); if (rw_toptexturescaley < 0) toprowoffset = -toprowoffset; fixed_t texheight = textureheight[toptexture]; // Ignore slopes for lower/upper textures unless flag is checked if (!(linedef->flags & ML_SKEWTD)) { if (linedef->flags & ML_DONTPEGTOP) rw_toptexturemid = frontsector->ceilingheight - viewz; else rw_toptexturemid = backsector->ceilingheight - viewz; } else if (linedef->flags & ML_DONTPEGTOP) { // top of texture at top rw_toptexturemid = worldtop; rw_toptextureslide = FixedMul(ceilingfrontslide, abs(rw_toptexturescaley)); } else { rw_toptexturemid = worldhigh + texheight; rw_toptextureslide = FixedMul(ceilingbackslide, abs(rw_toptexturescaley)); } rw_toptexturemid = FixedMul(rw_toptexturemid, abs(rw_toptexturescaley)); rw_toptexturemid += toprowoffset; } // check BOTTOM TEXTURE if (!bothfloorssky // never draw the bottom texture if on && (worldlow > worldbottom || worldlowslope > worldbottomslope)) // Only if VISIBLE!!! { // bottom texture bottomtexture = R_GetTextureNum(sidedef->bottomtexture); rw_bottomtexturescalex = sidedef->scalex_bottom; rw_bottomtexturescaley = sidedef->scaley_bottom; rw_invbottomtexturescalex = FixedDiv(FRACUNIT, rw_bottomtexturescalex); if (rw_bottomtexturescaley < 0) botrowoffset = -botrowoffset; // Ignore slopes for lower/upper textures unless flag is checked if (!(linedef->flags & ML_SKEWTD)) { if (linedef->flags & ML_DONTPEGBOTTOM) rw_bottomtexturemid = frontsector->floorheight - viewz; else rw_bottomtexturemid = backsector->floorheight - viewz; } else if (linedef->flags & ML_DONTPEGBOTTOM) { // bottom of texture at bottom // top of texture at top rw_bottomtexturemid = worldbottom; rw_bottomtextureslide = FixedMul(floorfrontslide, abs(rw_bottomtexturescaley)); } else { // top of texture at top rw_bottomtexturemid = worldlow; rw_bottomtextureslide = FixedMul(floorbackslide, abs(rw_bottomtexturescaley)); } rw_bottomtexturemid = FixedMul(rw_bottomtexturemid, abs(rw_bottomtexturescaley)); rw_bottomtexturemid += botrowoffset; } // allocate space for masked texture tables R_AllocTextureColumnTables(rw_stopx - start); texcoltables = true; if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) { ffloor_t *rover; ffloor_t *r2; fixed_t lowcut, highcut; fixed_t lowcutslope, highcutslope; // Used for height comparisons and etc across FOFs and slopes fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2; maskedtexture = true; ds_p->thicksidecol = thicksidecol = curtexturecolumntable - rw_x; curtexturecolumntable += rw_stopx - rw_x; lowcut = max(worldbottom, worldlow) + viewz; highcut = min(worldtop, worldhigh) + viewz; lowcutslope = max(worldbottomslope, worldlowslope) + viewz; highcutslope = min(worldtopslope, worldhighslope) + viewz; if (frontsector->ffloors && backsector->ffloors) { i = 0; for (rover = backsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->fofflags & FOF_RENDERSIDES) || !(rover->fofflags & FOF_EXISTS)) continue; if (!(rover->fofflags & FOF_ALLSIDES) && rover->fofflags & FOF_INVERTSIDES) continue; if (rover->norender == leveltime) continue; SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) continue; for (r2 = frontsector->ffloors; r2; r2 = r2->next) { if (r2->master == rover->master) // Skip if same control line. break; if (!(r2->fofflags & FOF_EXISTS) || !(r2->fofflags & FOF_RENDERSIDES)) continue; if (r2->norender == leveltime) continue; if (rover->fofflags & FOF_EXTRA) { if (!(r2->fofflags & FOF_CUTEXTRA)) continue; if (r2->fofflags & FOF_EXTRA && (r2->fofflags & (FOF_TRANSLUCENT|FOF_FOG)) != (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG))) continue; } else { if (!(r2->fofflags & FOF_CUTSOLIDS)) continue; } SLOPEPARAMS(*r2->t_slope, high2, highslope2, *r2->topheight) SLOPEPARAMS(*r2->b_slope, low2, lowslope2, *r2->bottomheight) if ((high2 < lowcut || highslope2 < lowcutslope) || (low2 > highcut || lowslope2 > highcutslope)) continue; if ((high1 > high2 || highslope1 > highslope2) || (low1 < low2 || lowslope1 < lowslope2)) continue; break; } if (r2) continue; ds_p->thicksides[i] = rover; i++; } for (rover = frontsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->fofflags & FOF_RENDERSIDES) || !(rover->fofflags & FOF_EXISTS)) continue; if (!(rover->fofflags & FOF_ALLSIDES || rover->fofflags & FOF_INVERTSIDES)) continue; if (rover->norender == leveltime) continue; SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) continue; for (r2 = backsector->ffloors; r2; r2 = r2->next) { if (r2->master == rover->master) // Skip if same control line. break; if (!(r2->fofflags & FOF_EXISTS) || !(r2->fofflags & FOF_RENDERSIDES)) continue; if (r2->norender == leveltime) continue; if (rover->fofflags & FOF_EXTRA) { if (!(r2->fofflags & FOF_CUTEXTRA)) continue; if (r2->fofflags & FOF_EXTRA && (r2->fofflags & (FOF_TRANSLUCENT|FOF_FOG)) != (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG))) continue; } else { if (!(r2->fofflags & FOF_CUTSOLIDS)) continue; } SLOPEPARAMS(*r2->t_slope, high2, highslope2, *r2->topheight) SLOPEPARAMS(*r2->b_slope, low2, lowslope2, *r2->bottomheight) #undef SLOPEPARAMS if ((high2 < lowcut || highslope2 < lowcutslope) || (low2 > highcut || lowslope2 > highcutslope)) continue; if ((high1 > high2 || highslope1 > highslope2) || (low1 < low2 || lowslope1 < lowslope2)) continue; break; } if (r2) continue; ds_p->thicksides[i] = rover; i++; } } else if (backsector->ffloors) { for (rover = backsector->ffloors, i = 0; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->fofflags & FOF_RENDERSIDES) || !(rover->fofflags & FOF_EXISTS)) continue; if (!(rover->fofflags & FOF_ALLSIDES) && rover->fofflags & FOF_INVERTSIDES) continue; if (rover->norender == leveltime) continue; // Oy vey. if ( ((P_GetFFloorTopZAt (rover, segleft .x, segleft .y)) <= worldbottom + viewz && (P_GetFFloorTopZAt (rover, segright.x, segright.y)) <= worldbottomslope + viewz) ||((P_GetFFloorBottomZAt(rover, segleft .x, segleft .y)) >= worldtop + viewz && (P_GetFFloorBottomZAt(rover, segright.x, segright.y)) >= worldtopslope + viewz)) continue; ds_p->thicksides[i] = rover; i++; } } else if (frontsector->ffloors) { for (rover = frontsector->ffloors, i = 0; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->fofflags & FOF_RENDERSIDES) || !(rover->fofflags & FOF_EXISTS)) continue; if (!(rover->fofflags & FOF_ALLSIDES || rover->fofflags & FOF_INVERTSIDES)) continue; if (rover->norender == leveltime) continue; // Oy vey. if ( (P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= worldbottom + viewz && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= worldbottomslope + viewz) ||(P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) >= worldtop + viewz && P_GetFFloorBottomZAt(rover, segright.x, segright.y) >= worldtopslope + viewz)) continue; if ( (P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= worldlow + viewz && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= worldlowslope + viewz) ||(P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) >= worldhigh + viewz && P_GetFFloorBottomZAt(rover, segright.x, segright.y) >= worldhighslope + viewz)) continue; ds_p->thicksides[i] = rover; i++; } } ds_p->numthicksides = numthicksides = i; } // masked midtexture if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) { ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x; curtexturecolumntable += rw_stopx - rw_x; ds_p->maskedtextureheight = maskedtextureheight = curtexturecolumntable - rw_x; curtexturecolumntable += rw_stopx - rw_x; maskedtexture = true; if (curline->polyseg) { // use REAL front and back floors please, so midtexture rendering isn't mucked up rw_midtextureslide = rw_midtexturebackslide = 0; if (linedef->flags & ML_MIDPEG) rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; else rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz; } else { // Set midtexture starting height if (linedef->flags & ML_NOSKEW) { // Ignore slopes when texturing rw_midtextureslide = rw_midtexturebackslide = 0; if (linedef->flags & ML_MIDPEG) rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; else rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; } else if (linedef->flags & ML_MIDPEG) { rw_midtexturemid = worldbottom; rw_midtextureslide = floorfrontslide; rw_midtextureback = worldlow; rw_midtexturebackslide = floorbackslide; } else { rw_midtexturemid = worldtop; rw_midtextureslide = ceilingfrontslide; rw_midtextureback = worldhigh; rw_midtexturebackslide = ceilingbackslide; } } rw_midtexturemid = FixedMul(rw_midtexturemid, abs(rw_midtexturescaley)); rw_midtextureback = FixedMul(rw_midtextureback, abs(rw_midtexturescaley)); rw_midtextureslide = FixedMul(rw_midtextureslide, abs(rw_midtexturescaley)); rw_midtexturebackslide = FixedMul(rw_midtexturebackslide, abs(rw_midtexturescaley)); rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid; rw_midtextureback += sidedef->rowoffset + sidedef->offsety_mid; } } // calculate rw_offset (only needed for textured lines) segtextured = midtexture || toptexture || bottomtexture || maskedtexture || (numthicksides > 0); if (segtextured) { fixed_t sideoffset = sidedef->textureoffset; offsetangle = rw_normalangle-rw_angle1; if (offsetangle > ANGLE_180) offsetangle = -(signed)offsetangle; if (offsetangle > ANGLE_90) offsetangle = ANGLE_90; sineval = FINESINE(offsetangle>>ANGLETOFINESHIFT); rw_offset = FixedMul(hyp, sineval); // big room fix if (longboi) { INT64 dx = (curline->v2->x)-(curline->v1->x); INT64 dy = (curline->v2->y)-(curline->v1->y); INT64 vdx = viewx-(curline->v1->x); INT64 vdy = viewy-(curline->v1->y); rw_offset = ((dx*vdx-dy*vdy))/(curline->length); } if (rw_normalangle-rw_angle1 < ANGLE_180) rw_offset = -rw_offset; rw_offset += curline->offset; rw_centerangle = ANGLE_90 + viewangle - rw_normalangle; rw_offset_top = sideoffset + sidedef->offsetx_top; rw_offset_mid = sideoffset + sidedef->offsetx_mid; rw_offset_bottom = sideoffset + sidedef->offsetx_bottom; rw_offsetx = rw_offset_mid; if (rw_midtexturescalex < 0) rw_offsetx = -rw_offsetx; if (numthicksides) ds_p->offsetx = rw_offsetx; // calculate light table // use different light tables // for horizontal / vertical / diagonal // OPTIMIZE: get rid of LIGHTSEGSHIFT globally lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight[0]; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS - 1]; else walllights = scalelight[lightnum]; } if (maskedtexture) { ds_p->invscale = invscale = curtexturecolumntable - rw_x; curtexturecolumntable += rw_stopx - rw_x; } // 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->heightsec == -1) { if (frontsector->floorpic != skyflatnum && P_GetSectorFloorZAt(frontsector, viewx, viewy) >= viewz) { // above view plane markfloor = false; } if (frontsector->ceilingpic != skyflatnum && P_GetSectorCeilingZAt(frontsector, viewx, viewy) <= viewz) { // below view plane markceiling = false; } } // calculate incremental stepping values for texture edges worldtop >>= 4; worldbottom >>= 4; worldtopslope >>= 4; worldbottomslope >>= 4; if (horizonline) { // HORIZON LINES topstep = bottomstep = 0; topfrac = bottomfrac = (centeryfrac>>4); topfrac++; // Prevent 1px HOM } else { 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 (frontsector->c_slope) { fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); topstep = (topfracend-topfrac)/(range); } if (frontsector->f_slope) { fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); bottomstep = (bottomfracend-bottomfrac)/(range); } } dc_numlights = 0; if (frontsector->numlights) { dc_numlights = frontsector->numlights; if (dc_numlights > dc_maxlights) { dc_maxlights = dc_numlights; dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL); } for (i = p = 0; i < dc_numlights; i++) { fixed_t leftheight, rightheight; light = &frontsector->lightlist[i]; rlight = &dc_lightlist[p]; leftheight = P_GetLightZAt(light, segleft.x, segleft.y); rightheight = P_GetLightZAt(light, segright.x, segright.y); if (light->slope) // Flag sector as having slopes frontsector->hasslope = true; leftheight -= viewz; rightheight -= viewz; leftheight >>= 4; rightheight >>= 4; if (i != 0) { if (leftheight < worldbottom && rightheight < worldbottomslope) continue; if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) continue; } rlight->height = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); rlight->heightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); rlight->heightstep = (rlight->heightstep-rlight->height)/(range); rlight->flags = light->flags; if (light->caster && light->caster->fofflags & FOF_CUTSOLIDS) { leftheight = P_GetFFloorBottomZAt(light->caster, segleft.x, segleft.y); rightheight = P_GetFFloorBottomZAt(light->caster, segright.x, segright.y); if (*light->caster->b_slope) // Flag sector as having slopes frontsector->hasslope = true; leftheight -= viewz; rightheight -= viewz; leftheight >>= 4; rightheight >>= 4; rlight->botheight = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); rlight->botheightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range); } rlight->lightlevel = *light->lightlevel; rlight->extra_colormap = *light->extra_colormap; p++; } dc_numlights = p; } if (numffloors) { for (i = 0; i < numffloors; i++) { ffloor[i].f_pos >>= 4; ffloor[i].f_pos_slope >>= 4; if (horizonline) // Horizon lines extend FOFs in contact with them too. { ffloor[i].f_step = 0; ffloor[i].f_frac = (centeryfrac>>4); topfrac++; // Prevent 1px HOM } else { ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range); } } } if (backsector) { worldhigh >>= 4; worldlow >>= 4; worldhighslope >>= 4; worldlowslope >>= 4; if (toptexture) { pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = -FixedMul (rw_scalestep,worldhigh); if (backsector->c_slope) { fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2); pixhighstep = (topfracend-pixhigh)/(range); } } if (bottomtexture) { pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); pixlowstep = -FixedMul (rw_scalestep,worldlow); if (backsector->f_slope) { fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2); pixlowstep = (bottomfracend-pixlow)/(range); } } { ffloor_t * rover; fixed_t roverleft, roverright; fixed_t planevistest; i = 0; if (backsector->ffloors) { for (rover = backsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES)) continue; if (rover->norender == leveltime) continue; // Let the renderer know this sector is sloped. if (*rover->b_slope || *rover->t_slope) backsector->hasslope = true; roverleft = P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) - viewz; roverright = P_GetFFloorBottomZAt(rover, segright.x, segright.y) - viewz; planevistest = P_GetFFloorBottomZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && ((viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || (viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) { //ffloor[i].slope = *rover->b_slope; ffloor[i].b_pos = roverleft; ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos >>= 4; ffloor[i].b_pos_slope >>= 4; ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); i++; } if (i >= MAXFFLOORS) break; roverleft = P_GetFFloorTopZAt(rover, segleft .x, segleft .y) - viewz; roverright = P_GetFFloorTopZAt(rover, segright.x, segright.y) - viewz; planevistest = P_GetFFloorTopZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && ((viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || (viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) { //ffloor[i].slope = *rover->t_slope; ffloor[i].b_pos = roverleft; ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos >>= 4; ffloor[i].b_pos_slope >>= 4; ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); i++; } } } else if (frontsector && frontsector->ffloors) { for (rover = frontsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES)) continue; if (rover->norender == leveltime) continue; // Let the renderer know this sector is sloped. if (*rover->b_slope || *rover->t_slope) frontsector->hasslope = true; roverleft = P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) - viewz; roverright = P_GetFFloorBottomZAt(rover, segright.x, segright.y) - viewz; planevistest = P_GetFFloorBottomZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && ((viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || (viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) { //ffloor[i].slope = *rover->b_slope; ffloor[i].b_pos = roverleft; ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos >>= 4; ffloor[i].b_pos_slope >>= 4; ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); i++; } if (i >= MAXFFLOORS) break; roverleft = P_GetFFloorTopZAt(rover, segleft .x, segleft .y) - viewz; roverright = P_GetFFloorTopZAt(rover, segright.x, segright.y) - viewz; planevistest = P_GetFFloorTopZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && ((viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || (viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) { //ffloor[i].slope = *rover->t_slope; ffloor[i].b_pos = roverleft; ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos >>= 4; ffloor[i].b_pos_slope >>= 4; ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); i++; } } } if (curline->polyseg && frontsector && (curline->polyseg->flags & POF_RENDERPLANES)) { while (i < numffloors && ffloor[i].polyobj != curline->polyseg) i++; if (i < numffloors && backsector->floorheight <= frontsector->ceilingheight && backsector->floorheight >= frontsector->floorheight && (viewz < backsector->floorheight)) { if (ffloor[i].plane->minx > ds_p->x1) ffloor[i].plane->minx = ds_p->x1; if (ffloor[i].plane->maxx < ds_p->x2) ffloor[i].plane->maxx = ds_p->x2; ffloor[i].slope = NULL; ffloor[i].b_pos = backsector->floorheight; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); i++; } if (i < numffloors && backsector->ceilingheight >= frontsector->floorheight && backsector->ceilingheight <= frontsector->ceilingheight && (viewz > backsector->ceilingheight)) { if (ffloor[i].plane->minx > ds_p->x1) ffloor[i].plane->minx = ds_p->x1; if (ffloor[i].plane->maxx < ds_p->x2) ffloor[i].plane->maxx = ds_p->x2; ffloor[i].slope = NULL; ffloor[i].b_pos = backsector->ceilingheight; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); i++; } } numbackffloors = i; } } // get a new or use the same visplane if (markceiling) { if (ceilingplane) //SoM: 3/29/2000: Check for null ceiling planes ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); else markceiling = false; // Don't mark ceiling flat lines for polys unless this line has an upper texture, otherwise we get flat leakage pulling downward // (If it DOES have an upper texture and we do this, the ceiling won't render at all) if (curline->polyseg && !curline->sidedef->toptexture) markceiling = false; } // get a new or use the same visplane if (markfloor) { if (floorplane) //SoM: 3/29/2000: Check for null planes floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); else markfloor = false; // Don't mark floor flat lines for polys unless this line has a lower texture, otherwise we get flat leakage pulling upward // (If it DOES have a lower texture and we do this, the floor won't render at all) if (curline->polyseg && !curline->sidedef->bottomtexture) markfloor = false; } ds_p->numffloorplanes = 0; if (numffloors) { if (!firstseg) { ds_p->numffloorplanes = numffloors; for (i = 0; i < numffloors; i++) { ds_p->ffloorplanes[i] = ffloor[i].plane = R_CheckPlane(ffloor[i].plane, rw_x, rw_stopx - 1); } firstseg = ds_p; } else { for (i = 0; i < numffloors; i++) R_ExpandPlane(ffloor[i].plane, rw_x, rw_stopx - 1); } // FIXME hack to fix planes disappearing when a seg goes behind the camera. This NEEDS to be changed to be done properly. -Red if (curline->polyseg) { for (i = 0; i < numffloors; i++) { if (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg) continue; if (ffloor[i].plane->minx > rw_x) ffloor[i].plane->minx = rw_x; if (ffloor[i].plane->maxx < rw_stopx - 1) ffloor[i].plane->maxx = rw_stopx - 1; } } } rw_silhouette = &(ds_p->silhouette); rw_tsilheight = &(ds_p->tsilheight); rw_bsilheight = &(ds_p->bsilheight); R_RenderSegLoop(); colfunc = colfuncs[BASEDRAWFUNC]; if (portalline) // if curline is a portal, set portalrender for drawseg ds_p->portalpass = portalrender+1; else ds_p->portalpass = 0; // save sprite clipping info if (maskedtexture || (ds_p->silhouette & (SIL_TOP | SIL_BOTTOM))) { R_AllocClippingTables(rw_stopx - start); if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { M_Memcpy(lastopening, ceilingclip + start, 2*(rw_stopx - start)); ds_p->sprtopclip = lastopening - start; lastopening += rw_stopx - start; } if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) { M_Memcpy(lastopening, floorclip + start, 2*(rw_stopx - start)); ds_p->sprbottomclip = lastopening - start; lastopening += rw_stopx - start; } } if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) { ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN : INT32_MAX; } if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX : INT32_MIN; } ds_p++; }