// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2016 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_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 = basecolfunc;
				break;
			case SPLATDRAWMODE_TRANS:
				if (!cv_translucency.value)
					colfunc = basecolfunc;
				else
				{
					dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
					colfunc = fuzzcolfunc;
				}

				break;
			case SPLATDRAWMODE_SHADE:
				colfunc = shadecolfunc;
				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 = basecolfunc;
}

#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 == wallcolfunc)
			twosmultipatchfunc();
		else
			colfunc();
	}
}

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;
	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 = fuzzcolfunc;
			break;
		case 909:
			colfunc = R_DrawFogColumn_8;
			windowtop = frontsector->ceilingheight;
			windowbottom = frontsector->floorheight;
			break;
		default:
			colfunc = wallcolfunc;
			break;
	}

	if (curline->polyseg && curline->polyseg->translucency > 0)
	{
		if (curline->polyseg->translucency >= NUMTRANSMAPS)
			return;

		dc_transmap = transtables + ((curline->polyseg->translucency-1)<<FF_TRANSSHIFT);
		colfunc = fuzzcolfunc;
	}

#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)
		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 == fuzzcolfunc)
				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 == fuzzcolfunc)
		{
			if (frontsector->extra_colormap && frontsector->extra_colormap->fog)
				lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
			else
				lightnum = LIGHTLEVELS - 1;
		}
		else
			lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);

		if (colfunc == R_DrawFogColumn_8
			|| (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];

						rlight->height += rlight->heightstep;
						height = rlight->height;

						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 = wallcolfunc;
}

// 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;
	}
}

//
// 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;
#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 = wallcolfunc;

	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 = fuzzcolfunc;
	}
	else if (pfloor->flags & FF_FOG)
		colfunc = R_DrawFogColumn_8;

#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
			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;

			if (*pfloor->b_slope) {
				pfloorleft = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y);
				pfloorright = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y);
			} else
				pfloorleft = pfloorright = *pfloor->bottomheight;

			if (leftheight < pfloorleft && rightheight < pfloorright)
				continue;

			if (*pfloor->t_slope) {
				pfloorleft = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y);
				pfloorright = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y);
			} else
				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;

			overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS);
			if (overflow_test < 0) overflow_test = -overflow_test;
			if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
			overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS);
			if (overflow_test < 0) overflow_test = -overflow_test;
			if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;

			rlight->height = (centeryfrac) - FixedMul(leftheight, ds->scale1);
			rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
			rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
			rlight->height -= rlight->heightstep;
#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) - rlight->heightstep;
#endif
			rlight->flags = light->flags;
			if (light->flags & FF_CUTLEVEL)
			{
#ifdef ESLOPE
				if (*light->caster->b_slope) {
					leftheight = P_GetZAt(*light->caster->b_slope, ds->leftpos.x, ds->leftpos.y);
					rightheight = P_GetZAt(*light->caster->b_slope, ds->rightpos.x, ds->rightpos.y);
				} else
					leftheight = rightheight = *light->caster->bottomheight;

				leftheight -= viewz;
				rightheight -= viewz;

				overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS);
				if (overflow_test < 0) overflow_test = -overflow_test;
				if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
				overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS);
				if (overflow_test < 0) overflow_test = -overflow_test;
				if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;

				rlight->botheight = (centeryfrac) - FixedMul(leftheight, ds->scale1);
				rlight->botheightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
				rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range);
				rlight->botheight -= rlight->botheightstep;
#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) - rlight->botheightstep;
#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 == fuzzcolfunc)
			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;

	dc_texturemid = *pfloor->topheight - viewz;

	if (newline)
	{
		offsetvalue = sides[newline->sidenum[0]].rowoffset;
		if (newline->flags & ML_DONTPEGBOTTOM)
			offsetvalue -= *pfloor->topheight - *pfloor->bottomheight;
	}
	else
	{
		offsetvalue = sides[pfloor->master->sidenum[0]].rowoffset;
		if (curline->linedef->flags & ML_DONTPEGBOTTOM)
			offsetvalue -= *pfloor->topheight - *pfloor->bottomheight;
	}

	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)
		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 left_top, right_top, left_bottom, right_bottom;

		if (*pfloor->t_slope)
		{
			left_top = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) - viewz;
			right_top = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) - viewz;
		}
		else
			left_top = right_top = *pfloor->topheight - viewz;

		if (*pfloor->b_slope)
		{
			left_bottom = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) - viewz;
			right_bottom = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) - viewz;
		}
		else
			left_bottom = 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

