Q&D port of decal code to draw generic wall sprites

- This still doesn't use all the sprite properties correctly. It also
  looks like they're going to need different code to build the clipping
  arrays. But at least wall sprites are drawn at the proper angle now!
This commit is contained in:
Randy Heit 2014-08-02 22:35:57 -05:00
parent 15251e7a21
commit d0043bed78
5 changed files with 279 additions and 47 deletions

View file

@ -26,6 +26,11 @@
#include "tarray.h"
#include <stddef.h>
// 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
struct FWallCoords
{
fixed_t TX1, TX2; // x coords at left, right of wall in view space
@ -51,6 +56,9 @@ struct FWallTmapVals
void InitDepth();
};
extern FWallCoords WallC;
extern FWallTmapVals WallT;
enum
{
FAKED_Center,

View file

@ -64,11 +64,6 @@ CVAR(Bool, r_np2, true, 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;
@ -86,10 +81,6 @@ fixed_t rw_offset_top;
fixed_t rw_offset_mid;
fixed_t rw_offset_bottom;
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat, int x1, int x2);
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat, int x1, int x2);
extern FWallCoords WallC;
extern FWallTmapVals WallT;
int wallshade;
@ -139,7 +130,6 @@ static fixed_t rw_bottomtexturescaley;
FTexture *rw_pic;
static fixed_t *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));
@ -3216,8 +3206,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
{ // calculate lighting
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
WallSpriteColumn (R_DrawMaskedColumn);
R_WallSpriteColumn (R_DrawMaskedColumn);
dc_x++;
}
@ -3230,7 +3219,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
rt_initcols();
for (int zz = 4; zz; --zz)
{
WallSpriteColumn (R_DrawMaskedColumnHoriz);
R_WallSpriteColumn (R_DrawMaskedColumnHoriz);
dc_x++;
}
rt_draw4cols (dc_x - 4);
@ -3242,8 +3231,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
{ // calculate lighting
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
WallSpriteColumn (R_DrawMaskedColumn);
R_WallSpriteColumn (R_DrawMaskedColumn);
dc_x++;
}
}
@ -3264,21 +3252,3 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
done:
WallC = savecoord;
}
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);
dc_texturefrac = 0;
drawfunc (column, spans);
rw_light += rw_lightstep;
}

View file

@ -33,6 +33,8 @@ extern size_t maxopenings;
int OWallMost (short *mostbuf, fixed_t z, const FWallCoords *wallc);
int WallMost (short *mostbuf, const secplane_t &plane, const FWallCoords *wallc);
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat, int x1, int x2);
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat, int x1, int x2);
ptrdiff_t R_NewOpening (ptrdiff_t len);
@ -40,4 +42,11 @@ void R_CheckDrawSegs ();
void R_RenderSegLoop ();
extern fixed_t swall[MAXWIDTH];
extern fixed_t lwall[MAXWIDTH];
extern fixed_t rw_light; // [RH] Scale lights with viewsize adjustments
extern fixed_t rw_lightstep;
extern fixed_t rw_lightleft;
extern fixed_t rw_offset;
#endif

View file

