SRB2/src/r_segs.c

3228 lines
97 KiB
C

// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2019 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 "r_splats.h"
#include "w_wad.h"
#include "z_zone.h"
#include "d_netcmd.h"
#include "m_misc.h"
#include "p_local.h" // Camera...
#include "p_slopes.h"
#include "console.h" // con_clipviewtop
// 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;
static fixed_t rw_offset2; // for splats
static fixed_t rw_scale, rw_scalestep;
static fixed_t rw_midtexturemid, rw_toptexturemid, rw_bottomtexturemid;
static INT32 worldtop, worldbottom, worldhigh, worldlow;
#ifdef ESLOPE
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
#endif
static fixed_t pixhigh, pixlow, pixhighstep, pixlowstep;
static fixed_t topfrac, topstep;
static fixed_t bottomfrac, bottomstep;
static lighttable_t **walllights;
static INT16 *maskedtexturecol;
#ifdef ESLOPE
static fixed_t *maskedtextureheight = NULL;
#endif
// ==========================================================================
// R_Splats Wall Splats Drawer
// ==========================================================================
#ifdef WALLSPLATS
static INT16 last_ceilingclip[MAXVIDWIDTH];
static INT16 last_floorclip[MAXVIDWIDTH];
static void R_DrawSplatColumn(column_t *column)
{
INT32 topscreen, bottomscreen;
fixed_t basetexturemid;
INT32 topdelta, prevdelta = -1;
basetexturemid = dc_texturemid;
for (; column->topdelta != 0xff ;)
{
// calculate unclipped screen coordinates for post
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
topscreen = sprtopscreen + spryscale*topdelta;
bottomscreen = topscreen + spryscale*column->length;
dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS;
if (dc_yh >= last_floorclip[dc_x])
dc_yh = last_floorclip[dc_x] - 1;
if (dc_yl <= last_ceilingclip[dc_x])
dc_yl = last_ceilingclip[dc_x] + 1;
if (dc_yl <= dc_yh && dl_yh < vid.height && yh > 0)
{
dc_source = (UINT8 *)column + 3;
dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
// Drawn by R_DrawColumn.
colfunc();
}
column = (column_t *)((UINT8 *)column + column->length + 4);
}
dc_texturemid = basetexturemid;
}
static void R_DrawWallSplats(void)
{
wallsplat_t *splat;
seg_t *seg;
angle_t angle, angle1, angle2;
INT32 x1, x2;
size_t pindex;
column_t *col;
patch_t *patch;
fixed_t texturecolumn;
splat = (wallsplat_t *)linedef->splats;
I_Assert(splat != NULL);
seg = ds_p->curline;
// draw all splats from the line that touches the range of the seg
for (; splat; splat = splat->next)
{
angle1 = R_PointToAngle(splat->v1.x, splat->v1.y);
angle2 = R_PointToAngle(splat->v2.x, splat->v2.y);
angle1 = (angle1 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT;
angle2 = (angle2 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT;
// out of the viewangletox lut
/// \todo clip it to the screen
if (angle1 > FINEANGLES/2 || angle2 > FINEANGLES/2)
continue;
x1 = viewangletox[angle1];
x2 = viewangletox[angle2];
if (x1 >= x2)
continue; // does not cross a pixel
// splat is not in this seg range
if (x2 < ds_p->x1 || x1 > ds_p->x2)
continue;
if (x1 < ds_p->x1)
x1 = ds_p->x1;
if (x2 > ds_p->x2)
x2 = ds_p->x2;
if (x2 <= x1)
continue;
// calculate incremental stepping values for texture edges
rw_scalestep = ds_p->scalestep;
spryscale = ds_p->scale1 + (x1 - ds_p->x1)*rw_scalestep;
mfloorclip = floorclip;
mceilingclip = ceilingclip;
patch = W_CachePatchNum(splat->patch, PU_CACHE);
dc_texturemid = splat->top + (SHORT(patch->height)<<(FRACBITS-1)) - viewz;
if (splat->yoffset)
dc_texturemid += *splat->yoffset;
sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
// set drawing mode
switch (splat->flags & SPLATDRAWMODE_MASK)
{
case SPLATDRAWMODE_OPAQUE:
colfunc = colfuncs[BASEDRAWFUNC];
break;
case SPLATDRAWMODE_TRANS:
if (!cv_translucency.value)
colfunc = colfuncs[BASEDRAWFUNC];
else
{
dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
}
break;
case SPLATDRAWMODE_SHADE:
colfunc = colfuncs[COLDRAWFUNC_SHADE];
break;
}
dc_texheight = 0;
// draw the columns
for (dc_x = x1; dc_x <= x2; dc_x++, spryscale += rw_scalestep)
{
pindex = FixedMul(spryscale, FixedDiv(640, vid.width))>>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 = 0xffffffffu / (unsigned)spryscale;
// find column of patch, from perspective
angle = (rw_centerangle + xtoviewangle[dc_x])>>ANGLETOFINESHIFT;
texturecolumn = rw_offset2 - splat->offset
- FixedMul(FINETANGENT(angle), rw_distance);
// FIXME!
texturecolumn >>= FRACBITS;
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
continue;
// draw the texture
col = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
R_DrawSplatColumn(col);
}
} // next splat
colfunc = colfuncs[BASEDRAWFUNC];
}
#endif //WALLSPLATS
// ==========================================================================
// R_RenderMaskedSegRange
// ==========================================================================
// If we have a multi-patch texture on a 2sided wall (rare) then we draw
// it using R_DrawColumn, else we draw it using R_DrawMaskedColumn, this
// way we don't have to store extra post_t info with each column for
// multi-patch textures. They are not normally needed as multi-patch
// textures don't have holes in it. At least not for now.
static INT32 column2s_length; // column->length : for multi-patch on 2sided wall = texture->height
static void R_Render2sidedMultiPatchColumn(column_t *column)
{
INT32 topscreen, bottomscreen;
topscreen = sprtopscreen; // + spryscale*column->topdelta; topdelta is 0 for the wall
bottomscreen = topscreen + spryscale * column2s_length;
dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS;
if (windowtop != INT32_MAX && windowbottom != INT32_MAX)
{
dc_yl = ((windowtop + FRACUNIT)>>FRACBITS);
dc_yh = (windowbottom - 1)>>FRACBITS;
}
if (dc_yh >= mfloorclip[dc_x])
dc_yh = mfloorclip[dc_x] - 1;
if (dc_yl <= mceilingclip[dc_x])
dc_yl = mceilingclip[dc_x] + 1;
if (dc_yl >= vid.height || dc_yh < 0)
return;
if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0)
{
dc_source = (UINT8 *)column + 3;
if (colfunc == colfuncs[BASEDRAWFUNC])
(colfuncs[COLDRAWFUNC_TWOSMULTIPATCH])();
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
(colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS])();
else
colfunc();
}
}
// quick wrapper for R_DrawFlippedMaskedColumn so it can be set as a colfunc_2s value
// uses column2s_length for texture->height as above
static void R_DrawFlippedMaskedSegColumn(column_t *column)
{
R_DrawFlippedMaskedColumn(column, column2s_length);
}
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 *);
line_t *ldef;
sector_t *front, *back;
INT32 times, repeats;
INT64 overflow_test;
#ifdef ESLOPE
INT32 range;
#endif
// Calculate light table.
// Use different light tables
// for horizontal / vertical / diagonal. Diagonal?
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
curline = ds->curline;
if (curline->glseg)
return;
frontsector = curline->frontsector;
backsector = curline->backsector;
texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX;
// hack translucent linedef types (900-909 for transtables 1-9)
ldef = curline->linedef;
switch (ldef->special)
{
case 900:
case 901:
case 902:
case 903:
case 904:
case 905:
case 906:
case 907:
case 908:
dc_transmap = transtables + ((ldef->special-900)<<FF_TRANSSHIFT);
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
break;
case 909:
colfunc = colfuncs[COLDRAWFUNC_FOG];
windowtop = frontsector->ceilingheight;
windowbottom = frontsector->floorheight;
break;
default:
colfunc = colfuncs[BASEDRAWFUNC];
break;
}
if (curline->polyseg && curline->polyseg->translucency > 0)
{
if (curline->polyseg->translucency >= NUMTRANSMAPS)
return;
dc_transmap = transtables + ((curline->polyseg->translucency-1)<<FF_TRANSSHIFT);
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
}
#ifdef ESLOPE
range = max(ds->x2-ds->x1, 1);
#endif
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes)
{
if (textures[texnum]->flip & 2) // vertically flipped?
{
colfunc_2s = R_DrawFlippedMaskedSegColumn;
column2s_length = textures[texnum]->height;
}
else
colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
}
else
{
colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info)
column2s_length = 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++)
{
#ifdef ESLOPE
fixed_t leftheight, rightheight;
#endif
light = &frontsector->lightlist[i];
rlight = &dc_lightlist[i];
#ifdef ESLOPE
if (light->slope) {
leftheight = P_GetZAt(light->slope, ds->leftpos.x, ds->leftpos.y);
rightheight = P_GetZAt(light->slope, ds->rightpos.x, ds->rightpos.y);
} else
leftheight = rightheight = light->height;
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;
#else
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
#endif
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 (rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->fog))
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
lightnum = LIGHTLEVELS - 1;
else
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
if (rlight->extra_colormap && rlight->extra_colormap->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])
{
if (frontsector->extra_colormap && frontsector->extra_colormap->fog)
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
else
lightnum = LIGHTLEVELS - 1;
}
else
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
if (colfunc == colfuncs[COLDRAWFUNC_FOG]
|| (frontsector->extra_colormap && frontsector->extra_colormap->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 = &sectors[frontsector->heightsec];
else
front = frontsector;
if (backsector->heightsec != -1)
back = &sectors[backsector->heightsec];
else
back = backsector;
if (ds->curline->sidedef->repeatcnt)
repeats = 1 + ds->curline->sidedef->repeatcnt;
else if (ldef->flags & ML_EFFECT5)
{
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 = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
if (dc_numlights)
{ // reset all lights to their starting heights
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height = rlight->startheight;
}
}
}
#ifndef ESLOPE
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
dc_texturemid = front->floorheight > back->floorheight
? front->floorheight : back->floorheight;
dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
}
else
{
dc_texturemid = front->ceilingheight < back->ceilingheight
? front->ceilingheight : back->ceilingheight;
dc_texturemid = dc_texturemid - viewz;
}
dc_texturemid += curline->sidedef->rowoffset;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
dc_texturemid += (textureheight[texnum])*times;
else
dc_texturemid -= (textureheight[texnum])*times;
#endif
dc_texheight = textureheight[texnum]>>FRACBITS;
// draw the columns
for (dc_x = x1; dc_x <= x2; dc_x++)
{
#ifdef ESLOPE
dc_texturemid = ds->maskedtextureheight[dc_x];
if (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3))
dc_texturemid += (textureheight[texnum])*times + textureheight[texnum];
else
dc_texturemid -= (textureheight[texnum])*times;
#endif
// calculate lighting
if (maskedtexturecol[dc_x] != INT16_MAX)
{
// 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;
}
if (dc_numlights)
{
lighttable_t **xwalllights;
sprbotscreen = INT32_MAX;
sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale));
realbot = windowbottom = FixedMul(textureheight[texnum], spryscale) + sprtopscreen;
dc_iscale = 0xffffffffu / (unsigned)spryscale;
// draw the texture
col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3);
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
if ((rlight->flags & FF_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, FixedDiv(640, vid.width))>>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);
for (i++; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height += rlight->heightstep;
}
continue;
}
colfunc_2s(col);
windowtop = windowbottom + 1;
dc_colormap = rlight->rcolormap;
}
windowbottom = realbot;
if (windowtop < windowbottom)
colfunc_2s(col);
spryscale += rw_scalestep;
continue;
}
// calculate lighting
pindex = FixedMul(spryscale, FixedDiv(640, vid.width))>>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 = 0xffffffffu / (unsigned)spryscale;
// draw the texture
col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3);
//#ifdef POLYOBJECTS_PLANES
#if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red
if (curline->dontrenderme && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES))
{
fixed_t my_topscreen;
fixed_t my_bottomscreen;
fixed_t my_yl, my_yh;
my_topscreen = sprtopscreen + spryscale*col->topdelta;
my_bottomscreen = sprbotscreen == INT32_MAX ? my_topscreen + spryscale*col->length
: sprbotscreen + spryscale*col->length;
my_yl = (my_topscreen+FRACUNIT-1)>>FRACBITS;
my_yh = (my_bottomscreen-1)>>FRACBITS;
// CONS_Debug(DBG_RENDER, "my_topscreen: %d\nmy_bottomscreen: %d\nmy_yl: %d\nmy_yh: %d\n", my_topscreen, my_bottomscreen, my_yl, my_yh);
if (numffloors)
{
INT32 top = my_yl;
INT32 bottom = my_yh;
for (i = 0; i < numffloors; i++)
{
if (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg)
continue;
if (ffloor[i].height < viewz)
{
INT32 top_w = ffloor[i].plane->top[dc_x];
// CONS_Debug(DBG_RENDER, "Leveltime : %d\n", leveltime);
// CONS_Debug(DBG_RENDER, "Top is %d, top_w is %d\n", top, top_w);
if (top_w < top)
{
ffloor[i].plane->top[dc_x] = (INT16)top;
ffloor[i].plane->picnum = 0;
}
// CONS_Debug(DBG_RENDER, "top_w is now %d\n", ffloor[i].plane->top[dc_x]);
}
else if (ffloor[i].height > viewz)
{
INT32 bottom_w = ffloor[i].plane->bottom[dc_x];
if (bottom_w > bottom)
{
ffloor[i].plane->bottom[dc_x] = (INT16)bottom;
ffloor[i].plane->picnum = 0;
}
}
}
}
}
else
#endif
colfunc_2s(col);
}
spryscale += rw_scalestep;
}
}
colfunc = colfuncs[BASEDRAWFUNC];
}
// Loop through R_DrawMaskedColumn calls
static void R_DrawRepeatMaskedColumn(column_t *col)
{
while (sprtopscreen < sprbotscreen) {
R_DrawMaskedColumn(col);
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)
{
do {
R_DrawFlippedMaskedColumn(col, column2s_length);
sprtopscreen += dc_texheight*spryscale;
} while (sprtopscreen < sprbotscreen);
}
//
// R_RenderThickSideRange
// Renders all the thick sides in the given range.
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 bottombounds = viewheight << FRACBITS;
fixed_t topbounds = (con_clipviewtop - 1) << FRACBITS;
fixed_t offsetvalue = 0;
lightlist_t *light;
r_lightlist_t *rlight;
#ifdef ESLOPE
INT32 range;
#endif
#ifndef ESLOPE
fixed_t lheight;
#endif
line_t *newline = NULL;
#ifdef ESLOPE
// 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?
boolean slopeskew = false;
fixed_t ffloortextureslide = 0;
INT32 oldx = -1;
fixed_t left_top, left_bottom; // needed here for slope skewing
pslope_t *skewslope = NULL;
#endif
void (*colfunc_2s) (column_t *);
// 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;
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
colfunc = colfuncs[BASEDRAWFUNC];
if (pfloor->master->flags & ML_TFERLINE)
{
size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum;
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
if (pfloor->flags & FF_TRANSLUCENT)
{
boolean fuzzy = true;
// Hacked up support for alpha value in software mode Tails 09-24-2002
if (pfloor->alpha < 12)
return; // Don't even draw it
else if (pfloor->alpha < 38)
dc_transmap = transtables + ((tr_trans90-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 64)
dc_transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 89)
dc_transmap = transtables + ((tr_trans70-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 115)
dc_transmap = transtables + ((tr_trans60-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 140)
dc_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 166)
dc_transmap = transtables + ((tr_trans40-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 192)
dc_transmap = transtables + ((tr_trans30-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 217)
dc_transmap = transtables + ((tr_trans20-1)<<FF_TRANSSHIFT);
else if (pfloor->alpha < 243)
dc_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT);
else
fuzzy = false; // Opaque
if (fuzzy)
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
}
else if (pfloor->flags & FF_FOG)
colfunc = colfuncs[COLDRAWFUNC_FOG];
#ifdef ESLOPE
range = max(ds->x2-ds->x1, 1);
#endif
//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++)
{
#ifdef ESLOPE
fixed_t leftheight, rightheight;
fixed_t pfloorleft, pfloorright;
INT64 overflow_test;
#endif
light = &frontsector->lightlist[i];
rlight = &dc_lightlist[p];
#ifdef ESLOPE
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
if (slope) { \
end1 = P_GetZAt(slope, ds->leftpos.x, ds->leftpos.y); \
end2 = P_GetZAt(slope, ds->rightpos.x, ds->rightpos.y); \
} else \
end1 = end2 = 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 ((nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height) > pfloorleft
&& (nextlight->slope ? 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);
#else
if (light->height < *pfloor->bottomheight)
continue;
if (light->height > *pfloor->topheight && i+1 < dc_numlights && frontsector->lightlist[i+1].height > *pfloor->topheight)
continue;
lheight = light->height;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : light->height;
rlight->heightstep = -FixedMul (rw_scalestep, (lheight - viewz));
rlight->height = (centeryfrac) - FixedMul((lheight - viewz), spryscale);
#endif
rlight->flags = light->flags;
if (light->flags & FF_CUTLEVEL)
{
#ifdef ESLOPE
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);
#else
lheight = *light->caster->bottomheight;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : *light->caster->bottomheight;
rlight->botheightstep = -FixedMul (rw_scalestep, (lheight - viewz));
rlight->botheight = (centeryfrac) - FixedMul((lheight - viewz), spryscale);
#endif
}
rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = *light->extra_colormap;
// Check if the current light effects the colormap/lightlevel
if (pfloor->flags & FF_FOG)
rlight->lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
else
rlight->lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
if (pfloor->flags & FF_FOG || rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->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->fog))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
else if (pfloor->flags & FF_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->flags & FF_FOG || (frontsector->extra_colormap && frontsector->extra_colormap->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->thicksidecol;
mfloorclip = ds->sprbottomclip;
mceilingclip = ds->sprtopclip;
dc_texheight = textureheight[texnum]>>FRACBITS;
#ifdef ESLOPE
// calculate both left ends
if (*pfloor->t_slope)
left_top = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) - viewz;
else
left_top = *pfloor->topheight - viewz;
if (*pfloor->b_slope)
left_bottom = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) - viewz;
else
left_bottom = *pfloor->bottomheight - viewz;
skewslope = *pfloor->t_slope; // skew using top slope by default
if (newline)
{
if (newline->flags & ML_DONTPEGTOP)
slopeskew = true;
}
else if (pfloor->master->flags & ML_DONTPEGTOP)
slopeskew = true;
if (slopeskew)
dc_texturemid = left_top;
else
#endif
dc_texturemid = *pfloor->topheight - viewz;
if (newline)
{
offsetvalue = sides[newline->sidenum[0]].rowoffset;
if (newline->flags & ML_DONTPEGBOTTOM)
{
#ifdef ESLOPE
skewslope = *pfloor->b_slope; // skew using bottom slope
if (slopeskew)
dc_texturemid = left_bottom;
else
#endif
offsetvalue -= *pfloor->topheight - *pfloor->bottomheight;
}
}
else
{
offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
#ifdef ESLOPE
skewslope = *pfloor->b_slope; // skew using bottom slope
if (slopeskew)
dc_texturemid = left_bottom;
else
#endif
offsetvalue -= *pfloor->topheight - *pfloor->bottomheight;
}
}
#ifdef ESLOPE
if (slopeskew)
{
angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y);
if (skewslope)
ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT));
}
#endif
dc_texturemid += offsetvalue;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes)
{
if (textures[texnum]->flip & 2) // vertically flipped?
{
colfunc_2s = R_DrawRepeatFlippedMaskedColumn;
column2s_length = textures[texnum]->height;
}
else
colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture
}
else
{
colfunc_2s = R_Render2sidedMultiPatchColumn; //render multipatch with no holes (no post_t info)
column2s_length = textures[texnum]->height;
}
#ifdef ESLOPE
// Set heights according to plane, or slope, whichever
{
fixed_t right_top, right_bottom;
// calculate right ends now
if (*pfloor->t_slope)
right_top = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) - viewz;
else
right_top = *pfloor->topheight - viewz;
if (*pfloor->b_slope)
right_bottom = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) - viewz;
else
right_bottom = *pfloor->bottomheight - 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);
}
#endif
// draw the columns
for (dc_x = x1; dc_x <= x2; dc_x++)
{
if (maskedtexturecol[dc_x] != INT16_MAX)
{
#ifdef ESLOPE
if (ffloortextureslide) { // skew FOF walls
if (oldx != -1)
dc_texturemid += FixedMul(ffloortextureslide, (maskedtexturecol[oldx]-maskedtexturecol[dc_x])<<FRACBITS);
oldx = dc_x;
}
#endif
// Calculate bounds
// clamp the values if necessary to avoid overflows and rendering glitches caused by them
#ifdef ESLOPE
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;
#else
sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale));
sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen;
#endif
// SoM: If column is out of range, why bother with it??
if (windowbottom < topbounds || windowtop > bottombounds)
{
if (dc_numlights)
{
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height += rlight->heightstep;
if (rlight->flags & FF_CUTLEVEL)
rlight->botheight += rlight->botheightstep;
}
}
spryscale += rw_scalestep;
continue;
}
dc_iscale = 0xffffffffu / (unsigned)spryscale;
// Get data for the column
col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);
// 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 & FF_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, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
if (pindex >= MAXLIGHTSCALE)
pindex = MAXLIGHTSCALE-1;
if (pfloor->flags & FF_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 & FF_CUTSOLIDS && !(pfloor->flags & FF_EXTRA))
solid = 1;
else if (rlight->flags & FF_CUTEXTRA && pfloor->flags & FF_EXTRA)
{
if (rlight->flags & FF_EXTRA)
{
// The light is from an extra 3D floor... Check the flags so
// there are no undesired cuts.
if ((rlight->flags & (FF_FOG|FF_SWIMMABLE)) == (pfloor->flags & (FF_FOG|FF_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);
for (i++; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height += rlight->heightstep;
if (rlight->flags & FF_CUTLEVEL)
rlight->botheight += rlight->botheightstep;
}
continue;
}
// draw the texture
colfunc_2s (col);
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);
spryscale += rw_scalestep;
continue;
}
// calculate lighting
pindex = FixedMul(spryscale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
if (pindex >= MAXLIGHTSCALE)
pindex = MAXLIGHTSCALE - 1;
dc_colormap = walllights[pindex];
if (pfloor->flags & FF_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);
spryscale += rw_scalestep;
}
}
colfunc = colfuncs[BASEDRAWFUNC];
#undef CLAMPMAX
#undef CLAMPMIN
}
// R_ExpandPlaneY
//
// A simple function to modify a vsplane'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_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)
//profile stuff ---------------------------------------------------------
//#define TIMING
#ifdef TIMING
#include "p5prof.h"
INT64 mycount;
INT64 mytotal = 0;
UINT32 nombre = 100000;
//static char runtest[10][80];
#endif
//profile stuff ---------------------------------------------------------
static void R_RenderSegLoop (void)
{
angle_t angle;
size_t pindex;
INT32 yl;
INT32 yh;
INT32 mid;
fixed_t texturecolumn = 0;
#ifdef ESLOPE
fixed_t oldtexturecolumn = -1;
#endif
INT32 top;
INT32 bottom;
INT32 i;
for (; rw_x < rw_stopx; rw_x++)
{
// mark floor / ceiling areas
yl = (topfrac+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);
}
if (numffloors)
{
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++)
{
#ifdef POLYOBJECTS_PLANES
if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
continue;
#endif
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;
#ifdef POLYOBJECTS_PLANES
// 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
#endif
if (top_w <= bottom_w)
{
ffloor[i].plane->top[rw_x] = (INT16)top_w;
ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w;
}
}
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;
#ifdef POLYOBJECTS_PLANES
// 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
#endif
if (top_w <= bottom_w)
{
ffloor[i].plane->top[rw_x] = (INT16)top_w;
ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w;
}
}
}
}
//SoM: Calculate offsets for Thick fake floors.
// calculate texture offset
angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
texturecolumn = rw_offset-FixedMul(FINETANGENT(angle),rw_distance);
#ifdef ESLOPE
if (oldtexturecolumn != -1) {
rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn-texturecolumn);
rw_midtexturemid += FixedMul(rw_midtextureslide, oldtexturecolumn-texturecolumn);
rw_toptexturemid += FixedMul(rw_toptextureslide, oldtexturecolumn-texturecolumn);
rw_midtextureback += FixedMul(rw_midtexturebackslide, oldtexturecolumn-texturecolumn);
}
oldtexturecolumn = texturecolumn;
#endif
texturecolumn >>= FRACBITS;
// texturecolumn and lighting are independent of wall tiers
if (segtextured)
{
// calculate lighting
pindex = FixedMul(rw_scale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
if (pindex >= MAXLIGHTSCALE)
pindex = MAXLIGHTSCALE-1;
dc_colormap = walllights[pindex];
dc_x = rw_x;
dc_iscale = 0xffffffffu / (unsigned)rw_scale;
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, FixedDiv(640, vid.width))>>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];
colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
}
}
frontscale[rw_x] = rw_scale;
// draw the wall tiers
if (midtexture)
{
// single sided line
if (yl <= yh && yh >= 0 && yl < viewheight)
{
dc_yl = yl;
dc_yh = yh;
dc_texturemid = rw_midtexturemid;
dc_source = R_GetColumn(midtexture,texturecolumn);
dc_texheight = textureheight[midtexture]>>FRACBITS;
//profile stuff ---------------------------------------------------------
#ifdef TIMING
ProfZeroTimer();
#endif
colfunc();
#ifdef TIMING
RDMSR(0x10,&mycount);
mytotal += mycount; //64bit add
if (nombre--==0)
I_Error("R_DrawColumn CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1),
(INT32)mytotal);
#endif
//profile stuff ---------------------------------------------------------
// dont draw anything more for this column, since
// a midtexture blocks the view
ceilingclip[rw_x] = (INT16)viewheight;
floorclip[rw_x] = -1;
}
else
{
// note: don't use min/max macros, since casting from INT32 to INT16 is involved here
if (markceiling)
ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
if (markfloor)
floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
}
}
else
{
// two sided line
if (toptexture)
{
// top wall
mid = pixhigh>>HEIGHTBITS;
pixhigh += pixhighstep;
if (mid >= floorclip[rw_x])
mid = floorclip[rw_x]-1;
if (mid >= yl) // back ceiling lower than front ceiling ?
{
if (yl >= viewheight) // entirely off bottom of screen
ceilingclip[rw_x] = (INT16)viewheight;
else if (mid >= 0) // safe to draw top texture
{
dc_yl = yl;
dc_yh = mid;
dc_texturemid = rw_toptexturemid;
dc_source = R_GetColumn(toptexture,texturecolumn);
dc_texheight = textureheight[toptexture]>>FRACBITS;
colfunc();
ceilingclip[rw_x] = (INT16)mid;
}
else // entirely off top of screen
ceilingclip[rw_x] = -1;
}
else
ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
}
else if (markceiling) // no top wall
ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
if (bottomtexture)
{
// bottom wall
mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
pixlow += pixlowstep;
// no space above wall?
if (mid <= ceilingclip[rw_x])
mid = ceilingclip[rw_x]+1;
if (mid <= yh) // back floor higher than front floor ?
{
if (yh < 0) // entirely off top of screen
floorclip[rw_x] = -1;
else if (mid < viewheight) // safe to draw bottom texture
{
dc_yl = mid;
dc_yh = yh;
dc_texturemid = rw_bottomtexturemid;
dc_source = R_GetColumn(bottomtexture,
texturecolumn);
dc_texheight = textureheight[bottomtexture]>>FRACBITS;
colfunc();
floorclip[rw_x] = (INT16)mid;
}
else // entirely off bottom of screen
floorclip[rw_x] = (INT16)viewheight;
}
else
floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
}
else if (markfloor) // no bottom wall
floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
}
if (maskedtexture || numthicksides)
{
// save texturecol
// for backdrawing of masked mid texture
maskedtexturecol[rw_x] = (INT16)texturecolumn;
#ifdef ESLOPE
if (maskedtextureheight != NULL) {
maskedtextureheight[rw_x] = (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3) ?
max(rw_midtexturemid, rw_midtextureback) :
min(rw_midtexturemid, rw_midtextureback));
}
#endif
}
if (dc_numlights)
{
for (i = 0; i < dc_numlights; i++)
{
dc_lightlist[i].height += dc_lightlist[i].heightstep;
if (dc_lightlist[i].flags & FF_CUTSOLIDS)
dc_lightlist[i].botheight += dc_lightlist[i].botheightstep;
}
}
for (i = 0; i < numffloors; i++)
ffloor[i].f_frac += ffloor[i].f_step;
for (i = 0; i < numbackffloors; i++)
{
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);
}
}
//
// 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;
#ifndef ESLOPE
fixed_t vtop;
#endif
INT32 lightnum;
INT32 i, p;
lightlist_t *light;
r_lightlist_t *rlight;
INT32 range;
#ifdef ESLOPE
vertex_t segleft, segright;
fixed_t ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide;
#endif
static size_t maxdrawsegs = 0;
#ifdef ESLOPE
maskedtextureheight = NULL;
//initialize segleft and segright
memset(&segleft, 0x00, sizeof(segleft));
memset(&segright, 0x00, sizeof(segright));
#endif
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;
//SoM: Code to remove limits on openings.
{
size_t pos = lastopening - openings;
size_t need = (rw_stopx - start)*4 + pos;
if (need > maxopenings)
{
drawseg_t *ds; //needed for fix from *cough* zdoom *cough*
INT16 *oldopenings = openings;
INT16 *oldlast = lastopening;
do
maxopenings = maxopenings ? maxopenings*2 : 16384;
while (need > maxopenings);
openings = Z_Realloc(openings, maxopenings * sizeof (*openings), PU_STATIC, NULL);
lastopening = openings + pos;
// borrowed fix from *cough* zdoom *cough*
// [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);
ADJUST(thicksidecol);
#undef ADJUST
}
}
} // 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]);
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
#ifdef ESLOPE
// 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
float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
///TODO: convert to FPU
a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y);
b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x);
c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y);
a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT));
b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT));
c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy);
det = a1*b2 - a2*b1;
ds_p->leftpos.x = segleft.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det);
ds_p->leftpos.y = segleft.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det);
}
// right
temp = xtoviewangle[stop]+viewangle;
{
// Both lines can be written in slope-intercept form, so figure out line intersection
float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
///TODO: convert to FPU
a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y);
b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x);
c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y);
a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT));
b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT));
c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy);
det = a1*b2 - a2*b1;
ds_p->rightpos.x = segright.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det);
ds_p->rightpos.y = segright.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det);
}
}
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
if (slope) { \
end1 = P_GetZAt(slope, segleft.x, segleft.y); \
end2 = P_GetZAt(slope, segright.x, segright.y); \
} else \
end1 = end2 = 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;
#else
worldtop = frontsector->ceilingheight - viewz;
worldbottom = frontsector->floorheight - viewz;
#endif
midtexture = toptexture = bottomtexture = maskedtexture = 0;
ds_p->maskedtexturecol = NULL;
ds_p->numthicksides = numthicksides = 0;
ds_p->thicksidecol = NULL;
ds_p->tsilheight = 0;
numbackffloors = 0;
for (i = 0; i < MAXFFLOORS; i++)
ds_p->thicksides[i] = NULL;
if (numffloors)
{
for (i = 0; i < numffloors; i++)
{
#ifdef POLYOBJECTS_PLANES
if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg))
continue;
#endif
#ifdef ESLOPE
if (ffloor[i].slope) {
ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft.x, segleft.y) - viewz;
ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y) - viewz;
} else
ffloor[i].f_pos_slope =
#endif
ffloor[i].f_pos = ffloor[i].height - viewz;
}
}
#ifdef ESLOPE
// 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 = FixedMul(frontsector->f_slope->zdelta, FINECOSINE((lineangle-frontsector->f_slope->xydirection)>>ANGLETOFINESHIFT));
if (frontsector->c_slope)
ceilingfrontslide = FixedMul(frontsector->c_slope->zdelta, FINECOSINE((lineangle-frontsector->c_slope->xydirection)>>ANGLETOFINESHIFT));
if (backsector && backsector->f_slope)
floorbackslide = FixedMul(backsector->f_slope->zdelta, FINECOSINE((lineangle-backsector->f_slope->xydirection)>>ANGLETOFINESHIFT));
if (backsector && backsector->c_slope)
ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT));
}
#endif
if (!backsector)
{
fixed_t texheight;
// single sided line
midtexture = R_GetTextureNum(sidedef->midtexture);
texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
#ifdef ESLOPE
if (linedef->flags & ML_EFFECT2) {
if (linedef->flags & ML_DONTPEGBOTTOM)
rw_midtexturemid = frontsector->floorheight + texheight - viewz;
else
rw_midtexturemid = frontsector->ceilingheight - viewz;
}
else
#endif
if (linedef->flags & ML_DONTPEGBOTTOM)
{
#ifdef ESLOPE
rw_midtexturemid = worldbottom + texheight;
rw_midtextureslide = floorfrontslide;
#else
vtop = frontsector->floorheight + texheight;
// bottom of texture at bottom
rw_midtexturemid = vtop - viewz;
#endif
}
else
{
// top of texture at top
rw_midtexturemid = worldtop;
#ifdef ESLOPE
rw_midtextureslide = ceilingfrontslide;
#endif
}
rw_midtexturemid += sidedef->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
boolean bothceilingssky = false; // turned on if both back and front ceilings are sky
boolean bothfloorssky = false; // likewise, but for floors
#ifdef ESLOPE
SLOPEPARAMS(backsector->c_slope, worldhigh, worldhighslope, backsector->ceilingheight)
SLOPEPARAMS(backsector->f_slope, worldlow, worldlowslope, backsector->floorheight)
worldhigh -= viewz;
worldhighslope -= viewz;
worldlow -= viewz;
worldlowslope -= viewz;
#else
worldhigh = backsector->ceilingheight - viewz;
worldlow = backsector->floorheight - viewz;
#endif
// hack to allow height changes in outdoor areas
// This is what gets rid of the upper textures if there should be sky
if (frontsector->ceilingpic == skyflatnum
&& backsector->ceilingpic == skyflatnum)
{
bothceilingssky = true;
}
// likewise, but for floors and upper textures
if (frontsector->floorpic == skyflatnum
&& backsector->floorpic == skyflatnum)
{
bothfloorssky = true;
}
ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
ds_p->silhouette = 0;
if (!bothfloorssky)
{
if (
#ifdef ESLOPE
worldbottomslope > worldlowslope ||
#endif
worldbottom > worldlow)
{
ds_p->silhouette = SIL_BOTTOM;
#ifdef ESLOPE
if ((backsector->f_slope ? P_GetZAt(backsector->f_slope, viewx, viewy) : backsector->floorheight) > viewz)
ds_p->bsilheight = INT32_MAX;
else
ds_p->bsilheight = (frontsector->f_slope ? INT32_MAX : frontsector->floorheight);
#else
ds_p->bsilheight = frontsector->floorheight;
#endif
}
#ifdef ESLOPE
else if ((backsector->f_slope ? P_GetZAt(backsector->f_slope, viewx, viewy) : backsector->floorheight) > viewz)
#else
else if (backsector->floorheight > viewz)
#endif
{
ds_p->silhouette = SIL_BOTTOM;
ds_p->bsilheight = INT32_MAX;
// ds_p->sprbottomclip = negonearray;
}
}
if (!bothceilingssky)
{
if (
#ifdef ESLOPE
worldtopslope < worldhighslope ||
#endif
worldtop < worldhigh)
{
ds_p->silhouette |= SIL_TOP;
#ifdef ESLOPE
if ((backsector->c_slope ? P_GetZAt(backsector->c_slope, viewx, viewy) : backsector->ceilingheight) < viewz)
ds_p->tsilheight = INT32_MIN;
else
ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight);
#else
ds_p->tsilheight = frontsector->ceilingheight;
#endif
}
#ifdef ESLOPE
else if ((backsector->c_slope ? P_GetZAt(backsector->c_slope, viewx, viewy) : backsector->ceilingheight) < viewz)
#else
else if (backsector->ceilingheight < viewz)
#endif
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = INT32_MIN;
// ds_p->sprtopclip = screenheightarray;
}
}
if (!bothceilingssky && !bothfloorssky)
{
#ifdef ESLOPE
if (worldhigh <= worldbottom && worldhighslope <= worldbottomslope)
#else
if (worldhigh <= worldbottom)
#endif
{
ds_p->sprbottomclip = negonearray;
ds_p->bsilheight = INT32_MAX;
ds_p->silhouette |= SIL_BOTTOM;
}
#ifdef ESLOPE
if (worldlow >= worldtop && worldlowslope >= worldtopslope)
#else
if (worldlow >= worldtop)
#endif
{
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)
{
#ifdef ESLOPE
if (doorclosed || (worldhigh <= worldbottom && worldhighslope <= worldbottomslope))
#else
if (doorclosed || backsector->ceilingheight <= frontsector->floorheight)
#endif
{
ds_p->sprbottomclip = negonearray;
ds_p->bsilheight = INT32_MAX;
ds_p->silhouette |= SIL_BOTTOM;
}
#ifdef ESLOPE
if (doorclosed || (worldlow >= worldtop && worldlowslope >= worldtopslope))
#else
if (doorclosed || backsector->floorheight >= frontsector->ceilingheight)
#endif
{ // 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
#ifdef ESLOPE
|| worldlowslope != worldbottomslope
|| backsector->f_slope != frontsector->f_slope
#endif
|| backsector->floorpic != frontsector->floorpic
|| backsector->lightlevel != frontsector->lightlevel
//SoM: 3/22/2000: Check floor x and y offsets.
|| backsector->floor_xoffs != frontsector->floor_xoffs
|| backsector->floor_yoffs != frontsector->floor_yoffs
|| backsector->floorpic_angle != frontsector->floorpic_angle
//SoM: 3/22/2000: Prevents bleeding.
|| (frontsector->heightsec != -1 && frontsector->floorpic != skyflatnum)
|| backsector->floorlightsec != frontsector->floorlightsec
//SoM: 4/3/2000: Check for colormaps
|| frontsector->extra_colormap != backsector->extra_colormap
|| (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag))
{
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
#ifdef ESLOPE
|| worldhighslope != worldtopslope
|| backsector->c_slope != frontsector->c_slope
#endif
|| backsector->ceilingpic != frontsector->ceilingpic
|| backsector->lightlevel != frontsector->lightlevel
//SoM: 3/22/2000: Check floor x and y offsets.
|| backsector->ceiling_xoffs != frontsector->ceiling_xoffs
|| backsector->ceiling_yoffs != frontsector->ceiling_yoffs
|| backsector->ceilingpic_angle != frontsector->ceilingpic_angle
//SoM: 3/22/2000: Prevents bleeding.
|| (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum)
|| backsector->ceilinglightsec != frontsector->ceilinglightsec
//SoM: 4/3/2000: Check for colormaps
|| frontsector->extra_colormap != backsector->extra_colormap
|| (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag))
{
markceiling = true;
}
else
{
// same plane on both sides
markceiling = false;
}
if (!bothceilingssky && !bothfloorssky)
{
#ifdef ESLOPE
if ((worldhigh <= worldbottom && worldhighslope <= worldbottomslope)
|| (worldlow >= worldtop && worldlowslope >= worldtopslope))
#else
if (backsector->ceilingheight <= frontsector->floorheight
|| backsector->floorheight >= frontsector->ceilingheight)
#endif
{
// closed door
markceiling = markfloor = true;
}
}
// check TOP TEXTURE
if (!bothceilingssky // never draw the top texture if on
&& (worldhigh < worldtop
#ifdef ESLOPE
|| worldhighslope < worldtopslope
#endif
))
{
fixed_t texheight;
// top texture
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
&& linedef->sidenum[1] != 0xffff)
{
// Special case... use offsets from 2nd side but only if it has a texture.
side_t *def = &sides[linedef->sidenum[1]];
toptexture = R_GetTextureNum(def->toptexture);
if (!toptexture) //Second side has no texture, use the first side's instead.
toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
else
{
toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + texheight;
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + texheight;
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
}
// check BOTTOM TEXTURE
if (!bothfloorssky // never draw the bottom texture if on
&& (worldlow > worldbottom
#ifdef ESLOPE
|| worldlowslope > worldbottomslope
#endif
)) //seulement si VISIBLE!!!
{
// bottom texture
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGBOTTOM)
rw_bottomtexturemid = frontsector->floorheight - viewz;
else
rw_bottomtexturemid = backsector->floorheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGBOTTOM)
{
// bottom of texture at bottom
// top of texture at top
rw_bottomtexturemid = worldbottom;
#ifdef ESLOPE
rw_bottomtextureslide = floorfrontslide;
#endif
}
else { // top of texture at top
rw_bottomtexturemid = worldlow;
#ifdef ESLOPE
rw_bottomtextureslide = floorbackslide;
#endif
}
}
rw_toptexturemid += sidedef->rowoffset;
rw_bottomtexturemid += sidedef->rowoffset;
// allocate space for masked texture tables
if (frontsector && backsector && frontsector->tag != backsector->tag && (backsector->ffloors || frontsector->ffloors))
{
ffloor_t *rover;
ffloor_t *r2;
fixed_t lowcut, highcut;
#ifdef ESLOPE
fixed_t lowcutslope, highcutslope;
// Used for height comparisons and etc across FOFs and slopes
fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2;
#endif
//markceiling = markfloor = true;
maskedtexture = true;
ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x;
lastopening += rw_stopx - rw_x;
lowcut = max(worldbottom, worldlow) + viewz;
highcut = min(worldtop, worldhigh) + viewz;
#ifdef ESLOPE
lowcutslope = max(worldbottomslope, worldlowslope) + viewz;
highcutslope = min(worldtopslope, worldhighslope) + viewz;
#endif
if (frontsector->ffloors && backsector->ffloors)
{
i = 0;
for (rover = backsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next)
{
if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS))
continue;
if (rover->flags & FF_INVERTSIDES)
continue;
if (rover->norender == leveltime)
continue;
#ifdef ESLOPE
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;
#else
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
#endif
for (r2 = frontsector->ffloors; r2; r2 = r2->next)
{
if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES))
continue;
if (r2->norender == leveltime)
continue;
if (rover->flags & FF_EXTRA)
{
if (!(r2->flags & FF_CUTEXTRA))
continue;
if (r2->flags & FF_EXTRA && (r2->flags & (FF_TRANSLUCENT|FF_FOG)) != (rover->flags & (FF_TRANSLUCENT|FF_FOG)))
continue;
}
else
{
if (!(r2->flags & FF_CUTSOLIDS))
continue;
}
#ifdef ESLOPE
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;
#else
if (*r2->topheight < lowcut || *r2->bottomheight > highcut)
continue;
if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight)
continue;
#endif
break;
}
if (r2)
continue;
ds_p->thicksides[i] = rover;
i++;
}
for (rover = frontsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next)
{
if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS))
continue;
if (!(rover->flags & FF_ALLSIDES))
continue;
if (rover->norender == leveltime)
continue;
#ifdef ESLOPE
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;
#else
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
#endif
for (r2 = backsector->ffloors; r2; r2 = r2->next)
{
if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES))
continue;
if (r2->norender == leveltime)
continue;
if (rover->flags & FF_EXTRA)
{
if (!(r2->flags & FF_CUTEXTRA))
continue;
if (r2->flags & FF_EXTRA && (r2->flags & (FF_TRANSLUCENT|FF_FOG)) != (rover->flags & (FF_TRANSLUCENT|FF_FOG)))
continue;
}
else
{
if (!(r2->flags & FF_CUTSOLIDS))
continue;
}
#ifdef ESLOPE
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;
#else
if (*r2->topheight < lowcut || *r2->bottomheight > highcut)
continue;
if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight)
continue;
#endif
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->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || rover->flags & FF_INVERTSIDES)
continue;
if (rover->norender == leveltime)
continue;
#ifdef ESLOPE
// Oy vey.
if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz
&& (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz)
||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz
&& (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz))
continue;
#else
if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight)
continue;
#endif
ds_p->thicksides[i] = rover;
i++;
}
}
else if (frontsector->ffloors)
{
for (rover = frontsector->ffloors, i = 0; rover && i < MAXFFLOORS; rover = rover->next)
{
if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_ALLSIDES))
continue;
if (rover->norender == leveltime)
continue;
#ifdef ESLOPE
// Oy vey.
if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz
&& (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz)
||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz
&& (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz))
continue;
if (( (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldlow+viewz
&& (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldlowslope+viewz)
||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldhigh+viewz
&& (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldhighslope+viewz))
continue;
#else
if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight)
continue;
if (*rover->topheight <= backsector->floorheight || *rover->bottomheight >= backsector->ceilingheight)
continue;
#endif
ds_p->thicksides[i] = rover;
i++;
}
}
ds_p->numthicksides = numthicksides = i;
}
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
{
// masked midtexture
if (!ds_p->thicksidecol)
{
ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
lastopening += rw_stopx - rw_x;
}
else
ds_p->maskedtexturecol = ds_p->thicksidecol;
#ifdef ESLOPE
maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0])
#ifdef POLYOBJECTS
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_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3))
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
#endif
// Set midtexture starting height
if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing
rw_midtextureslide = rw_midtexturebackslide = 0;
if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3))
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_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
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 += sidedef->rowoffset;
rw_midtextureback += sidedef->rowoffset;
#endif
maskedtexture = true;
}
}
// calculate rw_offset (only needed for textured lines)
segtextured = midtexture || toptexture || bottomtexture || maskedtexture || (numthicksides > 0);
if (segtextured)
{
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;
/// don't use texture offset for splats
rw_offset2 = rw_offset + curline->offset;
rw_offset += sidedef->textureoffset + curline->offset;
rw_centerangle = ANGLE_90 + viewangle - rw_normalangle;
// 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 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
&& (
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) :
#endif
frontsector->floorheight) >= viewz)
{
// above view plane
markfloor = false;
}
if (frontsector->ceilingpic != skyflatnum
&& (
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) :
#endif
frontsector->ceilingheight) <= viewz)
{
// below view plane
markceiling = false;
}
}
// calculate incremental stepping values for texture edges
worldtop >>= 4;
worldbottom >>= 4;
#ifdef ESLOPE
worldtopslope >>= 4;
worldbottomslope >>= 4;
#endif
if (linedef->special == HORIZONSPECIAL) { // 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);
#ifdef ESLOPE
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);
}
#endif
}
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++)
{
#ifdef ESLOPE
fixed_t leftheight, rightheight;
#endif
light = &frontsector->lightlist[i];
rlight = &dc_lightlist[p];
#ifdef ESLOPE
if (light->slope) {
leftheight = P_GetZAt(light->slope, segleft.x, segleft.y);
rightheight = P_GetZAt(light->slope, segright.x, segright.y);
// Flag sector as having slopes
frontsector->hasslope = true;
} else
leftheight = rightheight = light->height;
leftheight -= viewz;
rightheight -= viewz;
leftheight >>= 4;
rightheight >>= 4;
#endif
if (i != 0)
{
#ifdef ESLOPE
if (leftheight < worldbottom && rightheight < worldbottomslope)
continue;
if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight)
continue;
#else
if (light->height < frontsector->floorheight)
continue;
if (light->height > frontsector->ceilingheight && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight)
continue;
#endif
}
#ifdef ESLOPE
rlight->height = (centeryfrac>>4) - FixedMul(leftheight, rw_scale);
rlight->heightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2);
rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
#else
rlight->height = (centeryfrac>>4) - FixedMul((light->height - viewz) >> 4, rw_scale);
rlight->heightstep = -FixedMul (rw_scalestep, (light->height - viewz) >> 4);
#endif
rlight->flags = light->flags;
if (light->caster && light->caster->flags & FF_CUTSOLIDS)
{
#ifdef ESLOPE
if (*light->caster->b_slope) {
leftheight = P_GetZAt(*light->caster->b_slope, segleft.x, segleft.y);
rightheight = P_GetZAt(*light->caster->b_slope, segright.x, segright.y);
// Flag sector as having slopes
frontsector->hasslope = true;
} else
leftheight = rightheight = *light->caster->bottomheight;
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);
#else
rlight->botheight = (centeryfrac >> 4) - FixedMul((*light->caster->bottomheight - viewz) >> 4, rw_scale);
rlight->botheightstep = -FixedMul (rw_scalestep, (*light->caster->bottomheight - viewz) >> 4);
#endif
}
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;
#ifdef ESLOPE
ffloor[i].f_pos_slope >>= 4;
#endif
if (linedef->special == HORIZONSPECIAL) // 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
{
#ifdef ESLOPE
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);
#else
ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos);
ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
#endif
}
}
}
if (backsector)
{
worldhigh >>= 4;
worldlow >>= 4;
#ifdef ESLOPE
worldhighslope >>= 4;
worldlowslope >>= 4;
#endif
if (toptexture)
{
pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
pixhighstep = -FixedMul (rw_scalestep,worldhigh);
#ifdef ESLOPE
if (backsector->c_slope) {
fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2);
pixhighstep = (topfracend-pixhigh)/(range);
}
#endif
}
if (bottomtexture)
{
pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
pixlowstep = -FixedMul (rw_scalestep,worldlow);
#ifdef ESLOPE
if (backsector->f_slope) {
fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2);
pixlowstep = (bottomfracend-pixlow)/(range);
}
#endif
}
{
ffloor_t * rover;
#ifdef ESLOPE
fixed_t roverleft, roverright;
fixed_t planevistest;
#endif
i = 0;
if (backsector->ffloors)
{
for (rover = backsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES))
continue;
if (rover->norender == leveltime)
continue;
#ifdef ESLOPE
// Let the renderer know this sector is sloped.
if (*rover->b_slope || *rover->t_slope)
backsector->hasslope = true;
roverleft = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz;
roverright = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz;
planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight);
if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) &&
(roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) &&
((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) ||
(viewz > planevistest && (rover->flags & FF_BOTHPLANES))))
{
//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 = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz;
roverright = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz;
planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight);
if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) &&
(roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) &&
((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) ||
(viewz < planevistest && (rover->flags & FF_BOTHPLANES))))
{
//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 (*rover->bottomheight <= backsector->ceilingheight &&
*rover->bottomheight >= backsector->floorheight &&
((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) ||
(viewz > *rover->bottomheight && (rover->flags & FF_BOTHPLANES))))
{
ffloor[i].b_pos = *rover->bottomheight;
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 >= MAXFFLOORS)
break;
if (*rover->topheight >= backsector->floorheight &&
*rover->topheight <= backsector->ceilingheight &&
((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) ||
(viewz < *rover->topheight && (rover->flags & FF_BOTHPLANES))))
{
ffloor[i].b_pos = *rover->topheight;
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++;
}
#endif
}
}
else if (frontsector && frontsector->ffloors)
{
for (rover = frontsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES))
continue;
if (rover->norender == leveltime)
continue;
#ifdef ESLOPE
// Let the renderer know this sector is sloped.
if (*rover->b_slope || *rover->t_slope)
frontsector->hasslope = true;
roverleft = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz;
roverright = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz;
planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight);
if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) &&
(roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) &&
((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) ||
(viewz > planevistest && (rover->flags & FF_BOTHPLANES))))
{
//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 = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz;
roverright = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz;
planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight);
if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) &&
(roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) &&
((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) ||
(viewz < planevistest && (rover->flags & FF_BOTHPLANES))))
{
//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 (*rover->bottomheight <= frontsector->ceilingheight &&
*rover->bottomheight >= frontsector->floorheight &&
((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) ||
(viewz > *rover->bottomheight && (rover->flags & FF_BOTHPLANES))))
{
ffloor[i].b_pos = *rover->bottomheight;
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 >= MAXFFLOORS)
break;
if (*rover->topheight >= frontsector->floorheight &&
*rover->topheight <= frontsector->ceilingheight &&
((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) ||
(viewz < *rover->topheight && (rover->flags & FF_BOTHPLANES))))
{
ffloor[i].b_pos = *rover->topheight;
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++;
}
#endif
}
}
#ifdef POLYOBJECTS_PLANES
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;
#ifdef ESLOPE
ffloor[i].slope = NULL;
#endif
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;
#ifdef ESLOPE
ffloor[i].slope = NULL;
#endif
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++;
}
}
#endif
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);
}
#ifdef POLYOBJECTS_PLANES
// 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;
}
}
#endif
}
#ifdef WALLSPLATS
if (linedef->splats && cv_splats.value)
{
// Isn't a bit wasteful to copy the ENTIRE array for every drawseg?
M_Memcpy(last_ceilingclip + ds_p->x1, ceilingclip + ds_p->x1,
sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1));
M_Memcpy(last_floorclip + ds_p->x1, floorclip + ds_p->x1,
sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1));
R_RenderSegLoop();
R_DrawWallSplats();
}
else
#endif
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 (((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++;
}