#define CLAMPMAX INT32_MAX
#define CLAMPMIN (-INT32_MAX) // This is not INT32_MIN on purpose! INT32_MIN makes the drawers freak out.

	// draw the columns
	for (dc_x = x1; dc_x <= x2; dc_x++)
	{
		if (maskedtexturecol[dc_x] != INT16_MAX)
		{
			// 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;

#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)
				{
					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;

				// draw the texture
				col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);

				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;

					rlight->height += rlight->heightstep;
					height = rlight->height;

					if (solid)
					{
						rlight->botheight += rlight->botheightstep;
						bheight = rlight->botheight - (FRACUNIT >> 1);
					}

					if (height <= windowtop)
					{
						if (lighteffect)
							dc_colormap = rlight->rcolormap;
						if (solid && windowtop < bheight)
							windowtop = bheight;
						continue;
					}

					windowbottom = height;
					if (windowbottom >= sprbotscreen)
					{
						windowbottom = sprbotscreen;
						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;
					}
					colfunc_2s (col);
					if (solid)
						windowtop = bheight;
					else
						windowtop = windowbottom + 1;
					if (lighteffect)
						dc_colormap = rlight->rcolormap;
				}
				windowbottom = sprbotscreen;
				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);
			if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap)
				dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps);

#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

			dc_iscale = 0xffffffffu / (unsigned)spryscale;

			// draw the texture
			col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);

			colfunc_2s (col);
			spryscale += rw_scalestep;
		}
	}
	colfunc = wallcolfunc;

#undef CLAMPMAX
#undef CLAMPMIN
}

//
// 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;

		// no space above wall?
		top = ceilingclip[rw_x]+1;

		// no space above wall?
		if (yl < top)
			yl = top;

		if (markceiling)
		{
			bottom = yl-1;

			if (bottom >= floorclip[rw_x])
				bottom = floorclip[rw_x]-1;

			if (top <= bottom)
			{
				ceilingplane->top[rw_x] = (INT16)top;
				ceilingplane->bottom[rw_x] = (INT16)bottom;
			}
		}


		yh = bottomfrac>>HEIGHTBITS;

		bottom = floorclip[rw_x]-1;

		if (yh > bottom)
			yh = bottom;

		if (markfloor)
		{
#if 0 // Old Doom Legacy code
			bottom = floorclip[rw_x]-1;
			if (top <= ceilingclip[rw_x])
				top = ceilingclip[rw_x]+1;
			if (top <= bottom && floorplane)
			{
				floorplane->top[rw_x] = (INT16)top;
				floorplane->bottom[rw_x] = (INT16)bottom;
			}
#else // Spiffy new PRBoom code
			top  = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh;

			if (++top <= bottom && floorplane)
			{
				floorplane->top[rw_x] = (INT16)top;
				floorplane->bottom[rw_x] = (INT16)bottom;
			}
#endif
		}

		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;

				// 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) {
					if (ffloor[i].plane->minx > rw_x)
						ffloor[i].plane->minx = rw_x;
					else if (ffloor[i].plane->maxx < rw_x)
						ffloor[i].plane->maxx = rw_x;
				}
#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 (curline->polyseg && ffloor[i].polyobj && ffloor[i].polyobj == curline->polyseg && top_w >= bottom_w) {
						ffloor[i].plane->top[rw_x] = ffloor[i].plane->bottom[rw_x] = 0xFFFF;
					} 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 (curline->polyseg && ffloor[i].polyobj && ffloor[i].polyobj == curline->polyseg && top_w >= bottom_w) {
						ffloor[i].plane->top[rw_x] = ffloor[i].plane->bottom[rw_x] = 0xFFFF;
					} 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 = R_DrawColumnShadowed_8;
			}
		}

		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++)
		{
#ifdef POLYOBJECTS_PLANES
			if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
				continue;
#endif

			ffloor[i].f_frac += ffloor[i].f_step;
		}

		for (i = 0; i < numbackffloors; i++)
		{
			INT32 y_w;

#ifdef POLYOBJECTS_PLANES
			if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
				continue;
#endif
			y_w = ffloor[i].b_frac >> HEIGHTBITS;

			ffloor[i].f_clip[rw_x] = ffloor[i].c_clip[rw_x] = (INT16)(y_w & 0xFFFF);
			ffloor[i].b_frac += ffloor[i].b_step;
		}

		rw_scale += rw_scalestep;
		topfrac += topstep;
		bottomfrac += bottomstep;
	}
}