@ -114,6 +114,8 @@ FDynamicColormap *VisPSpritesBaseColormap[NUMPSPRITES];
static int spriteshade;
FTexture *WallSpriteTile;
// constant arrays
// used for psprite clipping and initializing clipping
short zeroarray[MAXWIDTH];
@ -145,6 +147,8 @@ static vissprite_t **spritesorter;
static int spritesortersize = 0;
static int vsprcount;
static void R_ProjectWallSprite(AActor *thing, fixed_t fx, fixed_t fy, fixed_t fz, FTextureID picnum, fixed_t xscale, fixed_t yscale, INTBOOL flip);
void R_DeinitSprites()
{
@ -401,6 +405,151 @@ void R_DrawVisSprite (vissprite_t *vis)
NetUpdate ();
}
void R_DrawWallSprite(vissprite_t *spr)
{
int x1, x2;
fixed_t yscale;
int shade = LIGHT2SHADE(140);
x1 = MAX<int>(spr->x1, spr->wallc.SX1);
x2 = MIN<int>(spr->x2, spr->wallc.SX2 + 1);
if (x1 >= x2)
return;
WallT.InitFromWallCoords(&spr->wallc);
PrepWall(swall, lwall, spr->pic->GetWidth() << FRACBITS, x1, x2);
dc_texturemid = spr->gzt - viewz;
yscale = FRACUNIT;
if (spr->renderflags & RF_XFLIP)
{
int right = (spr->pic->GetWidth() << FRACBITS) - 1;
for (int i = x1; i < x2; i++)
{
lwall[i] = right - lwall[i];
}
}
// Prepare lighting
bool calclighting = false;
FDynamicColormap *usecolormap = basecolormap;
bool rereadcolormap = true;
// Decals that are added to the scene must fade to black.
if (spr->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0)
{
usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
rereadcolormap = false;
}
rw_light = rw_lightleft + (x1 - spr->wallc.SX1) * rw_lightstep;
if (fixedlightlev >= 0)
dc_colormap = usecolormap->Maps + fixedlightlev;
else if (fixedcolormap != NULL)
dc_colormap = fixedcolormap;
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
dc_colormap = usecolormap->Maps;
else
calclighting = true;
// Draw it
WallSpriteTile = spr->pic;
if (spr->renderflags & RF_YFLIP)
{
sprflipvert = true;
yscale = -yscale;
dc_texturemid = dc_texturemid - (spr->pic->GetHeight() << FRACBITS);
}
else
{
sprflipvert = false;
}
// rw_offset is used as the texture's vertical scale
rw_offset = SafeDivScale30(1, yscale);
dc_x = x1;
ESPSResult mode;
mode = R_SetPatchStyle (spr->Style.RenderStyle, spr->Style.alpha, spr->Translation, spr->FillColor);
// R_SetPatchStyle can modify basecolormap.
if (rereadcolormap)
{
usecolormap = basecolormap;
}
if (mode == DontDraw)
{
return;
}
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 = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
}
R_WallSpriteColumn(R_DrawMaskedColumn);
dc_x++;
}
while (dc_x < stop4)
{
if (calclighting)
{ // calculate lighting
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
}
rt_initcols();
for (int zz = 4; zz; --zz)
{
R_WallSpriteColumn(R_DrawMaskedColumnHoriz);
dc_x++;
}
rt_draw4cols(dc_x - 4);
}
while (dc_x < x2)
{
if (calclighting)
{ // calculate lighting
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
}
R_WallSpriteColumn(R_DrawMaskedColumn);
dc_x++;
}
}
R_FinishSetPatchStyle();
}
void R_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);
dc_texturefrac = 0;
drawfunc (column, spans);
rw_light += rw_lightstep;
}
void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop, short *clipbot)
{
ESPSResult mode;
@ -521,12 +670,6 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
fy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY);
fz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ) + thing->GetBobOffset(r_TicFrac);
// transform the origin point
tr_x = fx - viewx;
tr_y = fy - viewy;
tz = DMulScale20 (tr_x, viewtancos, tr_y, viewtansin);
tex = NULL;
voxel = NULL;
@ -618,6 +761,18 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
return;
}
if ((thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
{
R_ProjectWallSprite(thing, fx, fy, fz, picnum, spritescaleX, spritescaleY, flip);
return;
}
// transform the origin point
tr_x = fx - viewx;
tr_y = fy - viewy;
tz = DMulScale20 (tr_x, viewtancos, tr_y, viewtansin);
// thing is behind view plane?
if (voxel == NULL && tz < MINZ)
return;
@ -782,7 +937,6 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
vis->heightsec = heightsec;
vis->sector = thing->Sector;
vis->cx = tx2;
vis->depth = tz;
vis->gx = fx;
vis->gy = fy;
@ -807,12 +961,14 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
{
vis->voxel = voxel->Voxel;
vis->bIsVoxel = true;
vis->bWallSprite = false;
DrewAVoxel = true;
}
else
{
vis->pic = tex;
vis->bIsVoxel = false;
vis->bWallSprite = false;
}
// The software renderer cannot invert the source without inverting the overlay
@ -874,6 +1030,78 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
}
}
static void R_ProjectWallSprite(AActor *thing, fixed_t fx, fixed_t fy, fixed_t fz, FTextureID picnum, fixed_t xscale, fixed_t yscale, INTBOOL flip)
{
FWallCoords wallc;
int x1, x2;
fixed_t lx1, lx2, ly1, ly2;
fixed_t gzb, gzt, tz;
FTexture *pic = TexMan(picnum, true);
angle_t ang = (thing->angle + ANGLE_90) >> ANGLETOFINESHIFT;
vissprite_t *vis;
// Determine left and right edges of sprite. The sprite's angle is its normal,
// so the edges are 90 degrees each side of it.
x2 = pic->GetScaledWidth();
x1 = pic->GetScaledLeftOffset();
x1 *= xscale;
x2 *= xscale;
lx1 = fx - FixedMul(x1, finecosine[ang]) - viewx;
ly1 = fy - FixedMul(x1, finesine[ang]) - viewy;
lx2 = lx1 + FixedMul(x2, finecosine[ang]);
ly2 = ly1 + FixedMul(x2, finesine[ang]);
// Is it off-screen?
if (wallc.Init(lx1, ly1, lx2, ly2, TOO_CLOSE_Z))
return;
if (wallc.SX1 > WindowRight || wallc.SX2 <= WindowLeft)
return;
// Sprite sorting should probably treat these as walls, not sprites,
// but right now, I just want to get them drawing.
tz = DMulScale20(fx - viewx, viewtancos, fy - viewy, viewtansin);
int scaled_to = pic->GetScaledTopOffset();
int scaled_bo = scaled_to - pic->GetScaledHeight();
gzt = fz + yscale * scaled_to;
gzb = fz + yscale * scaled_bo;
vis = R_NewVisSprite();
vis->x1 = wallc.SX1 < WindowLeft ? WindowLeft : wallc.SX1;
vis->x2 = wallc.SX2 >= WindowRight ? WindowRight-1 : wallc.SX2-1;
vis->idepth = (unsigned)DivScale32(1, tz) >> 1;
vis->depth = tz;
vis->sector = thing->Sector;
vis->heightsec = NULL;
vis->gx = fx;
vis->gy = fy;
vis->gz = fz;
vis->gzb = gzb;
vis->gzt = gzt;
vis->deltax = fx - viewx;
vis->deltay = fy - viewy;
vis->renderflags = thing->renderflags;
if(thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D
vis->Style.RenderStyle = thing->RenderStyle;
vis->FillColor = thing->fillcolor;
vis->Translation = thing->Translation;
vis->FakeFlatStat = 0;
vis->Style.alpha = thing->alpha;
vis->fakefloor = NULL;
vis->fakeceiling = NULL;
vis->ColormapNum = 0;
vis->bInMirror = MirrorFlags & RF_XFLIP;
vis->pic = pic;
vis->bIsVoxel = false;
vis->bWallSprite = true;
vis->ColormapNum = GETPALOOKUP(
(fixed_t)DivScale12 (r_SpriteVisibility, MAX(tz, MINZ)), spriteshade);
vis->Style.colormap = basecolormap->Maps + (vis->ColormapNum << COLORMAPSHIFT);
vis->wallc = wallc;
}
//
// R_AddSprites
@ -1904,9 +2132,16 @@ void R_DrawSprite (vissprite_t *spr)
{
mfloorclip = clipbot;
mceilingclip = cliptop;
if (!spr->bWallSprite)
{
R_DrawVisSprite(spr);
}
else
{
R_DrawWallSprite(spr);
}
}
else
{
// If it is completely clipped away, don't bother drawing it.
if (cliptop[x2] >= clipbot[x2])
@ -2161,7 +2396,6 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
vis->yscale = xscale;
vis->depth = tz;
vis->idepth = (DWORD)DivScale32 (1, tz) >> 1;
vis->cx = tx;
vis->gx = particle->x;
vis->gy = particle->y;
vis->gz = particle->z; // kg3D

View file

@ -23,6 +23,7 @@
#ifndef __R_THINGS__
#define __R_THINGS__
#include "r_bsp.h"
// A vissprite_t is a thing
// that will be drawn during a refresh.
@ -31,7 +32,6 @@
struct vissprite_t
{
short x1, x2;
fixed_t cx; // for line side calculation
fixed_t gx, gy, gz; // origin in world coordinates
angle_t angle;
fixed_t gzb, gzt; // global bottom / top for silhouette clipping
@ -43,18 +43,26 @@ struct vissprite_t
fixed_t floorclip;
union
{
// Used by regular sprites
FTexture *pic;
struct FVoxel *voxel;
};
union
{
// Used by face sprites
struct
{
FTexture *pic;
fixed_t texturemid;
fixed_t startfrac; // horizontal position of x1
fixed_t xiscale; // negative if flipped
};
// Used by wall sprites
struct
{
FWallCoords wallc;
};
// Used by voxels
struct
{
struct FVoxel *voxel;
fixed_t vx, vy, vz; // view origin
angle_t vang; // view angle
};
@ -64,6 +72,7 @@ struct vissprite_t
F3DFloor *fakefloor;
F3DFloor *fakeceiling;
BYTE bIsVoxel:1; // [RH] Use voxel instead of pic
BYTE bWallSprite:1; // [RH] This is a wall sprite
BYTE bSplitSprite:1; // [RH] Sprite was split by a drawseg
BYTE bInMirror:1; // [RH] Sprite is "inside" a mirror
BYTE FakeFlatStat; // [RH] which side of fake/floor ceiling sprite is on
@ -99,9 +108,11 @@ extern fixed_t pspritexscale;
extern fixed_t pspriteyscale;
extern fixed_t pspritexiscale;
extern FTexture *WallSpriteTile;
void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans);
void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans));
void R_CacheSprite (spritedef_t *sprite);
void R_SortVisSprites (int (STACK_ARGS *compare)(const void *, const void *), size_t first);