SRB2/src/r_splats.c

400 lines
9 KiB
C
Raw Normal View History

2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
2020-02-19 22:08:45 +00:00
// Copyright (C) 1999-2020 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// 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_splats.c
/// \brief Floor splats
2014-03-15 16:59:03 +00:00
#include "r_draw.h"
#include "r_main.h"
#include "r_splats.h"
#include "r_bsp.h"
2014-03-15 16:59:03 +00:00
#include "w_wad.h"
#include "z_zone.h"
struct rastery_s *prastertab; // for ASM code
2014-03-15 16:59:03 +00:00
#ifdef FLOORSPLATS
static struct rastery_s rastertab[MAXVIDHEIGHT];
static void prepare_rastertab(void);
UINT8 ds_splatclip[MAXVIDWIDTH];
2014-03-15 16:59:03 +00:00
// ==========================================================================
// FLOOR SPLATS
2014-03-15 16:59:03 +00:00
// ==========================================================================
#ifdef USEASM
void ASMCALL rasterize_segment_tex_asm(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir);
#endif
2014-03-15 16:59:03 +00:00
// Lactozilla
static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir)
2014-03-15 16:59:03 +00:00
{
#ifdef USEASM
if (R_ASM)
{
rasterize_segment_tex_asm(x1, y1, x2, y2, tv1, tv2, tc, dir);
2014-03-15 16:59:03 +00:00
return;
}
else
#endif
2014-03-15 16:59:03 +00:00
{
fixed_t xs, xe, count;
fixed_t dx0, dx1;
2014-03-15 16:59:03 +00:00
if (y1 == y2)
return;
2014-03-15 16:59:03 +00:00
if (y2 > y1)
{
count = (y2-y1)+1;
2014-03-15 16:59:03 +00:00
dx0 = FixedDiv((x2-x1)<<FRACBITS, count<<FRACBITS);
dx1 = FixedDiv((tv2-tv1)<<FRACBITS, count<<FRACBITS);
2014-03-15 16:59:03 +00:00
xs = x1 << FRACBITS;
xe = tv1 << FRACBITS;
tc <<= FRACBITS;
2014-03-15 16:59:03 +00:00
if (dir == 0)
{
for (;;)
{
rastertab[y1].maxx = xs;
rastertab[y1].tx2 = xe;
rastertab[y1].ty2 = tc;
2014-03-15 16:59:03 +00:00
xs += dx0;
xe += dx1;
y1++;
2014-03-15 16:59:03 +00:00
if (count-- < 1) break;
}
}
else
{
for (;;)
{
rastertab[y1].maxx = xs;
rastertab[y1].tx2 = tc;
rastertab[y1].ty2 = xe;
2014-03-15 16:59:03 +00:00
xs += dx0;
xe += dx1;
y1++;
2014-03-15 16:59:03 +00:00
if (count-- < 1) break;
}
2014-03-15 16:59:03 +00:00
}
}
else
{
count = (y1-y2)+1;
2014-03-15 16:59:03 +00:00
dx0 = FixedDiv((x1-x2)<<FRACBITS, count<<FRACBITS);
dx1 = FixedDiv((tv1-tv2)<<FRACBITS, count<<FRACBITS);
2014-03-15 16:59:03 +00:00
xs = x2 << FRACBITS;
xe = tv2 << FRACBITS;
tc <<= FRACBITS;
2014-03-15 16:59:03 +00:00
if (dir == 0)
{
for (;;)
{
rastertab[y2].minx = xs;
rastertab[y2].tx1 = xe;
rastertab[y2].ty1 = tc;
2014-03-15 16:59:03 +00:00
xs += dx0;
xe += dx1;
y2++;
2014-03-15 16:59:03 +00:00
if (count-- < 1) break;
}
}
else
{
for (;;)
{
rastertab[y2].minx = xs;
rastertab[y2].tx1 = tc;
rastertab[y2].ty1 = xe;
2014-03-15 16:59:03 +00:00
xs += dx0;
xe += dx1;
y2++;
2014-03-15 16:59:03 +00:00
if (count-- < 1) break;
}
}
2014-03-15 16:59:03 +00:00
}
}
}
// --------------------------------------------------------------------------
// Rasterize the four edges of a floor splat polygon,
// fill the polygon with linear interpolation, call span drawer for each
// scan line
// --------------------------------------------------------------------------
void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, vissprite_t *vis)
2014-03-15 16:59:03 +00:00
{
// rasterizing
INT32 miny = viewheight + 1, maxy = 0, y, x1, ry1, x2, y2, i;
fixed_t offsetx = 0, offsety = 0;
fixed_t step;
2014-03-15 16:59:03 +00:00
fixed_t planeheight;
fixed_t xstep, ystep;
2018-12-14 17:08:25 +00:00
angle_t angle, planecos, planesin;
fixed_t distance, span;
2014-03-15 16:59:03 +00:00
int spanfunctype = SPANDRAWFUNC_SPRITE;
2014-03-15 16:59:03 +00:00
prepare_rastertab();
2014-03-15 16:59:03 +00:00
#define RASTERPARAMS(vnum1, vnum2, tv1, tv2, tc, dir) \
x1 = verts[vnum1].x; \
ry1 = verts[vnum1].y; \
x2 = verts[vnum2].x; \
y2 = verts[vnum2].y; \
if (y2 > ry1) \
step = FixedDiv(x2-x1, y2-ry1+1); \
else if (y2 == ry1) \
step = 0; \
else \
step = FixedDiv(x2-x1, ry1-y2+1); \
if (ry1 < 0) { \
if (step) { \
x1 <<= FRACBITS; \
x1 += (-ry1)*step; \
x1 >>= FRACBITS; \
} \
ry1 = 0; \
} \
if (ry1 >= vid.height) { \
if (step) { \
x1 <<= FRACBITS; \
x1 -= (vid.height-1-ry1)*step; \
x1 >>= FRACBITS; \
} \
ry1 = vid.height - 1; \
} \
if (y2 < 0) { \
if (step) { \
x2 <<= FRACBITS; \
x2 -= (-y2)*step; \
x2 >>= FRACBITS; \
} \
y2 = 0; \
} \
if (y2 >= vid.height) { \
if (step) { \
x2 <<= FRACBITS; \
x2 += (vid.height-1-y2)*step; \
x2 >>= FRACBITS; \
} \
y2 = vid.height - 1; \
} \
rasterize_segment_tex(x1, ry1, x2, y2, tv1, tv2, tc, dir); \
if (ry1 < miny) \
miny = ry1; \
if (ry1 > maxy) \
maxy = ry1;
2014-03-15 16:59:03 +00:00
// do segment a -> top of texture
RASTERPARAMS(3,2,0,pSplat->width-1,0,0);
// do segment b -> right side of texture
RASTERPARAMS(2,1,0,pSplat->width-1,pSplat->height-1,0);
2014-03-15 16:59:03 +00:00
// do segment c -> bottom of texture
RASTERPARAMS(1,0,pSplat->width-1,0,pSplat->height-1,0);
2014-03-15 16:59:03 +00:00
// do segment d -> left side of texture
RASTERPARAMS(0,3,pSplat->width-1,0,0,1);
ds_source = pSplat->pic;
ds_flatwidth = pSplat->width;
ds_flatheight = pSplat->height;
if (R_CheckPowersOfTwo())
R_CheckFlatLength(ds_flatwidth * ds_flatheight);
ds_transmap = NULL;
if (vis->transmap)
{
ds_transmap = vis->transmap;
spanfunctype = SPANDRAWFUNC_TRANSSPRITE;
}
if (ds_powersoftwo)
spanfunc = spanfuncs[spanfunctype];
else
spanfunc = spanfuncs_npo2[spanfunctype];
if (pSplat->angle)
{
memset(cachedheight, 0, sizeof(cachedheight));
angle = (viewangle + pSplat->angle - ANGLE_90) >> ANGLETOFINESHIFT;
basexscale = FixedDiv(FINECOSINE(angle), centerxfrac);
baseyscale = -FixedDiv(FINESINE(angle), centerxfrac);
}
else
{
angle = (viewangle - ANGLE_90) >> ANGLETOFINESHIFT;
basexscale = FixedDiv(FINECOSINE(angle), centerxfrac);
baseyscale = -FixedDiv(FINESINE(angle), centerxfrac);
}
2014-03-15 16:59:03 +00:00
planeheight = abs(pSplat->z - viewz);
if (maxy >= vid.height)
maxy = vid.height-1;
2014-03-15 16:59:03 +00:00
for (y = miny; y <= maxy; y++)
{
x1 = rastertab[y].minx>>FRACBITS;
x2 = rastertab[y].maxx>>FRACBITS;
if (x1 > x2)
{
INT32 swap = x1;
x1 = x2;
x2 = swap;
}
2020-10-13 20:03:50 +00:00
if (x1 == INT16_MIN || x2 == INT16_MAX)
continue;
2014-03-15 16:59:03 +00:00
if (x1 < 0)
x1 = 0;
if (x2 >= vid.width)
x2 = vid.width - 1;
angle = (viewangle + pSplat->angle)>>ANGLETOFINESHIFT;
2018-12-14 17:08:25 +00:00
planecos = FINECOSINE(angle);
planesin = FINESINE(angle);
2014-03-15 16:59:03 +00:00
if (planeheight != cachedheight[y])
{
cachedheight[y] = planeheight;
distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
xstep = cachedxstep[y] = FixedMul(distance, basexscale);
ystep = cachedystep[y] = FixedMul(distance, baseyscale);
// don't divide by zero
2018-12-14 17:08:25 +00:00
if ((span = abs(centery-y)))
{
xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span;
ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span;
2018-12-14 17:08:25 +00:00
}
2014-03-15 16:59:03 +00:00
}
else
{
distance = cacheddistance[y];
xstep = cachedxstep[y];
ystep = cachedystep[y];
2014-03-15 16:59:03 +00:00
}
2018-12-14 17:08:25 +00:00
ds_xstep = FixedDiv(xstep, pSplat->xscale);
ds_ystep = FixedDiv(ystep, pSplat->yscale);
2014-03-15 16:59:03 +00:00
ds_colormap = vis->colormap;
ds_translation = R_GetSpriteTranslation(vis);
if (ds_translation == NULL)
ds_translation = colormaps;
2014-03-15 16:59:03 +00:00
if (vis->extra_colormap)
2014-03-15 16:59:03 +00:00
{
if (!ds_colormap)
ds_colormap = vis->extra_colormap->colormap;
else
ds_colormap = &vis->extra_colormap->colormap[ds_colormap - colormaps];
2014-03-15 16:59:03 +00:00
}
if (pSplat->angle)
{
// Add the view offset, rotated by the plane angle.
fixed_t a = -pSplat->verts[0].x + viewx;
fixed_t b = -pSplat->verts[0].y + viewy;
angle = (pSplat->angle >> ANGLETOFINESHIFT);
offsetx = FixedMul(a, FINECOSINE(angle)) - FixedMul(b,FINESINE(angle));
offsety = -FixedMul(a, FINESINE(angle)) - FixedMul(b,FINECOSINE(angle));
}
else
{
offsetx = viewx - pSplat->verts[0].x;
offsety = pSplat->verts[0].y - viewy;
}
2014-03-15 16:59:03 +00:00
if (vis != NULL)
{
INT32 xclip;
2014-03-15 16:59:03 +00:00
mfloorclip = vis->clipbot;
mceilingclip = vis->cliptop;
2014-03-15 16:59:03 +00:00
R_ClipVisSprite(vis, x1-1, x2+1, drawsegs, NULL);
memset(ds_splatclip, 0, sizeof(ds_splatclip));
2014-03-15 16:59:03 +00:00
if (x2 >= x1 && x1 < viewwidth && x1 >= 0)
{
for (xclip = x1; xclip <= x2; xclip++)
{
if (y >= mfloorclip[xclip])
ds_splatclip[xclip] = 1;
}
}
2014-03-15 16:59:03 +00:00
while (ds_splatclip[x1])
x1++;
i = x2;
while (i > x1)
2014-03-15 16:59:03 +00:00
{
if (ds_splatclip[i])
x2 = i-1;
i--;
2014-03-15 16:59:03 +00:00
}
}
ds_xfrac = FixedDiv(offsetx + FixedMul(planecos, distance) + (x1 - centerx) * xstep, pSplat->xscale);
ds_yfrac = FixedDiv(offsety - FixedMul(planesin, distance) + (x1 - centerx) * ystep, pSplat->yscale);
if (x2 >= x1)
{
ds_y = y;
ds_x1 = x1;
ds_x2 = x2;
spanfunc();
}
2014-03-15 16:59:03 +00:00
rastertab[y].minx = INT32_MAX;
rastertab[y].maxx = INT32_MIN;
}
if (pSplat->angle)
2014-03-15 16:59:03 +00:00
{
memset(cachedheight, 0, sizeof(cachedheight));
angle = (viewangle - ANGLE_90) >> ANGLETOFINESHIFT;
basexscale = FixedDiv(FINECOSINE(angle), centerxfrac);
baseyscale = -FixedDiv(FINESINE(angle), centerxfrac);
2014-03-15 16:59:03 +00:00
}
}
static void prepare_rastertab(void)
{
INT32 i;
prastertab = rastertab;
for (i = 0; i < vid.height; i++)
2014-03-15 16:59:03 +00:00
{
rastertab[i].minx = INT32_MAX;
rastertab[i].maxx = INT32_MIN;
2014-03-15 16:59:03 +00:00
}
}
#endif // FLOORSPLATS