qzdoom-gpl/src/r_segs.cpp

2133 lines
56 KiB
C++
Raw Normal View History

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// All the clipping: columns, horizontal spans, sky columns.
//
// This file contains some code from the Build Engine.
//
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
//-----------------------------------------------------------------------------
#include "m_alloc.h"
#include <stdlib.h>
#include <stddef.h>
#include "templates.h"
#include "i_system.h"
#include "doomdef.h"
#include "doomstat.h"
#include "p_lnspec.h"
#include "r_local.h"
#include "r_sky.h"
#include "v_video.h"
#include "m_swap.h"
#include "w_wad.h"
#include "stats.h"
2006-04-12 01:50:09 +00:00
#include "a_sharedglobal.h"
#define WALLYREPEAT 8
CVAR (Int, ty, 8, 0)
CVAR (Int, tx, 8, 0)
#define HEIGHTBITS 12
#define HEIGHTSHIFT (FRACBITS-HEIGHTBITS)
// The 3072 below is just an arbitrary value picked to avoid
// drawing lines the player is too close to that would overflow
// the texture calculations.
#define TOO_CLOSE_Z 3072
extern fixed_t globaluclip, globaldclip;
// OPTIMIZE: closed two sided lines as single sided
// killough 1/6/98: replaced globals with statics where appropriate
static BOOL segtextured; // True if any of the segs textures might be visible.
bool markfloor; // False if the back side is the same plane.
bool markceiling;
FTexture *toptexture;
FTexture *bottomtexture;
FTexture *midtexture;
int OWallMost (short *mostbuf, fixed_t z);
int WallMost (short *mostbuf, const secplane_t &plane);
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat);
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat);
extern fixed_t WallSZ1, WallSZ2, WallTX1, WallTX2, WallTY1, WallTY2, WallCX1, WallCX2, WallCY1, WallCY2;
extern int WallSX1, WallSX2;
extern float WallUoverZorg, WallUoverZstep, WallInvZorg, WallInvZstep, WallDepthScale, WallDepthOrg;
int wallshade;
short walltop[MAXWIDTH]; // [RH] record max extents of wall
short wallbottom[MAXWIDTH];
short wallupper[MAXWIDTH];
short walllower[MAXWIDTH];
fixed_t swall[MAXWIDTH];
fixed_t lwall[MAXWIDTH];
int lwallscale;
//
// regular wall
//
extern fixed_t rw_backcz1, rw_backcz2;
extern fixed_t rw_backfz1, rw_backfz2;
extern fixed_t rw_frontcz1, rw_frontcz2;
extern fixed_t rw_frontfz1, rw_frontfz2;
int rw_ceilstat, rw_floorstat;
bool rw_mustmarkfloor, rw_mustmarkceiling;
bool rw_prepped;
bool rw_markmirror;
bool rw_havehigh;
bool rw_havelow;
fixed_t rw_light; // [RH] Scale lights with viewsize adjustments
fixed_t rw_lightstep;
fixed_t rw_lightleft;
static fixed_t rw_frontlowertop;
static int rw_x;
static int rw_stopx;
fixed_t rw_offset;
static fixed_t rw_scalestep;
static fixed_t rw_midtexturemid;
static fixed_t rw_toptexturemid;
static fixed_t rw_bottomtexturemid;
FTexture *rw_pic;
static short *maskedtexturecol;
static FTexture *WallSpriteTile;
static void R_RenderDecal (side_t *wall, DBaseDecal *first, drawseg_t *clipper, int pass);
static void WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans));
//=============================================================================
//
// CVAR r_fogboundary
//
// If true, makes fog look more "real" by shading the walls separating two
// sectors with different fog.
//=============================================================================
CVAR(Bool, r_fogboundary, true, 0)
inline bool IsFogBoundary (sector_t *front, sector_t *back)
{
return r_fogboundary && !fixedcolormap && front->ColorMap->Fade &&
front->ColorMap->Fade != back->ColorMap->Fade &&
(front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum);
}
//=============================================================================
//
// CVAR r_drawmirrors
//
// Set to false to disable rendering of mirrors
//=============================================================================
CVAR(Bool, r_drawmirrors, true, 0)
//
// R_RenderMaskedSegRange
//
fixed_t *MaskedSWall;
static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FTexture::Span *spans), FTexture *tex)
{
if (maskedtexturecol[dc_x] != SHRT_MAX)
{
// calculate lighting
if (!fixedcolormap)
{
dc_colormap = basecolormap + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
dc_iscale = MaskedSWall[dc_x];
sprtopscreen = centeryfrac - FixedMul (dc_texturemid, spryscale);
// killough 1/25/98: here's where Medusa came in, because
// it implicitly assumed that the column was all one patch.
// Originally, Doom did not construct complete columns for
// multipatched textures, so there were no header or trailer
// bytes in the column referred to below, which explains
// the Medusa effect. The fix is to construct true columns
// when forming multipatched textures (see r_data.c).
// draw the texture
const FTexture::Span *spans;
const BYTE *pixels = tex->GetColumn (maskedtexturecol[dc_x], &spans);
blastfunc (pixels, spans);
maskedtexturecol[dc_x] = SHRT_MAX;
}
rw_light += rw_lightstep;
spryscale += rw_scalestep;
}
void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
{
FTexture *tex;
int i;
sector_t tempsec; // killough 4/13/98
fixed_t texheight, textop, scaley;
sprflipvert = false;
curline = ds->curline;
// killough 4/11/98: draw translucent 2s normal textures
// [RH] modified because we don't use user-definable translucency maps
ESPSResult drawmode;
drawmode = R_SetPatchStyle (curline->sidedef->Flags & WALLF_ADDTRANS ? STYLE_Add : STYLE_Translucent,
curline->linedef->alpha < 255 ? curline->linedef->alpha<<8 : FRACUNIT,
0, 0);
if ((drawmode == DontDraw && !ds->bFogBoundary))
{
return;
}
NetUpdate ();
frontsector = curline->frontsector;
backsector = curline->backsector;
tex = TexMan(curline->sidedef->midtexture);
// killough 4/13/98: get correct lightlevel for 2s normal textures
const sector_t *sec = R_FakeFlat (frontsector, &tempsec, NULL, NULL, false);
basecolormap = sec->ColorMap->Maps; // [RH] Set basecolormap
wallshade = ds->shade;
rw_lightstep = ds->lightstep;
rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
mfloorclip = openings + ds->sprbottomclip - ds->x1;
mceilingclip = openings + ds->sprtopclip - ds->x1;
// [RH] Draw fog partition
if (ds->bFogBoundary)
{
R_DrawFogBoundary (x1, x2, mceilingclip, mfloorclip);
if (ds->maskedtexturecol == -1)
{
goto clearfog;
}
}
MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1;
maskedtexturecol = openings + ds->maskedtexturecol - ds->x1;
spryscale = ds->iscale + ds->iscalestep * (x1 - ds->x1);
rw_scalestep = ds->iscalestep;
// find positioning
scaley = tex->ScaleY ? tex->ScaleY : ty;
texheight = SafeDivScale19 (tex->GetHeight(), scaley);
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
dc_texturemid = MAX (frontsector->floortexz, backsector->floortexz) + texheight;
}
else
{
dc_texturemid = MIN (frontsector->ceilingtexz, backsector->ceilingtexz);
}
if (tex->bWorldPanning)
{
// rowoffset is added before the MulScale3 so that the masked texture will
// still be positioned in world units rather than texels.
dc_texturemid += curline->sidedef->rowoffset - viewz;
textop = dc_texturemid;
dc_texturemid = MulScale3 (dc_texturemid, scaley);
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
textop = dc_texturemid - viewz + SafeDivScale3 (curline->sidedef->rowoffset, scaley);
dc_texturemid = MulScale3 (dc_texturemid - viewz, scaley) + curline->sidedef->rowoffset;
}
// [RH] Don't bother drawing segs that are completely offscreen
if (MulScale12 (globaldclip, ds->sz1) < -textop &&
MulScale12 (globaldclip, ds->sz2) < -textop)
{ // Texture top is below the bottom of the screen
goto clearfog;
}
if (MulScale12 (globaluclip, ds->sz1) > texheight - textop &&
MulScale12 (globaluclip, ds->sz2) > texheight - textop)
{ // Texture bottom is above the top of the screen
goto clearfog;
}
WallSZ1 = ds->sz1;
WallSZ2 = ds->sz2;
WallSX1 = ds->sx1;
WallSX2 = ds->sx2;
OWallMost (wallupper, textop);
OWallMost (walllower, textop - texheight);
for (i = x1; i <= x2; i++)
{
if (wallupper[i] < mceilingclip[i])
wallupper[i] = mceilingclip[i];
}
for (i = x1; i <= x2; i++)
{
if (walllower[i] > mfloorclip[i])
walllower[i] = mfloorclip[i];
}
mfloorclip = walllower;
mceilingclip = wallupper;
if (fixedlightlev)
dc_colormap = basecolormap + fixedlightlev;
else if (fixedcolormap)
dc_colormap = fixedcolormap;
// draw the columns one at a time
if (drawmode == DoDraw0)
{
for (dc_x = x1; dc_x <= x2; ++dc_x)
{
BlastMaskedColumn (R_DrawMaskedColumn, tex);
}
}
else
{
// [RH] Draw up to four columns at once
int stop = (x2+1) & ~3;
if (x1 > x2)
goto clearfog;
dc_x = x1;
while ((dc_x < stop) && (dc_x & 3))
{
BlastMaskedColumn (R_DrawMaskedColumn, tex);
dc_x++;
}
while (dc_x < stop)
{
rt_initcols();
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex);
rt_draw4cols (dc_x - 3);
dc_x++;
}
while (dc_x <= x2)
{
BlastMaskedColumn (R_DrawMaskedColumn, tex);
dc_x++;
}
}
clearfog:
R_FinishSetPatchStyle ();
//if (ds->bFogBoundary)
{
clearbufshort (openings + ds->sprtopclip - ds->x1 + x1, x2-x1+1, viewheight);
}
return;
}
extern int *texturewidthmask;
// prevlineasm1 is like vlineasm1 but skips the loop if only drawing one pixel
inline fixed_t prevline1 (fixed_t vince, byte *colormap, int count, fixed_t vplce, const byte *bufplce, byte *dest)
{
dc_iscale = vince;
dc_colormap = colormap;
dc_count = count;
dc_texturefrac = vplce;
dc_source = bufplce;
dc_dest = dest;
return doprevline1 ();
}
/*
esp+00 = edi
esp+04 = ebx
esp+08 = esi
esp+0c = ebp
esp+13 = bad
esp+14 = light
esp+18 = &uwal[x]
esp+1c = &lwal[x]
esp+20 = x2
esp+24 = &dwal[x]
esp+28 =
esp+2c = xoffset
esp+30 = yrepeat
esp+34 = texturemid
esp+40 = y1ve[]
esp+50 = y2ve[]
esp+54 =
esp+58 =
esp+5c =
esp+60 = <return address>
esp+64 = uwal
esp+68 = dwal
esp+6c = swal
esp+70 = lwal
esp+74 = getcol
esi = x
ebp = x2
*/
void wallscan (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal,
const BYTE *(*getcol)(FTexture *tex, int x))
{
long x, shiftval;
long y1ve[4], y2ve[4], u4, d4, z;
char bad;
fixed_t light = rw_light - rw_lightstep;
SDWORD yrepeat, texturemid, xoffset;
// This function also gets used to draw skies. Unlike BUILD, skies are
// drawn by visplane instead of by bunch, so these checks are invalid.
//if ((uwal[x1] > viewheight) && (uwal[x2] > viewheight)) return;
//if ((dwal[x1] < 0) && (dwal[x2] < 0)) return;
if (rw_pic->UseType == FTexture::TEX_Null)
{
return;
}
//extern cycle_t WallScanCycles;
//clock (WallScanCycles);
rw_pic->GetHeight(); // Make sure texture size is loaded
shiftval = rw_pic->HeightBits;
setupvline (32-shiftval);
yrepeat = (rw_pic->ScaleY ? rw_pic->ScaleY : ty) << (11 - shiftval);
texturemid = dc_texturemid << (16 - shiftval);
xoffset = rw_offset;
x = x1;
//while ((umost[x] > dmost[x]) && (x <= x2)) x++;
if (fixedcolormap)
{
palookupoffse[0] = dc_colormap;
palookupoffse[1] = dc_colormap;
palookupoffse[2] = dc_colormap;
palookupoffse[3] = dc_colormap;
}
for(; (x <= x2) && (x & 3); ++x)
{
light += rw_lightstep;
y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0]) continue;
if (!fixedcolormap)
{ // calculate lighting
dc_colormap = basecolormap + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + x + dc_destorg;
dc_iscale = swal[x] * yrepeat;
dc_count = y2ve[0] - y1ve[0];
dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
dovline1();
}
for(; x <= x2-3; x += 4)
{
bad = 0;
for (z = 3; z>= 0; --z)
{
y1ve[z] = uwal[x+z];//max(uwal[x+z],umost[x+z]);
y2ve[z] = dwal[x+z];//min(dwal[x+z],dmost[x+z])-1;
if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
bufplce[z] = getcol (rw_pic, (lwal[x+z] + xoffset) >> FRACBITS);
vince[z] = swal[x+z] * yrepeat;
vplce[z] = texturemid + FixedMul (vince[z], (y1ve[z]<<FRACBITS)-centeryfrac+FRACUNIT);
}
if (bad == 15)
{
light += rw_lightstep << 2;
continue;
}
if (!fixedcolormap)
{
for (z = 0; z < 4; ++z)
{
light += rw_lightstep;
palookupoffse[z] = basecolormap + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
}
u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
if ((bad != 0) || (u4 >= d4))
{
for (z = 0; z < 4; ++z)
{
if (!(bad & 1))
{
prevline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg);
}
bad >>= 1;
}
continue;
}
for (z = 0; z < 4; ++z)
{
if (u4 > y1ve[z])
{
vplce[z] = prevline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg);
}
}
if (d4 > u4)
{
dc_count = d4-u4;
dc_dest = ylookup[u4]+x+dc_destorg;
dovline4();
}
BYTE *i = x+ylookup[d4]+dc_destorg;
for (z = 0; z < 4; ++z)
{
if (y2ve[z] > d4)
{
prevline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
}
}
}
for(;x<=x2;x++)
{
light += rw_lightstep;
y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0]) continue;
if (!fixedcolormap)
{ // calculate lighting
dc_colormap = basecolormap + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + x + dc_destorg;
dc_iscale = swal[x] * yrepeat;
dc_count = y2ve[0] - y1ve[0];
dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
dovline1();
}
//unclock (WallScanCycles);
NetUpdate ();
}
void wallscan_striped (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal)
{
bool flooding = false;
byte *startcolormap = basecolormap;
int startshade = wallshade;
bool fogginess = foggy;
byte *floodcolormap = startcolormap;
int floodshade = startshade;
bool floodfoggy = foggy;
short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH];
short *up, *down;
FExtraLight *el = frontsector->ExtraLights;
up = uwal;
down = most1;
for (int i = 0; i < el->NumUsedLights; ++i)
{
if (flooding && !el->Lights[i].bFlooder)
{
continue;
}
if (!el->Lights[i].bOverlaps)
{
int j = WallMost (most3, el->Lights[i].Plane);
if (most3[x1] > dwal[x1] && most3[x2] > dwal[x2])
{ // Done - does not work as well as I thought it would
//break;
}
if (j != 3 && (most3[x1] > up[x1] || most3[x2] > up[x2]))
{
for (int j = x1; j <= x2; ++j)
{
down[j] = clamp (most3[j], up[j], dwal[j]);
}
wallscan (x1, x2, up, down, swal, lwal);
up = down;
down = (down == most1) ? most2 : most1;
}
}
if (el->Lights[i].Master == NULL)
{
basecolormap = floodcolormap;
wallshade = floodshade;
fogginess = floodfoggy;
}
else
{
basecolormap = el->Lights[i].Master->ColorMap->Maps;
fogginess = level.fadeto || el->Lights[i].Master->ColorMap->Fade;
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(fogginess,
el->Lights[i].Master->lightlevel) + r_actualextralight);
if (el->Lights[i].bFlooder)
{
floodcolormap = basecolormap;
floodshade = wallshade;
flooding = true;
}
}
}
wallscan (x1, x2, up, dwal, swal, lwal);
basecolormap = startcolormap;
wallshade = startshade;
}
//
// R_RenderSegLoop
// Draws zero, one, or two textures for walls.
// Can draw or mark the starting pixel of floor and ceiling textures.
// CALLED: CORE LOOPING ROUTINE.
//
// [RH] Rewrote this to use Build's wallscan, so it's quite far
// removed from the original Doom routine.
//
void R_RenderSegLoop ()
{
int x1 = rw_x;
int x2 = rw_stopx;
int x;
int xscale;
fixed_t xoffset = rw_offset;
if (fixedlightlev)
dc_colormap = basecolormap + fixedlightlev;
else if (fixedcolormap)
dc_colormap = fixedcolormap;
// clip wall to the floor and ceiling
for (x = x1; x < x2; ++x)
{
if (walltop[x] < ceilingclip[x])
{
walltop[x] = ceilingclip[x];
}
if (wallbottom[x] > floorclip[x])
{
wallbottom[x] = floorclip[x];
}
}
// mark ceiling areas
if (markceiling)
{
for (x = x1; x < x2; ++x)
{
short top = ceilingclip[x];
short bottom = MIN (walltop[x], floorclip[x]);
if (top < bottom)
{
ceilingplane->top[x] = top;
ceilingplane->bottom[x] = bottom;
}
}
}
// mark floor areas
if (markfloor)
{
for (x = x1; x < x2; ++x)
{
short top = MAX (wallbottom[x], ceilingclip[x]);
short bottom = floorclip[x];
if (top < bottom)
{
floorplane->top[x] = top;
floorplane->bottom[x] = bottom;
}
}
}
// draw the wall tiers
if (midtexture)
{ // one sided line
if (midtexture->UseType != FTexture::TEX_Null && viewactive)
{
dc_texturemid = rw_midtexturemid;
rw_pic = midtexture;
xscale = rw_pic->ScaleX ? rw_pic->ScaleX : tx;
if (xscale != lwallscale)
{
PrepLWall (lwall, (curline->sidedef->TexelLength*xscale) << (FRACBITS-3));
lwallscale = xscale;
}
if (midtexture->bWorldPanning)
{
rw_offset = MulScale3 (xoffset, midtexture->ScaleX ? midtexture->ScaleX : tx);
}
if (fixedlightlev || fixedcolormap || !frontsector->ExtraLights)
{
wallscan (x1, x2-1, walltop, wallbottom, swall, lwall);
}
else
{
wallscan_striped (x1, x2-1, walltop, wallbottom, swall, lwall);
}
}
clearbufshort (ceilingclip+x1, x2-x1, viewheight);
clearbufshort (floorclip+x1, x2-x1, 0xffff);
}
else
{ // two sided line
if (toptexture != NULL && toptexture->UseType != FTexture::TEX_Null)
{ // top wall
for (x = x1; x < x2; ++x)
{
wallupper[x] = MAX (MIN (wallupper[x], floorclip[x]), walltop[x]);
}
if (viewactive)
{
dc_texturemid = rw_toptexturemid;
rw_pic = toptexture;
xscale = rw_pic->ScaleX ? rw_pic->ScaleX : tx;
if (xscale != lwallscale)
{
PrepLWall (lwall, (curline->sidedef->TexelLength*xscale) << (FRACBITS-3));
lwallscale = xscale;
}
if (toptexture->bWorldPanning)
{
rw_offset = MulScale3 (xoffset, toptexture->ScaleX ? toptexture->ScaleX : tx);
}
if (fixedlightlev || fixedcolormap || !frontsector->ExtraLights)
{
wallscan (x1, x2-1, walltop, wallupper, swall, lwall);
}
else
{
wallscan_striped (x1, x2-1, walltop, wallupper, swall, lwall);
}
}
memcpy (ceilingclip+x1, wallupper+x1, (x2-x1)*sizeof(short));
}
else if (markceiling)
{ // no top wall
memcpy (ceilingclip+x1, walltop+x1, (x2-x1)*sizeof(short));
}
if (bottomtexture != NULL && bottomtexture->UseType != FTexture::TEX_Null)
{ // bottom wall
for (x = x1; x < x2; ++x)
{
walllower[x] = MIN (MAX (walllower[x], ceilingclip[x]), wallbottom[x]);
}
if (viewactive)
{
dc_texturemid = rw_bottomtexturemid;
rw_pic = bottomtexture;
xscale = rw_pic->ScaleX ? rw_pic->ScaleX : tx;
if (xscale != lwallscale)
{
PrepLWall (lwall, (curline->sidedef->TexelLength*xscale) << (FRACBITS-3));
lwallscale = xscale;
}
if (bottomtexture->bWorldPanning)
{
rw_offset = MulScale3 (xoffset, bottomtexture->ScaleX ? bottomtexture->ScaleX : tx);
}
else
{
rw_offset = xoffset;
}
if (fixedlightlev || fixedcolormap || !frontsector->ExtraLights)
{
wallscan (x1, x2-1, walllower, wallbottom, swall, lwall);
}
else
{
wallscan_striped (x1, x2-1, walllower, wallbottom, swall, lwall);
}
}
memcpy (floorclip+x1, walllower+x1, (x2-x1)*sizeof(short));
}
else if (markfloor)
{ // no bottom wall
memcpy (floorclip+x1, wallbottom+x1, (x2-x1)*sizeof(short));
}
}
rw_offset = xoffset;
}
void R_NewWall (bool needlights)
{
fixed_t rowoffset;
rw_markmirror = false;
sidedef = curline->sidedef;
linedef = curline->linedef;
// mark the segment as visible for auto map
linedef->flags |= ML_MAPPED;
midtexture = toptexture = bottomtexture = 0;
if (backsector == NULL)
{
// single sided line
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
// [RH] Render mirrors later, but mark them now.
if (linedef->special != Line_Mirror || !r_drawmirrors)
{
// [RH] Horizon lines do not need to be textured
if (linedef->special != Line_Horizon)
{
midtexture = TexMan(sidedef->midtexture);
rowoffset = sidedef->rowoffset;
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
rw_midtexturemid = frontsector->floortexz + (midtexture->GetHeight() << FRACBITS);
}
else
{ // top of texture at top
rw_midtexturemid = frontsector->ceilingtexz;
if (rowoffset < 0 && midtexture != NULL)
{
rowoffset += midtexture->GetHeight() << FRACBITS;
}
}
if (midtexture->bWorldPanning)
{
rw_midtexturemid = MulScale3 (rw_midtexturemid - viewz + rowoffset,
midtexture->ScaleY ? midtexture->ScaleY : ty);
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
rw_midtexturemid = MulScale3 (rw_midtexturemid - viewz,
midtexture->ScaleY ? midtexture->ScaleY : ty)
+ rowoffset;
}
}
}
else
{
rw_markmirror = true;
}
}
else
{ // two-sided line
// hack to allow height changes in outdoor areas
rw_frontlowertop = frontsector->ceilingtexz;
if (frontsector->ceilingpic == skyflatnum &&
backsector->ceilingpic == skyflatnum)
{
if (rw_havehigh)
{ // front ceiling is above back ceiling
memcpy (&walltop[WallSX1], &wallupper[WallSX1], (WallSX2 - WallSX1)*sizeof(walltop[0]));
rw_havehigh = false;
}
else
{ // back ceiling is above front ceiling
// Recalculate walltop so that the wall is clipped by the back sector's
// ceiling instead of the front sector's ceiling.
WallMost (walltop, backsector->ceilingplane);
}
// Putting sky ceilins on the front and back of a line alters the way unpegged
// positioning works.
rw_frontlowertop = backsector->ceilingtexz;
}
if ((rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2) ||
(rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2))
{
// closed door
markceiling = markfloor = true;
}
else
{
markfloor = rw_mustmarkfloor
|| backsector->floorplane != frontsector->floorplane
|| backsector->lightlevel != frontsector->lightlevel
|| backsector->floorpic != frontsector->floorpic
// killough 3/7/98: Add checks for (x,y) offsets
|| backsector->floor_xoffs != frontsector->floor_xoffs
|| (backsector->floor_yoffs + backsector->base_floor_yoffs) != (frontsector->floor_yoffs + frontsector->base_floor_yoffs)
// killough 4/15/98: prevent 2s normals
// from bleeding through deep water
|| frontsector->heightsec
|| backsector->FloorLight != frontsector->FloorLight
|| backsector->FloorFlags != frontsector->FloorFlags
// [RH] Add checks for colormaps
|| backsector->ColorMap != frontsector->ColorMap
|| backsector->floor_xscale != frontsector->floor_xscale
|| backsector->floor_yscale != frontsector->floor_yscale
|| (backsector->floor_angle + backsector->base_floor_angle) != (frontsector->floor_angle + frontsector->base_floor_angle)
|| (sidedef->midtexture && linedef->flags & ML_CLIP_MIDTEX)
;
markceiling = (frontsector->ceilingpic != skyflatnum ||
backsector->ceilingpic != skyflatnum) &&
(rw_mustmarkceiling
|| backsector->ceilingplane != frontsector->ceilingplane
|| backsector->lightlevel != frontsector->lightlevel
|| backsector->ceilingpic != frontsector->ceilingpic
// killough 3/7/98: Add checks for (x,y) offsets
|| backsector->ceiling_xoffs != frontsector->ceiling_xoffs
|| (backsector->ceiling_yoffs + backsector->base_ceiling_yoffs) != (frontsector->ceiling_yoffs + frontsector->base_ceiling_yoffs)
// killough 4/15/98: prevent 2s normals
// from bleeding through fake ceilings
|| (frontsector->heightsec && frontsector->ceilingpic != skyflatnum)
|| backsector->CeilingLight != frontsector->CeilingLight
|| backsector->CeilingFlags != frontsector->CeilingFlags
// [RH] Add check for colormaps
|| backsector->ColorMap != frontsector->ColorMap
|| backsector->ceiling_xscale != frontsector->ceiling_xscale
|| backsector->ceiling_yscale != frontsector->ceiling_yscale
|| (backsector->ceiling_angle + backsector->base_ceiling_angle) != (frontsector->ceiling_angle + frontsector->base_ceiling_angle)
|| (sidedef->midtexture && linedef->flags & ML_CLIP_MIDTEX)
);
}
if (rw_havehigh)
{ // top texture
toptexture = TexMan(sidedef->toptexture);
const int scale = toptexture->ScaleY ? toptexture->ScaleY : ty;
rowoffset = sidedef->rowoffset;
if (linedef->flags & ML_DONTPEGTOP)
{ // top of texture at top
rw_toptexturemid = MulScale3 (frontsector->ceilingtexz - viewz, scale);
if (rowoffset < 0 && toptexture != NULL)
{
rowoffset += toptexture->GetHeight() << FRACBITS;
}
}
else
{ // bottom of texture at bottom
rw_toptexturemid = MulScale3 (backsector->ceilingtexz - viewz, scale) + (toptexture->GetHeight() << FRACBITS);
}
if (toptexture->bWorldPanning)
{
rw_toptexturemid += MulScale3 (rowoffset, scale);
}
else
{
rw_toptexturemid += rowoffset;
}
}
if (rw_havelow)
{ // bottom texture
bottomtexture = TexMan(sidedef->bottomtexture);
rowoffset = sidedef->rowoffset;
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
rw_bottomtexturemid = rw_frontlowertop;
}
else
{ // top of texture at top
rw_bottomtexturemid = backsector->floortexz;
if (rowoffset < 0 && bottomtexture != NULL)
{
rowoffset += bottomtexture->GetHeight() << FRACBITS;
}
}
if (bottomtexture->bWorldPanning)
{
rw_bottomtexturemid = MulScale3 (rw_bottomtexturemid - viewz + rowoffset,
bottomtexture->ScaleY ? bottomtexture->ScaleY : ty);
}
else
{
rw_bottomtexturemid = MulScale3 (rw_bottomtexturemid - viewz,
bottomtexture->ScaleY ? bottomtexture->ScaleY : ty)
+ rowoffset;
}
}
}
// if a floor / ceiling plane is on the wrong side of the view plane,
// it is definitely invisible and doesn't need to be marked.
// killough 3/7/98: add deep water check
if (frontsector->heightsec == NULL ||
(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
{
if (frontsector->floorplane.ZatPoint (viewx, viewy) >= viewz) // above view plane
markfloor = false;
if (frontsector->ceilingplane.ZatPoint (viewx, viewy) <= viewz &&
frontsector->ceilingpic != skyflatnum) // below view plane
markceiling = false;
}
segtextured = TexMan(sidedef->midtexture) != NULL || toptexture != NULL || bottomtexture != NULL;
// calculate light table
if (needlights && (segtextured || (backsector && IsFogBoundary (frontsector, backsector))))
{
lwallscale = TexMan(sidedef->midtexture) ? TexMan(sidedef->midtexture)->ScaleX :
toptexture ? toptexture->ScaleX :
bottomtexture ? bottomtexture->ScaleX : 0;
if (lwallscale == 0)
{
lwallscale = tx;
}
PrepWall (swall, lwall, (sidedef->TexelLength*lwallscale) << (FRACBITS-3));
if (!fixedcolormap)
{
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, frontsector->lightlevel)
+ r_actualextralight);
GlobVis = r_WallVisibility;
rw_lightleft = SafeDivScale12 (GlobVis, WallSZ1);
rw_lightstep = (SafeDivScale12 (GlobVis, WallSZ2) - rw_lightleft) / (WallSX2 - WallSX1);
}
else
{
rw_lightleft = FRACUNIT;
rw_lightstep = 0;
}
}
}
int side_s::GetLightLevel (bool foggy, int baselight) const
{
// [RH] Get wall light level
2006-04-11 16:27:41 +00:00
if (this->Flags & WALLF_ABSLIGHTING && (!(this->Flags & WALLF_AUTOCONTRAST) || foggy))
{
return (BYTE)this->Light;
}
else
{
if (!foggy) // Don't do relative lighting in foggy sectors
{
2006-04-11 16:27:41 +00:00
int rellight;
if (this->Flags & WALLF_AUTOCONTRAST)
{
baselight = (BYTE)this->Light;
rellight = linedef->dx==0? level.WallVertLight : linedef->dy==0 ? level.WallHorizLight : 0;
}
else
{
rellight = this->Light;
}
baselight += rellight * 2;
}
return baselight;
}
}
//
// R_CheckDrawSegs
//
void R_CheckDrawSegs ()
{
if (ds_p == &drawsegs[MaxDrawSegs])
{ // [RH] Grab some more drawsegs
size_t newdrawsegs = MaxDrawSegs ? MaxDrawSegs*2 : 32;
ptrdiff_t firstofs = firstdrawseg - drawsegs;
drawsegs = (drawseg_t *)Realloc (drawsegs, newdrawsegs * sizeof(drawseg_t));
firstdrawseg = drawsegs + firstofs;
ds_p = drawsegs + MaxDrawSegs;
MaxDrawSegs = newdrawsegs;
DPrintf ("MaxDrawSegs increased to %d\n", MaxDrawSegs);
}
}
//
// R_CheckOpenings
//
void R_CheckOpenings (size_t need)
{
need += lastopening;
if (need > maxopenings)
{
do
maxopenings = maxopenings ? maxopenings*2 : 16384;
while (need > maxopenings);
openings = (short *)Realloc (openings, maxopenings * sizeof(*openings));
DPrintf ("MaxOpenings increased to %u\n", maxopenings);
}
}
//
// R_StoreWallRange
// A wall segment will be drawn between start and stop pixels (inclusive).
//
void R_StoreWallRange (int start, int stop)
{
bool maskedtexture = false;
#ifdef RANGECHECK
if (start >= viewwidth || start >= stop)
I_FatalError ("Bad R_StoreWallRange: %i to %i", start , stop);
#endif
// don't overflow and crash
R_CheckDrawSegs ();
if (!rw_prepped)
{
rw_prepped = true;
R_NewWall (true);
}
rw_offset = sidedef->textureoffset;
rw_light = rw_lightleft + rw_lightstep * (start - WallSX1);
ds_p->sx1 = WallSX1;
ds_p->sx2 = WallSX2;
ds_p->sz1 = WallSZ1;
ds_p->sz2 = WallSZ2;
ds_p->siz1 = (DWORD)DivScale32 (1, WallSZ1) >> 1;
ds_p->siz2 = (DWORD)DivScale32 (1, WallSZ2) >> 1;
ds_p->x1 = rw_x = start;
ds_p->x2 = stop-1;
ds_p->curline = curline;
rw_stopx = stop;
ds_p->bFogBoundary = false;
// killough 1/6/98, 2/1/98: remove limit on openings
R_CheckOpenings ((stop - start)*6);
ds_p->sprtopclip = ds_p->sprbottomclip = ds_p->maskedtexturecol = ds_p->swall = -1;
if (rw_markmirror)
{
WallMirrors.Push (ds_p - drawsegs);
ds_p->silhouette = SIL_BOTH;
}
else if (backsector == NULL)
{
ds_p->sprtopclip = R_NewOpening (stop - start);
ds_p->sprbottomclip = R_NewOpening (stop - start);
clearbufshort (openings + ds_p->sprtopclip, stop-start, viewheight);
memset (openings + ds_p->sprbottomclip, -1, (stop-start)*sizeof(short));
ds_p->silhouette = SIL_BOTH;
}
else
{
// two sided line
ds_p->silhouette = 0;
if (rw_frontfz1 > rw_backfz1 || rw_frontfz2 > rw_backfz2 ||
backsector->floorplane.ZatPoint (viewx, viewy) > viewz)
{
ds_p->silhouette = SIL_BOTTOM;
}
if (rw_frontcz1 < rw_backcz1 || rw_frontcz2 < rw_backcz2 ||
backsector->ceilingplane.ZatPoint (viewx, viewy) < viewz)
{
ds_p->silhouette |= SIL_TOP;
}
// killough 1/17/98: this test is required if the fix
// for the automap bug (r_bsp.c) is used, or else some
// sprites will be displayed behind closed doors. That
// fix prevents lines behind closed doors with dropoffs
// from being displayed on the automap.
//
// killough 4/7/98: make doorclosed external variable
{
extern int doorclosed; // killough 1/17/98, 2/8/98, 4/7/98
if (doorclosed || (rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2))
{
ds_p->sprbottomclip = R_NewOpening (stop - start);
memset (openings + ds_p->sprbottomclip, -1, (stop-start)*sizeof(short));
ds_p->silhouette |= SIL_BOTTOM;
}
if (doorclosed || (rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2))
{ // killough 1/17/98, 2/8/98
ds_p->sprtopclip = R_NewOpening (stop - start);
clearbufshort (openings + ds_p->sprtopclip, stop - start, viewheight);
ds_p->silhouette |= SIL_TOP;
}
}
// allocate space for masked texture tables, if needed
// [RH] Don't just allocate the space; fill it in too.
if ((TexMan(sidedef->midtexture)->UseType != FTexture::TEX_Null || IsFogBoundary (frontsector, backsector)) &&
(rw_ceilstat != 12 || sidedef->toptexture == 0) &&
(rw_floorstat != 3 || sidedef->bottomtexture == 0) &&
(WallSZ1 >= TOO_CLOSE_Z && WallSZ2 >= TOO_CLOSE_Z))
{
fixed_t *swal;
short *lwal;
int i;
maskedtexture = true;
ds_p->bFogBoundary = IsFogBoundary (frontsector, backsector);
if (sidedef->midtexture != 0)
{
ds_p->maskedtexturecol = R_NewOpening (stop - start);
ds_p->swall = R_NewOpening ((stop - start) * 2);
lwal = openings + ds_p->maskedtexturecol;
swal = (fixed_t *)(openings + ds_p->swall);
int scaley = TexMan(sidedef->midtexture)->ScaleY ?
TexMan(sidedef->midtexture)->ScaleY : ty;
int xoffset = rw_offset;
for (i = start; i < stop; i++)
{
*lwal++ = (short)((lwall[i] + xoffset) >> FRACBITS);
*swal++ = MulScale5 (swall[i], scaley);
}
fixed_t istart = *((fixed_t *)(openings + ds_p->swall));
fixed_t iend = *(swal - 1);
if (istart < 3 && istart >= 0) istart = 3;
if (istart > -3 && istart < 0) istart = -3;
if (iend < 3 && iend >= 0) iend = 3;
if (iend > -3 && iend < 0) iend = -3;
istart = DivScale32 (1, istart);
iend = DivScale32 (1, iend);
ds_p->iscale = istart;
if (stop - start > 1)
{
ds_p->iscalestep = (iend - istart) / (stop - start - 1);
}
else
{
ds_p->iscalestep = 0;
}
}
ds_p->light = rw_light;
ds_p->lightstep = rw_lightstep;
ds_p->shade = wallshade;
if (ds_p->bFogBoundary || ds_p->maskedtexturecol != -1)
{
InterestingDrawsegs.Push (ds_p - drawsegs);
}
}
}
// render it
if (markceiling)
{
if (ceilingplane)
{ // killough 4/11/98: add NULL ptr checks
ceilingplane = R_CheckPlane (ceilingplane, start, stop-1);
}
else
{
markceiling = false;
}
}
if (markfloor)
{
if (floorplane)
{ // killough 4/11/98: add NULL ptr checks
floorplane = R_CheckPlane (floorplane, start, stop-1);
}
else
{
markfloor = false;
}
}
R_RenderSegLoop ();
// save sprite clipping info
if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && ds_p->sprtopclip == -1)
{
ds_p->sprtopclip = R_NewOpening (stop - start);
memcpy (openings + ds_p->sprtopclip, &ceilingclip[start], sizeof(short)*(stop-start));
}
if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && ds_p->sprbottomclip == -1)
{
ds_p->sprbottomclip = R_NewOpening (stop - start);
memcpy (openings + ds_p->sprbottomclip, &floorclip[start], sizeof(short)*(stop-start));
}
if (maskedtexture && curline->sidedef->midtexture != 0)
{
ds_p->silhouette |= SIL_TOP | SIL_BOTTOM;
}
// [RH] Draw any decals bound to the seg
2006-04-12 01:50:09 +00:00
for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
{
R_RenderDecal (curline->sidedef, decal, ds_p, 0);
}
ds_p++;
}
int OWallMost (short *mostbuf, fixed_t z)
{
int bad, y, ix1, ix2, iy1, iy2;
fixed_t s1, s2, s3, s4;
z = -(z >> 4);
s1 = MulScale16 (globaluclip, WallSZ1); s2 = MulScale16 (globaluclip, WallSZ2);
s3 = MulScale16 (globaldclip, WallSZ1); s4 = MulScale16 (globaldclip, WallSZ2);
bad = (z<s1)+((z<s2)<<1)+((z>s3)<<2)+((z>s4)<<3);
if ((bad&3) == 3)
{
memset (&mostbuf[WallSX1], 0, (WallSX2 - WallSX1)*sizeof(mostbuf[0]));
return bad;
}
if ((bad&12) == 12)
{
clearbufshort (&mostbuf[WallSX1], WallSX2 - WallSX1, viewheight);
return bad;
}
ix1 = WallSX1; iy1 = WallSZ1;
ix2 = WallSX2; iy2 = WallSZ2;
if (bad & 3)
{
int t = DivScale30 (z-s1, s2-s1);
int inty = WallSZ1 + MulScale30 (WallSZ2 - WallSZ1, t);
int xcross = WallSX1 + Scale (MulScale30 (WallSZ2, t), WallSX2 - WallSX1, inty);
if ((bad & 3) == 2)
{
if (WallSX1 <= xcross) { iy2 = inty; ix2 = xcross; }
if (WallSX2 > xcross) memset (&mostbuf[xcross], 0, (WallSX2-xcross)*sizeof(mostbuf[0]));
}
else
{
if (xcross <= WallSX2) { iy1 = inty; ix1 = xcross; }
if (xcross > WallSX1) memset (&mostbuf[WallSX1], 0, (xcross-WallSX1)*sizeof(mostbuf[0]));
}
}
if (bad & 12)
{
int t = DivScale30 (z-s3, s4-s3);
int inty = WallSZ1 + MulScale30 (WallSZ2 - WallSZ1, t);
int xcross = WallSX1 + Scale (MulScale30 (WallSZ2, t), WallSX2 - WallSX1, inty);
if ((bad & 12) == 8)
{
if (WallSX1 <= xcross) { iy2 = inty; ix2 = xcross; }
if (WallSX2 > xcross) clearbufshort (&mostbuf[xcross], WallSX2 - xcross, viewheight);
}
else
{
if (xcross <= WallSX2) { iy1 = inty; ix1 = xcross; }
if (xcross > WallSX1) clearbufshort (&mostbuf[WallSX1], xcross - WallSX1, viewheight);
}
}
y = Scale (z, InvZtoScale, iy1);
if (ix2 == ix1)
{
mostbuf[ix1] = (short)((y + centeryfrac) >> FRACBITS);
}
else
{
fixed_t yinc = (Scale (z, InvZtoScale, iy2) - y) / (ix2 - ix1);
qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac, yinc);
}
if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight;
if (mostbuf[ix2] < 0) mostbuf[ix2] = 0;
else if (mostbuf[ix2] > viewheight) mostbuf[ix2] = (short)viewheight;
return bad;
}
int WallMost (short *mostbuf, const secplane_t &plane)
{
if ((plane.a | plane.b) == 0)
{
return OWallMost (mostbuf, ((plane.c < 0) ? plane.d : -plane.d) - viewz);
}
fixed_t x, y, den, z1, z2, oz1, oz2;
fixed_t s1, s2, s3, s4;
int bad, ix1, ix2, iy1, iy2;
if (MirrorFlags & RF_XFLIP)
{
x = curline->v2->x;
y = curline->v2->y;
if (WallSX1 == 0 && 0 != (den = WallTX1 - WallTX2 + WallTY1 - WallTY2))
{
int frac = SafeDivScale30 (WallTY1 + WallTX1, den);
x -= MulScale30 (frac, x - curline->v1->x);
y -= MulScale30 (frac, y - curline->v1->y);
}
z1 = viewz - plane.ZatPoint (x, y);
if (WallSX2 > WallSX1 + 1)
{
x = curline->v1->x;
y = curline->v1->y;
if (WallSX2 == viewwidth && 0 != (den = WallTX1 - WallTX2 - WallTY1 + WallTY2))
{
int frac = SafeDivScale30 (WallTY2 - WallTX2, den);
x += MulScale30 (frac, curline->v2->x - x);
y += MulScale30 (frac, curline->v2->y - y);
}
z2 = viewz - plane.ZatPoint (x, y);
}
else
{
z2 = z1;
}
}
else
{
x = curline->v1->x;
y = curline->v1->y;
if (WallSX1 == 0 && 0 != (den = WallTX1 - WallTX2 + WallTY1 - WallTY2))
{
int frac = SafeDivScale30 (WallTY1 + WallTX1, den);
x += MulScale30 (frac, curline->v2->x - x);
y += MulScale30 (frac, curline->v2->y - y);
}
z1 = viewz - plane.ZatPoint (x, y);
if (WallSX2 > WallSX1 + 1)
{
x = curline->v2->x;
y = curline->v2->y;
if (WallSX2 == viewwidth && 0 != (den = WallTX1 - WallTX2 - WallTY1 + WallTY2))
{
int frac = SafeDivScale30 (WallTY2 - WallTX2, den);
x -= MulScale30 (frac, x - curline->v1->x);
y -= MulScale30 (frac, y - curline->v1->y);
}
z2 = viewz - plane.ZatPoint (x, y);
}
else
{
z2 = z1;
}
}
s1 = MulScale12 (globaluclip, WallSZ1); s2 = MulScale12 (globaluclip, WallSZ2);
s3 = MulScale12 (globaldclip, WallSZ1); s4 = MulScale12 (globaldclip, WallSZ2);
bad = (z1<s1)+((z2<s2)<<1)+((z1>s3)<<2)+((z2>s4)<<3);
ix1 = WallSX1; ix2 = WallSX2;
iy1 = WallSZ1; iy2 = WallSZ2;
oz1 = z1; oz2 = z2;
if ((bad&3) == 3)
{
memset (&mostbuf[ix1], -1, (ix2-ix1)*sizeof(mostbuf[0]));
return bad;
}
if ((bad&12) == 12)
{
clearbufshort (&mostbuf[ix1], ix2-ix1, viewheight);
return bad;
}
if (bad&3)
{
//inty = intz / (globaluclip>>16)
int t = SafeDivScale30 (oz1-s1, s2-s1+oz1-oz2);
int inty = WallSZ1 + MulScale30 (WallSZ2-WallSZ1,t);
int intz = oz1 + MulScale30 (oz2-oz1,t);
int xcross = WallSX1 + Scale (MulScale30 (WallSZ2, t), WallSX2-WallSX1, inty);
//t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4));
//inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
//intz = z1 + mulscale30(z2-z1,t);
if ((bad&3) == 2)
{
if (WallSX1 <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; }
memset (&mostbuf[xcross], 0, (WallSX2-xcross)*sizeof(mostbuf[0]));
}
else
{
if (xcross <= WallSX2) { z1 = intz; iy1 = inty; ix1 = xcross; }
memset (&mostbuf[WallSX1], 0, (xcross-WallSX1)*sizeof(mostbuf[0]));
}
}
if (bad&12)
{
//inty = intz / (globaldclip>>16)
int t = SafeDivScale30 (oz1-s3, s4-s3+oz1-oz2);
int inty = WallSZ1 + MulScale30 (WallSZ2-WallSZ1,t);
int intz = oz1 + MulScale30 (oz2-oz1,t);
int xcross = WallSX1 + Scale (MulScale30 (WallSZ2, t), WallSX2-WallSX1,inty);
//t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4));
//inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
//intz = z1 + mulscale30(z2-z1,t);
if ((bad&12) == 8)
{
if (WallSX1 <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; }
if (WallSX2 > xcross) clearbufshort (&mostbuf[xcross], WallSX2-xcross, viewheight);
}
else
{
if (xcross <= WallSX2) { z1 = intz; iy1 = inty; ix1 = xcross; }
if (xcross > WallSX1) clearbufshort (&mostbuf[WallSX1], xcross-WallSX1, viewheight);
}
}
y = Scale (z1>>4, InvZtoScale, iy1);
if (ix2 == ix1)
{
mostbuf[ix1] = (short)((y + centeryfrac) >> FRACBITS);
}
else
{
fixed_t yinc = (Scale (z2>>4, InvZtoScale, iy2) - y) / (ix2-ix1);
qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac,yinc);
}
if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight;
if (mostbuf[ix2] < 0) mostbuf[ix2] = 0;
else if (mostbuf[ix2] > viewheight) mostbuf[ix2] = (short)viewheight;
return bad;
}
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
{ // swall = scale, lwall = texturecolumn
int x;
float top, bot, i;
float xrepeat = (float)walxrepeat;
float ol, l, topinc, botinc;
i = (float)(WallSX1 - centerx);
top = WallUoverZorg + WallUoverZstep * i;
bot = WallInvZorg + WallInvZstep * i;
topinc = WallUoverZstep * 4.f;
botinc = WallInvZstep * 4.f;
x = WallSX1;
l = top / bot;
swall[x] = quickertoint (l * WallDepthScale + WallDepthOrg);
lwall[x] = quickertoint (l * xrepeat);
// As long as l is invalid, step one column at a time so that
// we can get as many correct texture columns as possible.
while (l > 1.0 && x+1 < WallSX2)
{
l = (top += WallUoverZstep) / (bot += WallInvZstep);
x++;
swall[x] = quickertoint (l * WallDepthScale + WallDepthOrg);
lwall[x] = quickertoint (l * xrepeat);
}
l *= xrepeat;
while (x+4 < WallSX2)
{
top += topinc; bot += botinc;
ol = l; l = top / bot;
swall[x+4] = quickertoint (l * WallDepthScale + WallDepthOrg);
lwall[x+4] = quickertoint (l *= xrepeat);
i = (ol+l) * 0.5f;
lwall[x+2] = quickertoint (i);
lwall[x+1] = quickertoint ((ol+i) * 0.5f);
lwall[x+3] = quickertoint ((l+i) * 0.5f);
swall[x+2] = ((swall[x]+swall[x+4])>>1);
swall[x+1] = ((swall[x]+swall[x+2])>>1);
swall[x+3] = ((swall[x+4]+swall[x+2])>>1);
x += 4;
}
if (x+2 < WallSX2)
{
top += topinc * 0.5f; bot += botinc * 0.5f;
ol = l; l = top / bot;
swall[x+2] = quickertoint (l * WallDepthScale + WallDepthOrg);
lwall[x+2] = quickertoint (l *= xrepeat);
lwall[x+1] = quickertoint ((l+ol)*0.5f);
swall[x+1] = (swall[x]+swall[x+2])>>1;
x += 2;
}
if (x+1 < WallSX2)
{
l = (top + WallUoverZstep) / (bot + WallInvZstep);
swall[x+1] = quickertoint (l * WallDepthScale + WallDepthOrg);
lwall[x+1] = quickertoint (l * xrepeat);
}
/*
for (x = WallSX1; x < WallSX2; x++)
{
frac = top / bot;
lwall[x] = quickertoint (frac * xrepeat);
swall[x] = quickertoint (frac * WallDepthScale + WallDepthOrg);
top += WallUoverZstep;
bot += WallInvZstep;
}
*/
// fix for rounding errors
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
if (WallSX1 > 0)
{
for (x = WallSX1; x < WallSX2; x++)
{
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
{
lwall[x] = fix;
}
else
{
break;
}
}
}
fix = walxrepeat - 1 - fix;
for (x = WallSX2-1; x >= WallSX1; x--)
{
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
{
lwall[x] = fix;
}
else
{
break;
}
}
}
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat)
{ // lwall = texturecolumn
int x;
float top, bot, i;
float xrepeat = (float)walxrepeat;
float ol, l, topinc, botinc;
i = (float)(WallSX1 - centerx);
top = WallUoverZorg + WallUoverZstep * i;
bot = WallInvZorg + WallInvZstep * i;
topinc = WallUoverZstep * 4.f;
botinc = WallInvZstep * 4.f;
x = WallSX1;
l = top / bot;
lwall[x] = quickertoint (l * xrepeat);
// As long as l is invalid, step one column at a time so that
// we can get as many correct texture columns as possible.
while (l > 1.0 && x+1 < WallSX2)
{
l = (top += WallUoverZstep) / (bot += WallInvZstep);
lwall[++x] = quickertoint (l * xrepeat);
}
l *= xrepeat;
while (x+4 < WallSX2)
{
top += topinc; bot += botinc;
ol = l; l = top / bot;
lwall[x+4] = quickertoint (l *= xrepeat);
i = (ol+l) * 0.5f;
lwall[x+2] = quickertoint (i);
lwall[x+1] = quickertoint ((ol+i) * 0.5f);
lwall[x+3] = quickertoint ((l+i) * 0.5f);
x += 4;
}
if (x+2 < WallSX2)
{
top += topinc * 0.5f; bot += botinc * 0.5f;
ol = l; l = top / bot;
lwall[x+2] = quickertoint (l *= xrepeat);
lwall[x+1] = quickertoint ((l+ol)*0.5f);
x += 2;
}
if (x+1 < WallSX2)
{
l = (top + WallUoverZstep) / (bot + WallInvZstep);
lwall[x+1] = quickertoint (l * xrepeat);
}
// fix for rounding errors
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
if (WallSX1 > 0)
{
for (x = WallSX1; x < WallSX2; x++)
{
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
{
lwall[x] = fix;
}
else
{
break;
}
}
}
fix = walxrepeat - 1 - fix;
for (x = WallSX2-1; x >= WallSX1; x--)
{
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
{
lwall[x] = fix;
}
else
{
break;
}
}
}
// pass = 0: when seg is first drawn
// = 1: drawing masked textures (including sprites)
// Currently, only pass = 0 is done or used
static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, int pass)
{
fixed_t lx, ly, lx2, ly2, decalx, decaly;
int x1, x2;
fixed_t xscale, yscale;
fixed_t topoff;
byte flipx;
fixed_t zpos;
int needrepeat = 0;
sector_t *front, *back;
2006-04-12 01:50:09 +00:00
if (decal->RenderFlags & RF_INVISIBLE || !viewactive || decal->PicNum == 0xFFFF)
return;
// Determine actor z
zpos = decal->Z;
front = curline->frontsector;
back = (curline->backsector != NULL) ? curline->backsector : curline->frontsector;
2006-04-12 01:50:09 +00:00
switch (decal->RenderFlags & RF_RELMASK)
{
default:
zpos = decal->Z;
break;
case RF_RELUPPER:
if (curline->linedef->flags & ML_DONTPEGTOP)
{
zpos = decal->Z + front->ceilingtexz;
}
else
{
zpos = decal->Z + back->ceilingtexz;
}
break;
case RF_RELLOWER:
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
zpos = decal->Z + front->ceilingtexz;
}
else
{
zpos = decal->Z + back->floortexz;
}
break;
case RF_RELMID:
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
zpos = decal->Z + front->floortexz;
}
else
{
zpos = decal->Z + front->ceilingtexz;
}
}
xscale = decal->ScaleX;
yscale = decal->ScaleY;
2006-04-12 01:50:09 +00:00
WallSpriteTile = TexMan(decal->PicNum);
May 3, 2006 (Changes by Graf Zahl) - Removed doom.x, heretic.x and strife.x from the SVN repository. These are generated files. - Fixed: A_PainDie has to check whether a valid target exists before calling IsFriend. - Fixed: FDecalLib::FindAnimator needs a signed counter to work properly. May 1, 2006 (Changes by Graf Zahl) - Added support for game specific pickup messages, if only to be able to define Raven's invulnerability item in DECORATE. - Removed A_TreeDeath because it is no longer used. - Fixed: When picking up a PowerupGiver for an active powerup the blend color and the duration were transferred to a temorary item and never took effect. They have to be trnasferred to the newly created powerup item before trying to give it to the player, not afterward. - Made the colormap of the InvulnerabilitySphere item specific. The base power class still needs to have its color adjusted per game though and since Raven's invulnerability item is used in both Hexen and Heretic it can't define its own colormap/blend. - Separated the invulnerability colormaps from the game being played and made them item specific. They can also be specified as regular blend colors in DECORATE now. - Converted a_hereticarmor.cpp and most of a_doomartifacts.cpp, a_hereticartifacts.cpp and a_heretickeys.cpp to DECORATE. - Changed the Soulsphere to be a real health item with the Dehacked modifications made in d_dehacked.cpp as for most other items which need to be adjusted. - Added IF_BIGPOWERUP flag to AInventory to expose the RESPAWN_SUPER dmflag to DECORATE. Also removed the now obsolete ShouldRespawn methods from AInvulnerabilitySphere and ABlurSphere. - Converted a_splashes.cpp to DECORATE. - Converted most of a_debris.cpp to DECORATE. SVN r73 (trunk)
2006-05-03 14:54:48 +00:00
flipx = (byte)(decal->RenderFlags & RF_XFLIP);
if (WallSpriteTile->UseType == FTexture::TEX_Null)
{
return;
}
// Determine left and right edges of sprite. Since this sprite is bound
2006-04-12 01:50:09 +00:00
// to a wall, we use the wall's angle instead of the decal's. This is
// pretty much the same as what R_AddLine() does.
x2 = WallSpriteTile->GetWidth();
x1 = WallSpriteTile->LeftOffset;
x2 = x2 - x1;
x1 *= xscale;
x2 *= xscale;
decal->GetXY (wall, decalx, decaly);
angle_t ang = R_PointToAngle2 (curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y) >> ANGLETOFINESHIFT;
lx = decalx - FixedMul (x1, finecosine[ang]) - viewx;
lx2 = decalx + FixedMul (x2, finecosine[ang]) - viewx;
ly = decaly - FixedMul (x1, finesine[ang]) - viewy;
ly2 = decaly + FixedMul (x2, finesine[ang]) - viewy;
WallTX1 = DMulScale20 (lx, viewsin, -ly, viewcos);
WallTX2 = DMulScale20 (lx2, viewsin, -ly2, viewcos);
WallTY1 = DMulScale20 (lx, viewtancos, ly, viewtansin);
WallTY2 = DMulScale20 (lx2, viewtancos, ly2, viewtansin);
if (MirrorFlags & RF_XFLIP)
{
int t = 256-WallTX1;
WallTX1 = 256-WallTX2;
WallTX2 = t;
swap (WallTY1, WallTY2);
}
if (WallTX1 >= -WallTY1)
{
if (WallTX1 > WallTY1) return; // left edge is off the right side
if (WallTY1 == 0) return;
x1 = (centerxfrac + Scale (WallTX1, centerxfrac, WallTY1)) >> FRACBITS;
if (WallTX1 >= 0) x1 = MIN (viewwidth, x1+1); // fix for signed divide
WallSZ1 = WallTY1;
}
else
{
if (WallTX2 < -WallTY2) return; // wall is off the left side
fixed_t den = WallTX1 - WallTX2 - WallTY2 + WallTY1;
if (den == 0) return;
x1 = 0;
WallSZ1 = WallTY1 + Scale (WallTY2 - WallTY1, WallTX1 + WallTY1, den);
}
if (WallSZ1 < TOO_CLOSE_Z)
return;
if (WallTX2 <= WallTY2)
{
if (WallTX2 < -WallTY2) return; // right edge is off the left side
if (WallTY2 == 0) return;
x2 = (centerxfrac + Scale (WallTX2, centerxfrac, WallTY2)) >> FRACBITS;
if (WallTX2 >= 0) x2 = MIN (viewwidth, x2+1); // fix for signed divide
WallSZ2 = WallTY2;
}
else
{
if (WallTX1 > WallTY1) return; // wall is off the right side
fixed_t den = WallTY2 - WallTY1 - WallTX2 + WallTX1;
if (den == 0) return;
x2 = viewwidth;
WallSZ2 = WallTY1 + Scale (WallTY2 - WallTY1, WallTX1 - WallTY1, den);
}
if (x1 >= x2 || x1 > clipper->x2 || x2 <= clipper->x1 || WallSZ2 < TOO_CLOSE_Z)
return;
if (MirrorFlags & RF_XFLIP)
{
WallUoverZorg = (float)WallTX2 * WallTMapScale;
WallUoverZstep = (float)(-WallTY2) * 32.f;
WallInvZorg = (float)(WallTX2 - WallTX1) * WallTMapScale;
WallInvZstep = (float)(WallTY1 - WallTY2) * 32.f;
}
else
{
WallUoverZorg = (float)WallTX1 * WallTMapScale;
WallUoverZstep = (float)(-WallTY1) * 32.f;
WallInvZorg = (float)(WallTX1 - WallTX2) * WallTMapScale;
WallInvZstep = (float)(WallTY2 - WallTY1) * 32.f;
}
WallDepthScale = WallInvZstep * WallTMapScale2;
WallDepthOrg = -WallUoverZstep * WallTMapScale2;
// Get the top and bottom clipping arrays
2006-04-12 01:50:09 +00:00
switch (decal->RenderFlags & RF_CLIPMASK)
{
case RF_CLIPFULL:
if (curline->backsector == NULL)
{
if (pass != 0)
{
return;
}
mceilingclip = walltop;
mfloorclip = wallbottom;
}
else if (pass == 0)
{
mceilingclip = walltop;
mfloorclip = ceilingclip;
needrepeat = 1;
}
else
{
mceilingclip = openings + clipper->sprtopclip - clipper->x1;
mfloorclip = openings + clipper->sprbottomclip - clipper->x1;
}
break;
case RF_CLIPUPPER:
if (pass != 0)
{
return;
}
mceilingclip = walltop;
mfloorclip = ceilingclip;
break;
case RF_CLIPMID:
if (curline->backsector != NULL && pass != 2)
{
return;
}
mceilingclip = openings + clipper->sprtopclip - clipper->x1;
mfloorclip = openings + clipper->sprbottomclip - clipper->x1;
break;
case RF_CLIPLOWER:
if (pass != 0)
{
return;
}
mceilingclip = floorclip;
mfloorclip = wallbottom;
break;
}
topoff = WallSpriteTile->TopOffset << FRACBITS;
dc_texturemid = topoff + FixedDiv (zpos - viewz, yscale);
// Clip sprite to drawseg
if (x1 < clipper->x1)
{
x1 = clipper->x1;
}
if (x2 > clipper->x2)
{
x2 = clipper->x2 + 1;
}
if (x1 >= x2)
{
return;
}
swap (x1, WallSX1);
swap (x2, WallSX2);
PrepWall (swall, lwall, WallSpriteTile->GetWidth() << FRACBITS);
swap (x1, WallSX1);
swap (x2, WallSX2);
if (flipx)
{
int i;
int right = (WallSpriteTile->GetWidth() << FRACBITS) - 1;
for (i = x1; i < x2; i++)
{
lwall[i] = right - lwall[i];
}
}
// Prepare lighting
bool calclighting = false;
rw_light = rw_lightleft + (x1 - WallSX1) * rw_lightstep;
if (fixedlightlev)
dc_colormap = basecolormap + fixedlightlev;
else if (fixedcolormap)
dc_colormap = fixedcolormap;
2006-04-12 01:50:09 +00:00
else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT))
dc_colormap = basecolormap;
else
calclighting = true;
// Draw it
2006-04-12 01:50:09 +00:00
if (decal->RenderFlags & RF_YFLIP)
{
sprflipvert = true;
yscale = -yscale;
dc_texturemid = dc_texturemid - (WallSpriteTile->GetHeight() << FRACBITS);
}
else
{
sprflipvert = false;
}
// rw_offset is used as the texture's vertical scale
rw_offset = SafeDivScale30(1, yscale);
do
{
dc_x = x1;
ESPSResult mode;
2006-04-12 01:50:09 +00:00
mode = R_SetPatchStyle (decal->RenderStyle, decal->Alpha, decal->Translation, decal->AlphaColor);
if (mode == DontDraw)
{
needrepeat = 0;
}
else
{
int stop4;
if (mode == DoDraw0)
{ // 1 column at a time
stop4 = dc_x;
}
else // DoDraw1
{ // up to 4 columns at a time
stop4 = x2 & ~3;
}
while ((dc_x < stop4) && (dc_x & 3))
{
if (calclighting)
{ // calculate lighting
dc_colormap = basecolormap + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
WallSpriteColumn (R_DrawMaskedColumn);
dc_x++;
}
while (dc_x < stop4)
{
if (calclighting)
{ // calculate lighting
dc_colormap = basecolormap + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
rt_initcols();
for (int zz = 4; zz; --zz)
{
WallSpriteColumn (R_DrawMaskedColumnHoriz);
dc_x++;
}
rt_draw4cols (dc_x - 4);
}
while (dc_x < x2)
{
if (calclighting)
{ // calculate lighting
dc_colormap = basecolormap + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
WallSpriteColumn (R_DrawMaskedColumn);
dc_x++;
}
}
// If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will
// be set 1 if we need to draw on the lower wall. In all other cases,
// needrepeat will be 0, and the while will fail.
mceilingclip = floorclip;
mfloorclip = wallbottom;
R_FinishSetPatchStyle ();
} while (needrepeat--);
colfunc = basecolfunc;
hcolfunc_post1 = rt_map1col;
hcolfunc_post4 = rt_map4cols;
R_FinishSetPatchStyle ();
}
static void WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans))
{
unsigned int texturecolumn = lwall[dc_x] >> FRACBITS;
dc_iscale = MulScale16 (swall[dc_x], rw_offset);
spryscale = SafeDivScale32 (1, dc_iscale);
if (sprflipvert)
sprtopscreen = centeryfrac + FixedMul (dc_texturemid, spryscale);
else
sprtopscreen = centeryfrac - FixedMul (dc_texturemid, spryscale);
const BYTE *column;
const FTexture::Span *spans;
column = WallSpriteTile->GetColumn (texturecolumn, &spans);
drawfunc (column, spans);
rw_light += rw_lightstep;
}