//
// R_StoreWallRange
// A wall segment will be drawn
//  between start and stop pixels (inclusive).
//
void R_StoreWallRange(INT32 start, INT32 stop)
{
	fixed_t       hyp;
	fixed_t       sineval;
	angle_t       distangle, offsetangle;
#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

	if (ds_p == drawsegs+maxdrawsegs)
	{
		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;
		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;
	hyp = R_PointToDist (curline->v1->x, curline->v1->y);
	sineval = FINESINE(distangle>>ANGLETOFINESHIFT);
	rw_distance = FixedMul (hyp, sineval);


	ds_p->x1 = rw_x = start;
	ds_p->x2 = stop;
	ds_p->curline = curline;
	rw_stopx = stop+1;

	//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);
		}
	}

	if (frontsector->c_slope) {
		worldtop = P_GetZAt(frontsector->c_slope, segleft.x, segleft.y) - viewz;
		worldtopslope = P_GetZAt(frontsector->c_slope, segright.x, segright.y) - viewz;
	} else {
		worldtopslope =
#else
	{
#endif
		worldtop = frontsector->ceilingheight - viewz;
	}


#ifdef ESLOPE
	if (frontsector->f_slope) {
		worldbottom = P_GetZAt(frontsector->f_slope, segleft.x, segleft.y) - viewz;
		worldbottomslope = P_GetZAt(frontsector->f_slope, segright.x, segright.y) - viewz;
	} else {
		worldbottomslope =
#else
	{
#endif
		worldbottom = frontsector->floorheight - viewz;
	}

	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

#ifdef ESLOPE
		if (backsector->c_slope) {
			worldhigh = P_GetZAt(backsector->c_slope, segleft.x, segleft.y) - viewz;
			worldhighslope = P_GetZAt(backsector->c_slope, segright.x, segright.y) - viewz;
		} else {
			worldhighslope =
#else
		{
#endif
			worldhigh = backsector->ceilingheight - viewz;
		}


#ifdef ESLOPE
		if (backsector->f_slope) {
			worldlow = P_GetZAt(backsector->f_slope, segleft.x, segleft.y) - viewz;
			worldlowslope = P_GetZAt(backsector->f_slope, segright.x, segright.y) - viewz;
		} else {
			worldlowslope =
#else
		{
#endif
			worldlow = backsector->floorheight - viewz;
		}


		// hack to allow height changes in outdoor areas
		if (frontsector->ceilingpic == skyflatnum
			&& backsector->ceilingpic == skyflatnum)
		{
#ifdef ESLOPE
			worldtopslope = worldhighslope =
#endif
			worldtop = worldhigh;
		}

		ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
		ds_p->silhouette = 0;

		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 (
#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;
		}

#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.
		{
#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 (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
		    || 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 (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 (backsector->ceilingheight <= frontsector->floorheight ||
		    backsector->floorheight >= frontsector->ceilingheight)
		{
			// closed door
			markceiling = markfloor = true;
		}

		// check TOP TEXTURE
		if (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 (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
					if (*rover->t_slope) {
						high1 = P_GetZAt(*rover->t_slope, segleft.x, segleft.y);
						highslope1 = P_GetZAt(*rover->t_slope, segright.x, segright.y);
					} else
						high1 = highslope1 = *rover->topheight;
					if (*rover->b_slope) {
						low1 = P_GetZAt(*rover->b_slope, segleft.x, segleft.y);
						lowslope1 = P_GetZAt(*rover->b_slope, segright.x, segright.y);
					} else
						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
						if (*r2->t_slope) {
							high2 = P_GetZAt(*r2->t_slope, segleft.x, segleft.y);
							highslope2 = P_GetZAt(*r2->t_slope, segright.x, segright.y);
						} else
							high2 = highslope2 = *r2->topheight;
						if (*r2->b_slope) {
							low2 = P_GetZAt(*r2->b_slope, segleft.x, segleft.y);
							lowslope2 = P_GetZAt(*r2->b_slope, segright.x, segright.y);
						} else
							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
					if (*rover->t_slope) {
						high1 = P_GetZAt(*rover->t_slope, segleft.x, segleft.y);
						highslope1 = P_GetZAt(*rover->t_slope, segright.x, segright.y);
					} else
						high1 = highslope1 = *rover->topheight;
					if (*rover->b_slope) {
						low1 = P_GetZAt(*rover->b_slope, segleft.x, segleft.y);
						lowslope1 = P_GetZAt(*rover->b_slope, segright.x, segright.y);
					} else
						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
						if (*r2->t_slope) {
							high2 = P_GetZAt(*r2->t_slope, segleft.x, segleft.y);
							highslope2 = P_GetZAt(*r2->t_slope, segright.x, segright.y);
						} else
							high2 = highslope2 = *r2->topheight;
						if (*r2->b_slope) {
							low2 = P_GetZAt(*r2->b_slope, segleft.x, segleft.y);
							lowslope2 = P_GetZAt(*r2->b_slope, segright.x, segright.y);
						} else
							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++;
				}
			}
			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);

		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 ((
#ifdef ESLOPE
			frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) :
#endif
			frontsector->floorheight) >= viewz)
		{
			// above view plane
			markfloor = false;
		}

		if ((
#ifdef ESLOPE
			frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) :
#endif
			frontsector->ceilingheight) <= viewz &&
		    frontsector->ceilingpic != skyflatnum)
		{
			// below view plane
			markceiling = false;
		}
	}

	// calculate incremental stepping values for texture edges
	worldtop >>= 4;
	worldbottom >>= 4;
#ifdef ESLOPE
	worldtopslope >>= 4;
	worldbottomslope >>= 4;
#endif

	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++)
		{
#ifdef POLYOBJECTS_PLANES
			if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
				continue;
#endif

			ffloor[i].f_pos >>= 4;
#ifdef ESLOPE
			ffloor[i].f_pos_slope >>= 4;
			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 = 0;
	}

	// 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 = 0;
	}

	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 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 = wallcolfunc;

	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++;
}