mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-25 13:31:07 +00:00
Move FCoverageBuffer to r_voxel
This commit is contained in:
parent
579199a246
commit
6d642b1906
3 changed files with 644 additions and 668 deletions
|
@ -19,12 +19,6 @@
|
|||
// DESCRIPTION:
|
||||
// Refresh of things, i.e. objects represented by sprites.
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
|
@ -85,29 +79,6 @@ namespace swrenderer
|
|||
{
|
||||
using namespace drawerargs;
|
||||
|
||||
// [RH] A c-buffer. Used for keeping track of offscreen voxel spans.
|
||||
|
||||
struct FCoverageBuffer
|
||||
{
|
||||
struct Span
|
||||
{
|
||||
Span *NextSpan;
|
||||
short Start, Stop;
|
||||
};
|
||||
|
||||
FCoverageBuffer(int size);
|
||||
~FCoverageBuffer();
|
||||
|
||||
void Clear();
|
||||
void InsertSpan(int listnum, int start, int stop);
|
||||
Span *AllocSpan();
|
||||
|
||||
FMemArena SpanArena;
|
||||
Span **Spans; // [0..NumLists-1] span lists
|
||||
Span *FreeSpans;
|
||||
unsigned int NumLists;
|
||||
};
|
||||
|
||||
//
|
||||
// Sprite rotation 0 is facing the viewer,
|
||||
// rotation 1 is one angle turn CLOCKWISE around the axis.
|
||||
|
@ -128,9 +99,6 @@ FTexture *WallSpriteTile;
|
|||
// INITIALIZATION FUNCTIONS
|
||||
//
|
||||
|
||||
int OffscreenBufferWidth, OffscreenBufferHeight;
|
||||
BYTE *OffscreenColorBuffer;
|
||||
FCoverageBuffer *OffscreenCoverageBuffer;
|
||||
|
||||
//
|
||||
|
||||
|
@ -148,6 +116,7 @@ static int vsprcount;
|
|||
void R_DeinitSprites()
|
||||
{
|
||||
R_DeinitVisSprites();
|
||||
R_DeinitRenderVoxel();
|
||||
|
||||
// Free vissprites sorter
|
||||
if (spritesorter != NULL)
|
||||
|
@ -156,19 +125,6 @@ void R_DeinitSprites()
|
|||
spritesortersize = 0;
|
||||
spritesorter = NULL;
|
||||
}
|
||||
|
||||
// Free offscreen buffer
|
||||
if (OffscreenColorBuffer != NULL)
|
||||
{
|
||||
delete[] OffscreenColorBuffer;
|
||||
OffscreenColorBuffer = NULL;
|
||||
}
|
||||
if (OffscreenCoverageBuffer != NULL)
|
||||
{
|
||||
delete OffscreenCoverageBuffer;
|
||||
OffscreenCoverageBuffer = NULL;
|
||||
}
|
||||
OffscreenBufferHeight = OffscreenBufferWidth = 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -241,81 +197,6 @@ bool R_ClipSpriteColumnWithPortals(vissprite_t* spr)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop, short *clipbot)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
// Do setup for blending.
|
||||
R_SetColorMapLight(spr->Style.BaseColormap, 0, spr->Style.ColormapNum << FRACBITS);
|
||||
bool visible = R_SetPatchStyle(spr->Style.RenderStyle, spr->Style.Alpha, spr->Translation, spr->FillColor);
|
||||
|
||||
if (!visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (colfunc == fuzzcolfunc || colfunc == R_FillColumn)
|
||||
{
|
||||
flags = DVF_OFFSCREEN | DVF_SPANSONLY;
|
||||
}
|
||||
else if (colfunc != basecolfunc)
|
||||
{
|
||||
flags = DVF_OFFSCREEN;
|
||||
}
|
||||
if (flags != 0)
|
||||
{
|
||||
R_CheckOffscreenBuffer(RenderTarget->GetWidth(), RenderTarget->GetHeight(), !!(flags & DVF_SPANSONLY));
|
||||
}
|
||||
if (spr->bInMirror)
|
||||
{
|
||||
flags |= DVF_MIRRORED;
|
||||
}
|
||||
|
||||
// Render the voxel, either directly to the screen or offscreen.
|
||||
R_DrawVoxel(spr->pa.vpos, spr->pa.vang, spr->gpos, spr->Angle,
|
||||
spr->xscale, FLOAT2FIXED(spr->yscale), spr->voxel, spr->Style.BaseColormap, spr->Style.ColormapNum, cliptop, clipbot,
|
||||
minslabz, maxslabz, flags);
|
||||
|
||||
// Blend the voxel, if that's what we need to do.
|
||||
if ((flags & ~DVF_MIRRORED) != 0)
|
||||
{
|
||||
int pixelsize = r_swtruecolor ? 4 : 1;
|
||||
for (int x = 0; x < viewwidth; ++x)
|
||||
{
|
||||
if (!(flags & DVF_SPANSONLY) && (x & 3) == 0)
|
||||
{
|
||||
rt_initcols(OffscreenColorBuffer + x * OffscreenBufferHeight);
|
||||
}
|
||||
for (FCoverageBuffer::Span *span = OffscreenCoverageBuffer->Spans[x]; span != NULL; span = span->NextSpan)
|
||||
{
|
||||
if (flags & DVF_SPANSONLY)
|
||||
{
|
||||
dc_x = x;
|
||||
dc_yl = span->Start;
|
||||
dc_yh = span->Stop - 1;
|
||||
dc_count = span->Stop - span->Start;
|
||||
dc_dest = (ylookup[span->Start] + x) * pixelsize + dc_destorg;
|
||||
colfunc();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_span_coverage(x, span->Start, span->Stop - 1);
|
||||
}
|
||||
}
|
||||
if (!(flags & DVF_SPANSONLY) && (x & 3) == 3)
|
||||
{
|
||||
rt_draw4cols(x - 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R_FinishSetPatchStyle();
|
||||
NetUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// R_ProjectSprite
|
||||
// Generates a vissprite for a thing if it might be visible.
|
||||
|
@ -1535,552 +1416,4 @@ inline int sgn(int v)
|
|||
return v < 0 ? -1 : v > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void R_DrawVoxel(const FVector3 &globalpos, FAngle viewangle,
|
||||
const FVector3 &dasprpos, DAngle dasprang,
|
||||
fixed_t daxscale, fixed_t dayscale, FVoxel *voxobj,
|
||||
FSWColormap *colormap, int colormapnum, short *daumost, short *dadmost, int minslabz, int maxslabz, int flags)
|
||||
{
|
||||
int i, j, k, x, y, syoff, ggxstart, ggystart, nxoff;
|
||||
fixed_t cosang, sinang, sprcosang, sprsinang;
|
||||
int backx, backy, gxinc, gyinc;
|
||||
int daxscalerecip, dayscalerecip, cnt, gxstart, gystart, dazscale;
|
||||
int lx, rx, nx, ny, x1=0, y1=0, x2=0, y2=0, yinc=0;
|
||||
int yoff, xs=0, ys=0, xe, ye, xi=0, yi=0, cbackx, cbacky, dagxinc, dagyinc;
|
||||
kvxslab_t *voxptr, *voxend;
|
||||
FVoxelMipLevel *mip;
|
||||
int z1a[64], z2a[64], yplc[64];
|
||||
|
||||
const int nytooclose = centerxwide * 2100, nytoofar = 32768*32768 - 1048576;
|
||||
const int xdimenscale = FLOAT2FIXED(centerxwide * YaspectMul / 160);
|
||||
const double centerxwide_f = centerxwide;
|
||||
const double centerxwidebig_f = centerxwide_f * 65536*65536*8;
|
||||
|
||||
// Convert to Build's coordinate system.
|
||||
fixed_t globalposx = xs_Fix<4>::ToFix(globalpos.X);
|
||||
fixed_t globalposy = xs_Fix<4>::ToFix(-globalpos.Y);
|
||||
fixed_t globalposz = xs_Fix<8>::ToFix(-globalpos.Z);
|
||||
|
||||
fixed_t dasprx = xs_Fix<4>::ToFix(dasprpos.X);
|
||||
fixed_t daspry = xs_Fix<4>::ToFix(-dasprpos.Y);
|
||||
fixed_t dasprz = xs_Fix<8>::ToFix(-dasprpos.Z);
|
||||
|
||||
// Shift the scales from 16 bits of fractional precision to 6.
|
||||
// Also do some magic voodoo scaling to make them the right size.
|
||||
daxscale = daxscale / (0xC000 >> 6);
|
||||
dayscale = dayscale / (0xC000 >> 6);
|
||||
if (daxscale <= 0 || dayscale <= 0)
|
||||
{
|
||||
// won't be visible.
|
||||
return;
|
||||
}
|
||||
|
||||
angle_t viewang = viewangle.BAMs();
|
||||
cosang = FLOAT2FIXED(viewangle.Cos()) >> 2;
|
||||
sinang = FLOAT2FIXED(-viewangle.Sin()) >> 2;
|
||||
sprcosang = FLOAT2FIXED(dasprang.Cos()) >> 2;
|
||||
sprsinang = FLOAT2FIXED(-dasprang.Sin()) >> 2;
|
||||
|
||||
R_SetupDrawSlab(colormap, 0.0f, colormapnum << FRACBITS);
|
||||
|
||||
int pixelsize = r_swtruecolor ? 4 : 1;
|
||||
|
||||
// Select mip level
|
||||
i = abs(DMulScale6(dasprx - globalposx, cosang, daspry - globalposy, sinang));
|
||||
i = DivScale6(i, MIN(daxscale, dayscale));
|
||||
j = xs_Fix<13>::ToFix(FocalLengthX);
|
||||
for (k = 0; i >= j && k < voxobj->NumMips; ++k)
|
||||
{
|
||||
i >>= 1;
|
||||
}
|
||||
if (k >= voxobj->NumMips) k = voxobj->NumMips - 1;
|
||||
|
||||
mip = &voxobj->Mips[k]; if (mip->SlabData == NULL) return;
|
||||
|
||||
minslabz >>= k;
|
||||
maxslabz >>= k;
|
||||
|
||||
daxscale <<= (k+8); dayscale <<= (k+8);
|
||||
dazscale = FixedDiv(dayscale, FLOAT2FIXED(BaseYaspectMul));
|
||||
daxscale = fixed_t(daxscale / YaspectMul);
|
||||
daxscale = Scale(daxscale, xdimenscale, centerxwide << 9);
|
||||
dayscale = Scale(dayscale, FixedMul(xdimenscale, viewingrangerecip), centerxwide << 9);
|
||||
|
||||
daxscalerecip = (1<<30) / daxscale;
|
||||
dayscalerecip = (1<<30) / dayscale;
|
||||
|
||||
fixed_t piv_x = fixed_t(mip->Pivot.X*256.);
|
||||
fixed_t piv_y = fixed_t(mip->Pivot.Y*256.);
|
||||
fixed_t piv_z = fixed_t(mip->Pivot.Z*256.);
|
||||
|
||||
x = FixedMul(globalposx - dasprx, daxscalerecip);
|
||||
y = FixedMul(globalposy - daspry, daxscalerecip);
|
||||
backx = (DMulScale10(x, sprcosang, y, sprsinang) + piv_x) >> 8;
|
||||
backy = (DMulScale10(y, sprcosang, x, -sprsinang) + piv_y) >> 8;
|
||||
cbackx = clamp(backx, 0, mip->SizeX - 1);
|
||||
cbacky = clamp(backy, 0, mip->SizeY - 1);
|
||||
|
||||
sprcosang = MulScale14(daxscale, sprcosang);
|
||||
sprsinang = MulScale14(daxscale, sprsinang);
|
||||
|
||||
x = (dasprx - globalposx) - DMulScale18(piv_x, sprcosang, piv_y, -sprsinang);
|
||||
y = (daspry - globalposy) - DMulScale18(piv_y, sprcosang, piv_x, sprsinang);
|
||||
|
||||
cosang = FixedMul(cosang, dayscalerecip);
|
||||
sinang = FixedMul(sinang, dayscalerecip);
|
||||
|
||||
gxstart = y*cosang - x*sinang;
|
||||
gystart = x*cosang + y*sinang;
|
||||
gxinc = DMulScale10(sprsinang, cosang, sprcosang, -sinang);
|
||||
gyinc = DMulScale10(sprcosang, cosang, sprsinang, sinang);
|
||||
if ((abs(globalposz - dasprz) >> 10) >= abs(dazscale)) return;
|
||||
|
||||
x = 0; y = 0; j = MAX(mip->SizeX, mip->SizeY);
|
||||
fixed_t *ggxinc = (fixed_t *)alloca((j + 1) * sizeof(fixed_t) * 2);
|
||||
fixed_t *ggyinc = ggxinc + (j + 1);
|
||||
for (i = 0; i <= j; i++)
|
||||
{
|
||||
ggxinc[i] = x; x += gxinc;
|
||||
ggyinc[i] = y; y += gyinc;
|
||||
}
|
||||
|
||||
syoff = DivScale21(globalposz - dasprz, FixedMul(dazscale, 0xE800)) + (piv_z << 7);
|
||||
yoff = (abs(gxinc) + abs(gyinc)) >> 1;
|
||||
|
||||
for (cnt = 0; cnt < 8; cnt++)
|
||||
{
|
||||
switch (cnt)
|
||||
{
|
||||
case 0: xs = 0; ys = 0; xi = 1; yi = 1; break;
|
||||
case 1: xs = mip->SizeX-1; ys = 0; xi = -1; yi = 1; break;
|
||||
case 2: xs = 0; ys = mip->SizeY-1; xi = 1; yi = -1; break;
|
||||
case 3: xs = mip->SizeX-1; ys = mip->SizeY-1; xi = -1; yi = -1; break;
|
||||
case 4: xs = 0; ys = cbacky; xi = 1; yi = 2; break;
|
||||
case 5: xs = mip->SizeX-1; ys = cbacky; xi = -1; yi = 2; break;
|
||||
case 6: xs = cbackx; ys = 0; xi = 2; yi = 1; break;
|
||||
case 7: xs = cbackx; ys = mip->SizeY-1; xi = 2; yi = -1; break;
|
||||
}
|
||||
xe = cbackx; ye = cbacky;
|
||||
if (cnt < 4)
|
||||
{
|
||||
if ((xi < 0) && (xe >= xs)) continue;
|
||||
if ((xi > 0) && (xe <= xs)) continue;
|
||||
if ((yi < 0) && (ye >= ys)) continue;
|
||||
if ((yi > 0) && (ye <= ys)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((xi < 0) && (xe > xs)) continue;
|
||||
if ((xi > 0) && (xe < xs)) continue;
|
||||
if ((yi < 0) && (ye > ys)) continue;
|
||||
if ((yi > 0) && (ye < ys)) continue;
|
||||
xe += xi; ye += yi;
|
||||
}
|
||||
|
||||
i = sgn(ys - backy) + sgn(xs - backx) * 3 + 4;
|
||||
switch(i)
|
||||
{
|
||||
case 6: case 7: x1 = 0; y1 = 0; break;
|
||||
case 8: case 5: x1 = gxinc; y1 = gyinc; break;
|
||||
case 0: case 3: x1 = gyinc; y1 = -gxinc; break;
|
||||
case 2: case 1: x1 = gxinc+gyinc; y1 = gyinc-gxinc; break;
|
||||
}
|
||||
switch(i)
|
||||
{
|
||||
case 2: case 5: x2 = 0; y2 = 0; break;
|
||||
case 0: case 1: x2 = gxinc; y2 = gyinc; break;
|
||||
case 8: case 7: x2 = gyinc; y2 = -gxinc; break;
|
||||
case 6: case 3: x2 = gxinc+gyinc; y2 = gyinc-gxinc; break;
|
||||
}
|
||||
BYTE oand = (1 << int(xs<backx)) + (1 << (int(ys<backy)+2));
|
||||
BYTE oand16 = oand + 16;
|
||||
BYTE oand32 = oand + 32;
|
||||
|
||||
if (yi > 0) { dagxinc = gxinc; dagyinc = FixedMul(gyinc, viewingrangerecip); }
|
||||
else { dagxinc = -gxinc; dagyinc = -FixedMul(gyinc, viewingrangerecip); }
|
||||
|
||||
/* Fix for non 90 degree viewing ranges */
|
||||
nxoff = FixedMul(x2 - x1, viewingrangerecip);
|
||||
x1 = FixedMul(x1, viewingrangerecip);
|
||||
|
||||
ggxstart = gxstart + ggyinc[ys];
|
||||
ggystart = gystart - ggxinc[ys];
|
||||
|
||||
for (x = xs; x != xe; x += xi)
|
||||
{
|
||||
BYTE *slabxoffs = &mip->SlabData[mip->OffsetX[x]];
|
||||
short *xyoffs = &mip->OffsetXY[x * (mip->SizeY + 1)];
|
||||
|
||||
nx = FixedMul(ggxstart + ggxinc[x], viewingrangerecip) + x1;
|
||||
ny = ggystart + ggyinc[x];
|
||||
for (y = ys; y != ye; y += yi, nx += dagyinc, ny -= dagxinc)
|
||||
{
|
||||
if ((ny <= nytooclose) || (ny >= nytoofar)) continue;
|
||||
voxptr = (kvxslab_t *)(slabxoffs + xyoffs[y]);
|
||||
voxend = (kvxslab_t *)(slabxoffs + xyoffs[y+1]);
|
||||
if (voxptr >= voxend) continue;
|
||||
|
||||
lx = xs_RoundToInt(nx * centerxwide_f / (ny + y1)) + centerx;
|
||||
if (lx < 0) lx = 0;
|
||||
rx = xs_RoundToInt((nx + nxoff) * centerxwide_f / (ny + y2)) + centerx;
|
||||
if (rx > viewwidth) rx = viewwidth;
|
||||
if (rx <= lx) continue;
|
||||
|
||||
if (flags & DVF_MIRRORED)
|
||||
{
|
||||
int t = viewwidth - lx;
|
||||
lx = viewwidth - rx;
|
||||
rx = t;
|
||||
}
|
||||
|
||||
fixed_t l1 = xs_RoundToInt(centerxwidebig_f / (ny - yoff));
|
||||
fixed_t l2 = xs_RoundToInt(centerxwidebig_f / (ny + yoff));
|
||||
for (; voxptr < voxend; voxptr = (kvxslab_t *)((BYTE *)voxptr + voxptr->zleng + 3))
|
||||
{
|
||||
const BYTE *col = voxptr->col;
|
||||
int zleng = voxptr->zleng;
|
||||
int ztop = voxptr->ztop;
|
||||
fixed_t z1, z2;
|
||||
|
||||
if (ztop < minslabz)
|
||||
{
|
||||
int diff = minslabz - ztop;
|
||||
ztop = minslabz;
|
||||
col += diff;
|
||||
zleng -= diff;
|
||||
}
|
||||
if (ztop + zleng > maxslabz)
|
||||
{
|
||||
int diff = ztop + zleng - maxslabz;
|
||||
zleng -= diff;
|
||||
}
|
||||
if (zleng <= 0) continue;
|
||||
|
||||
j = (ztop << 15) - syoff;
|
||||
if (j < 0)
|
||||
{
|
||||
k = j + (zleng << 15);
|
||||
if (k < 0)
|
||||
{
|
||||
if ((voxptr->backfacecull & oand32) == 0) continue;
|
||||
z2 = MulScale32(l2, k) + centery; /* Below slab */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((voxptr->backfacecull & oand) == 0) continue; /* Middle of slab */
|
||||
z2 = MulScale32(l1, k) + centery;
|
||||
}
|
||||
z1 = MulScale32(l1, j) + centery;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((voxptr->backfacecull & oand16) == 0) continue;
|
||||
z1 = MulScale32(l2, j) + centery; /* Above slab */
|
||||
z2 = MulScale32(l1, j + (zleng << 15)) + centery;
|
||||
}
|
||||
|
||||
if (z2 <= z1) continue;
|
||||
|
||||
if (zleng == 1)
|
||||
{
|
||||
yinc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (z2-z1 >= 1024) yinc = FixedDiv(zleng, z2 - z1);
|
||||
else yinc = (((1 << 24) - 1) / (z2 - z1)) * zleng >> 8;
|
||||
}
|
||||
// [RH] Clip each column separately, not just by the first one.
|
||||
for (int stripwidth = MIN<int>(countof(z1a), rx - lx), lxt = lx;
|
||||
lxt < rx;
|
||||
(lxt += countof(z1a)), stripwidth = MIN<int>(countof(z1a), rx - lxt))
|
||||
{
|
||||
// Calculate top and bottom pixels locations
|
||||
for (int xxx = 0; xxx < stripwidth; ++xxx)
|
||||
{
|
||||
if (zleng == 1)
|
||||
{
|
||||
yplc[xxx] = 0;
|
||||
z1a[xxx] = MAX<int>(z1, daumost[lxt + xxx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (z1 < daumost[lxt + xxx])
|
||||
{
|
||||
yplc[xxx] = yinc * (daumost[lxt + xxx] - z1);
|
||||
z1a[xxx] = daumost[lxt + xxx];
|
||||
}
|
||||
else
|
||||
{
|
||||
yplc[xxx] = 0;
|
||||
z1a[xxx] = z1;
|
||||
}
|
||||
}
|
||||
z2a[xxx] = MIN<int>(z2, dadmost[lxt + xxx]);
|
||||
}
|
||||
// Find top and bottom pixels that match and draw them as one strip
|
||||
for (int xxl = 0, xxr; xxl < stripwidth; )
|
||||
{
|
||||
if (z1a[xxl] >= z2a[xxl])
|
||||
{ // No column here
|
||||
xxl++;
|
||||
continue;
|
||||
}
|
||||
int z1 = z1a[xxl];
|
||||
int z2 = z2a[xxl];
|
||||
// How many columns share the same extents?
|
||||
for (xxr = xxl + 1; xxr < stripwidth; ++xxr)
|
||||
{
|
||||
if (z1a[xxr] != z1 || z2a[xxr] != z2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(flags & DVF_OFFSCREEN))
|
||||
{
|
||||
// Draw directly to the screen.
|
||||
R_DrawSlab(xxr - xxl, yplc[xxl], z2 - z1, yinc, col, (ylookup[z1] + lxt + xxl) * pixelsize + dc_destorg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record the area covered and possibly draw to an offscreen buffer.
|
||||
dc_yl = z1;
|
||||
dc_yh = z2 - 1;
|
||||
dc_count = z2 - z1;
|
||||
dc_iscale = yinc;
|
||||
for (int x = xxl; x < xxr; ++x)
|
||||
{
|
||||
OffscreenCoverageBuffer->InsertSpan(lxt + x, z1, z2);
|
||||
if (!(flags & DVF_SPANSONLY))
|
||||
{
|
||||
dc_x = lxt + x;
|
||||
rt_initcols(OffscreenColorBuffer + (dc_x & ~3) * OffscreenBufferHeight);
|
||||
dc_source = col;
|
||||
dc_source2 = nullptr;
|
||||
dc_texturefrac = yplc[xxl];
|
||||
hcolfunc_pre();
|
||||
}
|
||||
}
|
||||
}
|
||||
xxl = xxr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FCoverageBuffer Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FCoverageBuffer::FCoverageBuffer(int lists)
|
||||
: Spans(NULL), FreeSpans(NULL)
|
||||
{
|
||||
NumLists = lists;
|
||||
Spans = new Span *[lists];
|
||||
memset(Spans, 0, sizeof(Span*)*lists);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FCoverageBuffer Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FCoverageBuffer::~FCoverageBuffer()
|
||||
{
|
||||
if (Spans != NULL)
|
||||
{
|
||||
delete[] Spans;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FCoverageBuffer :: Clear
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FCoverageBuffer::Clear()
|
||||
{
|
||||
SpanArena.FreeAll();
|
||||
memset(Spans, 0, sizeof(Span*)*NumLists);
|
||||
FreeSpans = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FCoverageBuffer :: InsertSpan
|
||||
//
|
||||
// start is inclusive.
|
||||
// stop is exclusive.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FCoverageBuffer::InsertSpan(int listnum, int start, int stop)
|
||||
{
|
||||
assert(unsigned(listnum) < NumLists);
|
||||
assert(start < stop);
|
||||
|
||||
Span **span_p = &Spans[listnum];
|
||||
Span *span;
|
||||
|
||||
if (*span_p == NULL || (*span_p)->Start > stop)
|
||||
{ // This list is empty or the first entry is after this one, so we can just insert the span.
|
||||
goto addspan;
|
||||
}
|
||||
|
||||
// Insert the new span in order, merging with existing ones.
|
||||
while (*span_p != NULL)
|
||||
{
|
||||
if ((*span_p)->Stop < start) // ===== (existing span)
|
||||
{ // Span ends before this one starts. // ++++ (new span)
|
||||
span_p = &(*span_p)->NextSpan;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the new span overlap or abut the existing one?
|
||||
if ((*span_p)->Start <= start)
|
||||
{
|
||||
if ((*span_p)->Stop >= stop) // =============
|
||||
{ // The existing span completely covers this one. // +++++
|
||||
return;
|
||||
}
|
||||
extend: // Extend the existing span with the new one. // ======
|
||||
span = *span_p; // +++++++
|
||||
span->Stop = stop; // (or) +++++
|
||||
|
||||
// Free up any spans we just covered up.
|
||||
span_p = &(*span_p)->NextSpan;
|
||||
while (*span_p != NULL && (*span_p)->Start <= stop && (*span_p)->Stop <= stop)
|
||||
{
|
||||
Span *span = *span_p; // ====== ======
|
||||
*span_p = span->NextSpan; // +++++++++++++
|
||||
span->NextSpan = FreeSpans;
|
||||
FreeSpans = span;
|
||||
}
|
||||
if (*span_p != NULL && (*span_p)->Start <= stop) // ======= ========
|
||||
{ // Our new span connects two existing spans. // ++++++++++++++
|
||||
// They should all be collapsed into a single span.
|
||||
span->Stop = (*span_p)->Stop;
|
||||
span = *span_p;
|
||||
*span_p = span->NextSpan;
|
||||
span->NextSpan = FreeSpans;
|
||||
FreeSpans = span;
|
||||
}
|
||||
goto check;
|
||||
}
|
||||
else if ((*span_p)->Start <= stop) // =====
|
||||
{ // The new span extends the existing span from // ++++
|
||||
// the beginning. // (or) ++++
|
||||
(*span_p)->Start = start;
|
||||
if ((*span_p)->Stop < stop)
|
||||
{ // The new span also extends the existing span // ======
|
||||
// at the bottom // ++++++++++++++
|
||||
goto extend;
|
||||
}
|
||||
goto check;
|
||||
}
|
||||
else // ======
|
||||
{ // No overlap, so insert a new span. // +++++
|
||||
goto addspan;
|
||||
}
|
||||
}
|
||||
// Append a new span to the end of the list.
|
||||
addspan:
|
||||
span = AllocSpan();
|
||||
span->NextSpan = *span_p;
|
||||
span->Start = start;
|
||||
span->Stop = stop;
|
||||
*span_p = span;
|
||||
check:
|
||||
#ifdef _DEBUG
|
||||
// Validate the span list: Spans must be in order, and there must be
|
||||
// at least one pixel between spans.
|
||||
for (span = Spans[listnum]; span != NULL; span = span->NextSpan)
|
||||
{
|
||||
assert(span->Start < span->Stop);
|
||||
if (span->NextSpan != NULL)
|
||||
{
|
||||
assert(span->Stop < span->NextSpan->Start);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FCoverageBuffer :: AllocSpan
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FCoverageBuffer::Span *FCoverageBuffer::AllocSpan()
|
||||
{
|
||||
Span *span;
|
||||
|
||||
if (FreeSpans != NULL)
|
||||
{
|
||||
span = FreeSpans;
|
||||
FreeSpans = span->NextSpan;
|
||||
}
|
||||
else
|
||||
{
|
||||
span = (Span *)SpanArena.Alloc(sizeof(Span));
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_CheckOffscreenBuffer
|
||||
//
|
||||
// Allocates the offscreen coverage buffer and optionally the offscreen
|
||||
// color buffer. If they already exist but are the wrong size, they will
|
||||
// be reallocated.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_CheckOffscreenBuffer(int width, int height, bool spansonly)
|
||||
{
|
||||
if (OffscreenCoverageBuffer == NULL)
|
||||
{
|
||||
assert(OffscreenColorBuffer == NULL && "The color buffer cannot exist without the coverage buffer");
|
||||
OffscreenCoverageBuffer = new FCoverageBuffer(width);
|
||||
}
|
||||
else if (OffscreenCoverageBuffer->NumLists != (unsigned)width)
|
||||
{
|
||||
delete OffscreenCoverageBuffer;
|
||||
OffscreenCoverageBuffer = new FCoverageBuffer(width);
|
||||
if (OffscreenColorBuffer != NULL)
|
||||
{
|
||||
delete[] OffscreenColorBuffer;
|
||||
OffscreenColorBuffer = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OffscreenCoverageBuffer->Clear();
|
||||
}
|
||||
|
||||
if (!spansonly)
|
||||
{
|
||||
if (OffscreenColorBuffer == NULL)
|
||||
{
|
||||
OffscreenColorBuffer = new BYTE[width * height * 4];
|
||||
}
|
||||
else if (OffscreenBufferWidth != width || OffscreenBufferHeight != height)
|
||||
{
|
||||
delete[] OffscreenColorBuffer;
|
||||
OffscreenColorBuffer = new BYTE[width * height * 4];
|
||||
}
|
||||
}
|
||||
OffscreenBufferWidth = width;
|
||||
OffscreenBufferHeight = height;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
** Voxel rendering
|
||||
** Copyright (c) 1998-2016 Randy Heit
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -39,6 +40,13 @@
|
|||
|
||||
namespace swrenderer
|
||||
{
|
||||
namespace
|
||||
{
|
||||
FCoverageBuffer *OffscreenCoverageBuffer;
|
||||
int OffscreenBufferWidth, OffscreenBufferHeight;
|
||||
uint8_t *OffscreenColorBuffer;
|
||||
}
|
||||
|
||||
void R_DrawVisVoxel(vissprite_t *sprite, int minZ, int maxZ, short *cliptop, short *clipbottom)
|
||||
{
|
||||
R_SetColorMapLight(sprite->Style.BaseColormap, 0, sprite->Style.ColormapNum << FRACBITS);
|
||||
|
@ -214,4 +222,614 @@ namespace swrenderer
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R_DeinitRenderVoxel()
|
||||
{
|
||||
// Free offscreen buffer
|
||||
if (OffscreenColorBuffer != nullptr)
|
||||
{
|
||||
delete[] OffscreenColorBuffer;
|
||||
OffscreenColorBuffer = nullptr;
|
||||
}
|
||||
if (OffscreenCoverageBuffer != nullptr)
|
||||
{
|
||||
delete OffscreenCoverageBuffer;
|
||||
OffscreenCoverageBuffer = nullptr;
|
||||
}
|
||||
OffscreenBufferHeight = OffscreenBufferWidth = 0;
|
||||
}
|
||||
|
||||
void R_CheckOffscreenBuffer(int width, int height, bool spansonly)
|
||||
{
|
||||
// Allocates the offscreen coverage buffer and optionally the offscreen
|
||||
// color buffer. If they already exist but are the wrong size, they will
|
||||
// be reallocated.
|
||||
|
||||
if (OffscreenCoverageBuffer == nullptr)
|
||||
{
|
||||
assert(OffscreenColorBuffer == nullptr && "The color buffer cannot exist without the coverage buffer");
|
||||
OffscreenCoverageBuffer = new FCoverageBuffer(width);
|
||||
}
|
||||
else if (OffscreenCoverageBuffer->NumLists != (unsigned)width)
|
||||
{
|
||||
delete OffscreenCoverageBuffer;
|
||||
OffscreenCoverageBuffer = new FCoverageBuffer(width);
|
||||
if (OffscreenColorBuffer != nullptr)
|
||||
{
|
||||
delete[] OffscreenColorBuffer;
|
||||
OffscreenColorBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OffscreenCoverageBuffer->Clear();
|
||||
}
|
||||
|
||||
if (!spansonly)
|
||||
{
|
||||
if (OffscreenColorBuffer == nullptr)
|
||||
{
|
||||
OffscreenColorBuffer = new uint8_t[width * height * 4];
|
||||
}
|
||||
else if (OffscreenBufferWidth != width || OffscreenBufferHeight != height)
|
||||
{
|
||||
delete[] OffscreenColorBuffer;
|
||||
OffscreenColorBuffer = new uint8_t[width * height * 4];
|
||||
}
|
||||
}
|
||||
OffscreenBufferWidth = width;
|
||||
OffscreenBufferHeight = height;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FCoverageBuffer::FCoverageBuffer(int lists)
|
||||
: Spans(nullptr), FreeSpans(nullptr)
|
||||
{
|
||||
NumLists = lists;
|
||||
Spans = new Span *[lists];
|
||||
memset(Spans, 0, sizeof(Span*)*lists);
|
||||
}
|
||||
|
||||
FCoverageBuffer::~FCoverageBuffer()
|
||||
{
|
||||
if (Spans != nullptr)
|
||||
{
|
||||
delete[] Spans;
|
||||
}
|
||||
}
|
||||
|
||||
void FCoverageBuffer::Clear()
|
||||
{
|
||||
SpanArena.FreeAll();
|
||||
memset(Spans, 0, sizeof(Span*)*NumLists);
|
||||
FreeSpans = nullptr;
|
||||
}
|
||||
|
||||
void FCoverageBuffer::InsertSpan(int listnum, int start, int stop)
|
||||
{
|
||||
// start is inclusive.
|
||||
// stop is exclusive.
|
||||
|
||||
assert(unsigned(listnum) < NumLists);
|
||||
assert(start < stop);
|
||||
|
||||
Span **span_p = &Spans[listnum];
|
||||
Span *span;
|
||||
|
||||
if (*span_p == nullptr || (*span_p)->Start > stop)
|
||||
{ // This list is empty or the first entry is after this one, so we can just insert the span.
|
||||
goto addspan;
|
||||
}
|
||||
|
||||
// Insert the new span in order, merging with existing ones.
|
||||
while (*span_p != nullptr)
|
||||
{
|
||||
if ((*span_p)->Stop < start) // ===== (existing span)
|
||||
{ // Span ends before this one starts. // ++++ (new span)
|
||||
span_p = &(*span_p)->NextSpan;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the new span overlap or abut the existing one?
|
||||
if ((*span_p)->Start <= start)
|
||||
{
|
||||
if ((*span_p)->Stop >= stop) // =============
|
||||
{ // The existing span completely covers this one. // +++++
|
||||
return;
|
||||
}
|
||||
extend: // Extend the existing span with the new one. // ======
|
||||
span = *span_p; // +++++++
|
||||
span->Stop = stop; // (or) +++++
|
||||
|
||||
// Free up any spans we just covered up.
|
||||
span_p = &(*span_p)->NextSpan;
|
||||
while (*span_p != nullptr && (*span_p)->Start <= stop && (*span_p)->Stop <= stop)
|
||||
{
|
||||
Span *span = *span_p; // ====== ======
|
||||
*span_p = span->NextSpan; // +++++++++++++
|
||||
span->NextSpan = FreeSpans;
|
||||
FreeSpans = span;
|
||||
}
|
||||
if (*span_p != nullptr && (*span_p)->Start <= stop) // ======= ========
|
||||
{ // Our new span connects two existing spans. // ++++++++++++++
|
||||
// They should all be collapsed into a single span.
|
||||
span->Stop = (*span_p)->Stop;
|
||||
span = *span_p;
|
||||
*span_p = span->NextSpan;
|
||||
span->NextSpan = FreeSpans;
|
||||
FreeSpans = span;
|
||||
}
|
||||
goto check;
|
||||
}
|
||||
else if ((*span_p)->Start <= stop) // =====
|
||||
{ // The new span extends the existing span from // ++++
|
||||
// the beginning. // (or) ++++
|
||||
(*span_p)->Start = start;
|
||||
if ((*span_p)->Stop < stop)
|
||||
{ // The new span also extends the existing span // ======
|
||||
// at the bottom // ++++++++++++++
|
||||
goto extend;
|
||||
}
|
||||
goto check;
|
||||
}
|
||||
else // ======
|
||||
{ // No overlap, so insert a new span. // +++++
|
||||
goto addspan;
|
||||
}
|
||||
}
|
||||
// Append a new span to the end of the list.
|
||||
addspan:
|
||||
span = AllocSpan();
|
||||
span->NextSpan = *span_p;
|
||||
span->Start = start;
|
||||
span->Stop = stop;
|
||||
*span_p = span;
|
||||
check:
|
||||
#ifdef _DEBUG
|
||||
// Validate the span list: Spans must be in order, and there must be
|
||||
// at least one pixel between spans.
|
||||
for (span = Spans[listnum]; span != nullptr; span = span->NextSpan)
|
||||
{
|
||||
assert(span->Start < span->Stop);
|
||||
if (span->NextSpan != nullptr)
|
||||
{
|
||||
assert(span->Stop < span->NextSpan->Start);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
FCoverageBuffer::Span *FCoverageBuffer::AllocSpan()
|
||||
{
|
||||
Span *span;
|
||||
|
||||
if (FreeSpans != nullptr)
|
||||
{
|
||||
span = FreeSpans;
|
||||
FreeSpans = span->NextSpan;
|
||||
}
|
||||
else
|
||||
{
|
||||
span = (Span *)SpanArena.Alloc(sizeof(Span));
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Old BUILD implementation follows:
|
||||
//
|
||||
// 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.
|
||||
|
||||
#if 0
|
||||
void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop, short *clipbot)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
// Do setup for blending.
|
||||
R_SetColorMapLight(spr->Style.BaseColormap, 0, spr->Style.ColormapNum << FRACBITS);
|
||||
bool visible = R_SetPatchStyle(spr->Style.RenderStyle, spr->Style.Alpha, spr->Translation, spr->FillColor);
|
||||
|
||||
if (!visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (colfunc == fuzzcolfunc || colfunc == R_FillColumn)
|
||||
{
|
||||
flags = DVF_OFFSCREEN | DVF_SPANSONLY;
|
||||
}
|
||||
else if (colfunc != basecolfunc)
|
||||
{
|
||||
flags = DVF_OFFSCREEN;
|
||||
}
|
||||
if (flags != 0)
|
||||
{
|
||||
R_CheckOffscreenBuffer(RenderTarget->GetWidth(), RenderTarget->GetHeight(), !!(flags & DVF_SPANSONLY));
|
||||
}
|
||||
if (spr->bInMirror)
|
||||
{
|
||||
flags |= DVF_MIRRORED;
|
||||
}
|
||||
|
||||
// Render the voxel, either directly to the screen or offscreen.
|
||||
R_DrawVoxel(spr->pa.vpos, spr->pa.vang, spr->gpos, spr->Angle,
|
||||
spr->xscale, FLOAT2FIXED(spr->yscale), spr->voxel, spr->Style.BaseColormap, spr->Style.ColormapNum, cliptop, clipbot,
|
||||
minslabz, maxslabz, flags);
|
||||
|
||||
// Blend the voxel, if that's what we need to do.
|
||||
if ((flags & ~DVF_MIRRORED) != 0)
|
||||
{
|
||||
int pixelsize = r_swtruecolor ? 4 : 1;
|
||||
for (int x = 0; x < viewwidth; ++x)
|
||||
{
|
||||
if (!(flags & DVF_SPANSONLY) && (x & 3) == 0)
|
||||
{
|
||||
rt_initcols(OffscreenColorBuffer + x * OffscreenBufferHeight);
|
||||
}
|
||||
for (FCoverageBuffer::Span *span = OffscreenCoverageBuffer->Spans[x]; span != NULL; span = span->NextSpan)
|
||||
{
|
||||
if (flags & DVF_SPANSONLY)
|
||||
{
|
||||
dc_x = x;
|
||||
dc_yl = span->Start;
|
||||
dc_yh = span->Stop - 1;
|
||||
dc_count = span->Stop - span->Start;
|
||||
dc_dest = (ylookup[span->Start] + x) * pixelsize + dc_destorg;
|
||||
colfunc();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_span_coverage(x, span->Start, span->Stop - 1);
|
||||
}
|
||||
}
|
||||
if (!(flags & DVF_SPANSONLY) && (x & 3) == 3)
|
||||
{
|
||||
rt_draw4cols(x - 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R_FinishSetPatchStyle();
|
||||
NetUpdate();
|
||||
}
|
||||
|
||||
void R_DrawVoxel(const FVector3 &globalpos, FAngle viewangle,
|
||||
const FVector3 &dasprpos, DAngle dasprang,
|
||||
fixed_t daxscale, fixed_t dayscale, FVoxel *voxobj,
|
||||
FSWColormap *colormap, int colormapnum, short *daumost, short *dadmost, int minslabz, int maxslabz, int flags)
|
||||
{
|
||||
int i, j, k, x, y, syoff, ggxstart, ggystart, nxoff;
|
||||
fixed_t cosang, sinang, sprcosang, sprsinang;
|
||||
int backx, backy, gxinc, gyinc;
|
||||
int daxscalerecip, dayscalerecip, cnt, gxstart, gystart, dazscale;
|
||||
int lx, rx, nx, ny, x1=0, y1=0, x2=0, y2=0, yinc=0;
|
||||
int yoff, xs=0, ys=0, xe, ye, xi=0, yi=0, cbackx, cbacky, dagxinc, dagyinc;
|
||||
kvxslab_t *voxptr, *voxend;
|
||||
FVoxelMipLevel *mip;
|
||||
int z1a[64], z2a[64], yplc[64];
|
||||
|
||||
const int nytooclose = centerxwide * 2100, nytoofar = 32768*32768 - 1048576;
|
||||
const int xdimenscale = FLOAT2FIXED(centerxwide * YaspectMul / 160);
|
||||
const double centerxwide_f = centerxwide;
|
||||
const double centerxwidebig_f = centerxwide_f * 65536*65536*8;
|
||||
|
||||
// Convert to Build's coordinate system.
|
||||
fixed_t globalposx = xs_Fix<4>::ToFix(globalpos.X);
|
||||
fixed_t globalposy = xs_Fix<4>::ToFix(-globalpos.Y);
|
||||
fixed_t globalposz = xs_Fix<8>::ToFix(-globalpos.Z);
|
||||
|
||||
fixed_t dasprx = xs_Fix<4>::ToFix(dasprpos.X);
|
||||
fixed_t daspry = xs_Fix<4>::ToFix(-dasprpos.Y);
|
||||
fixed_t dasprz = xs_Fix<8>::ToFix(-dasprpos.Z);
|
||||
|
||||
// Shift the scales from 16 bits of fractional precision to 6.
|
||||
// Also do some magic voodoo scaling to make them the right size.
|
||||
daxscale = daxscale / (0xC000 >> 6);
|
||||
dayscale = dayscale / (0xC000 >> 6);
|
||||
if (daxscale <= 0 || dayscale <= 0)
|
||||
{
|
||||
// won't be visible.
|
||||
return;
|
||||
}
|
||||
|
||||
angle_t viewang = viewangle.BAMs();
|
||||
cosang = FLOAT2FIXED(viewangle.Cos()) >> 2;
|
||||
sinang = FLOAT2FIXED(-viewangle.Sin()) >> 2;
|
||||
sprcosang = FLOAT2FIXED(dasprang.Cos()) >> 2;
|
||||
sprsinang = FLOAT2FIXED(-dasprang.Sin()) >> 2;
|
||||
|
||||
R_SetupDrawSlab(colormap, 0.0f, colormapnum << FRACBITS);
|
||||
|
||||
int pixelsize = r_swtruecolor ? 4 : 1;
|
||||
|
||||
// Select mip level
|
||||
i = abs(DMulScale6(dasprx - globalposx, cosang, daspry - globalposy, sinang));
|
||||
i = DivScale6(i, MIN(daxscale, dayscale));
|
||||
j = xs_Fix<13>::ToFix(FocalLengthX);
|
||||
for (k = 0; i >= j && k < voxobj->NumMips; ++k)
|
||||
{
|
||||
i >>= 1;
|
||||
}
|
||||
if (k >= voxobj->NumMips) k = voxobj->NumMips - 1;
|
||||
|
||||
mip = &voxobj->Mips[k]; if (mip->SlabData == NULL) return;
|
||||
|
||||
minslabz >>= k;
|
||||
maxslabz >>= k;
|
||||
|
||||
daxscale <<= (k+8); dayscale <<= (k+8);
|
||||
dazscale = FixedDiv(dayscale, FLOAT2FIXED(BaseYaspectMul));
|
||||
daxscale = fixed_t(daxscale / YaspectMul);
|
||||
daxscale = Scale(daxscale, xdimenscale, centerxwide << 9);
|
||||
dayscale = Scale(dayscale, FixedMul(xdimenscale, viewingrangerecip), centerxwide << 9);
|
||||
|
||||
daxscalerecip = (1<<30) / daxscale;
|
||||
dayscalerecip = (1<<30) / dayscale;
|
||||
|
||||
fixed_t piv_x = fixed_t(mip->Pivot.X*256.);
|
||||
fixed_t piv_y = fixed_t(mip->Pivot.Y*256.);
|
||||
fixed_t piv_z = fixed_t(mip->Pivot.Z*256.);
|
||||
|
||||
x = FixedMul(globalposx - dasprx, daxscalerecip);
|
||||
y = FixedMul(globalposy - daspry, daxscalerecip);
|
||||
backx = (DMulScale10(x, sprcosang, y, sprsinang) + piv_x) >> 8;
|
||||
backy = (DMulScale10(y, sprcosang, x, -sprsinang) + piv_y) >> 8;
|
||||
cbackx = clamp(backx, 0, mip->SizeX - 1);
|
||||
cbacky = clamp(backy, 0, mip->SizeY - 1);
|
||||
|
||||
sprcosang = MulScale14(daxscale, sprcosang);
|
||||
sprsinang = MulScale14(daxscale, sprsinang);
|
||||
|
||||
x = (dasprx - globalposx) - DMulScale18(piv_x, sprcosang, piv_y, -sprsinang);
|
||||
y = (daspry - globalposy) - DMulScale18(piv_y, sprcosang, piv_x, sprsinang);
|
||||
|
||||
cosang = FixedMul(cosang, dayscalerecip);
|
||||
sinang = FixedMul(sinang, dayscalerecip);
|
||||
|
||||
gxstart = y*cosang - x*sinang;
|
||||
gystart = x*cosang + y*sinang;
|
||||
gxinc = DMulScale10(sprsinang, cosang, sprcosang, -sinang);
|
||||
gyinc = DMulScale10(sprcosang, cosang, sprsinang, sinang);
|
||||
if ((abs(globalposz - dasprz) >> 10) >= abs(dazscale)) return;
|
||||
|
||||
x = 0; y = 0; j = MAX(mip->SizeX, mip->SizeY);
|
||||
fixed_t *ggxinc = (fixed_t *)alloca((j + 1) * sizeof(fixed_t) * 2);
|
||||
fixed_t *ggyinc = ggxinc + (j + 1);
|
||||
for (i = 0; i <= j; i++)
|
||||
{
|
||||
ggxinc[i] = x; x += gxinc;
|
||||
ggyinc[i] = y; y += gyinc;
|
||||
}
|
||||
|
||||
syoff = DivScale21(globalposz - dasprz, FixedMul(dazscale, 0xE800)) + (piv_z << 7);
|
||||
yoff = (abs(gxinc) + abs(gyinc)) >> 1;
|
||||
|
||||
for (cnt = 0; cnt < 8; cnt++)
|
||||
{
|
||||
switch (cnt)
|
||||
{
|
||||
case 0: xs = 0; ys = 0; xi = 1; yi = 1; break;
|
||||
case 1: xs = mip->SizeX-1; ys = 0; xi = -1; yi = 1; break;
|
||||
case 2: xs = 0; ys = mip->SizeY-1; xi = 1; yi = -1; break;
|
||||
case 3: xs = mip->SizeX-1; ys = mip->SizeY-1; xi = -1; yi = -1; break;
|
||||
case 4: xs = 0; ys = cbacky; xi = 1; yi = 2; break;
|
||||
case 5: xs = mip->SizeX-1; ys = cbacky; xi = -1; yi = 2; break;
|
||||
case 6: xs = cbackx; ys = 0; xi = 2; yi = 1; break;
|
||||
case 7: xs = cbackx; ys = mip->SizeY-1; xi = 2; yi = -1; break;
|
||||
}
|
||||
xe = cbackx; ye = cbacky;
|
||||
if (cnt < 4)
|
||||
{
|
||||
if ((xi < 0) && (xe >= xs)) continue;
|
||||
if ((xi > 0) && (xe <= xs)) continue;
|
||||
if ((yi < 0) && (ye >= ys)) continue;
|
||||
if ((yi > 0) && (ye <= ys)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((xi < 0) && (xe > xs)) continue;
|
||||
if ((xi > 0) && (xe < xs)) continue;
|
||||
if ((yi < 0) && (ye > ys)) continue;
|
||||
if ((yi > 0) && (ye < ys)) continue;
|
||||
xe += xi; ye += yi;
|
||||
}
|
||||
|
||||
i = sgn(ys - backy) + sgn(xs - backx) * 3 + 4;
|
||||
switch(i)
|
||||
{
|
||||
case 6: case 7: x1 = 0; y1 = 0; break;
|
||||
case 8: case 5: x1 = gxinc; y1 = gyinc; break;
|
||||
case 0: case 3: x1 = gyinc; y1 = -gxinc; break;
|
||||
case 2: case 1: x1 = gxinc+gyinc; y1 = gyinc-gxinc; break;
|
||||
}
|
||||
switch(i)
|
||||
{
|
||||
case 2: case 5: x2 = 0; y2 = 0; break;
|
||||
case 0: case 1: x2 = gxinc; y2 = gyinc; break;
|
||||
case 8: case 7: x2 = gyinc; y2 = -gxinc; break;
|
||||
case 6: case 3: x2 = gxinc+gyinc; y2 = gyinc-gxinc; break;
|
||||
}
|
||||
BYTE oand = (1 << int(xs<backx)) + (1 << (int(ys<backy)+2));
|
||||
BYTE oand16 = oand + 16;
|
||||
BYTE oand32 = oand + 32;
|
||||
|
||||
if (yi > 0) { dagxinc = gxinc; dagyinc = FixedMul(gyinc, viewingrangerecip); }
|
||||
else { dagxinc = -gxinc; dagyinc = -FixedMul(gyinc, viewingrangerecip); }
|
||||
|
||||
/* Fix for non 90 degree viewing ranges */
|
||||
nxoff = FixedMul(x2 - x1, viewingrangerecip);
|
||||
x1 = FixedMul(x1, viewingrangerecip);
|
||||
|
||||
ggxstart = gxstart + ggyinc[ys];
|
||||
ggystart = gystart - ggxinc[ys];
|
||||
|
||||
for (x = xs; x != xe; x += xi)
|
||||
{
|
||||
BYTE *slabxoffs = &mip->SlabData[mip->OffsetX[x]];
|
||||
short *xyoffs = &mip->OffsetXY[x * (mip->SizeY + 1)];
|
||||
|
||||
nx = FixedMul(ggxstart + ggxinc[x], viewingrangerecip) + x1;
|
||||
ny = ggystart + ggyinc[x];
|
||||
for (y = ys; y != ye; y += yi, nx += dagyinc, ny -= dagxinc)
|
||||
{
|
||||
if ((ny <= nytooclose) || (ny >= nytoofar)) continue;
|
||||
voxptr = (kvxslab_t *)(slabxoffs + xyoffs[y]);
|
||||
voxend = (kvxslab_t *)(slabxoffs + xyoffs[y+1]);
|
||||
if (voxptr >= voxend) continue;
|
||||
|
||||
lx = xs_RoundToInt(nx * centerxwide_f / (ny + y1)) + centerx;
|
||||
if (lx < 0) lx = 0;
|
||||
rx = xs_RoundToInt((nx + nxoff) * centerxwide_f / (ny + y2)) + centerx;
|
||||
if (rx > viewwidth) rx = viewwidth;
|
||||
if (rx <= lx) continue;
|
||||
|
||||
if (flags & DVF_MIRRORED)
|
||||
{
|
||||
int t = viewwidth - lx;
|
||||
lx = viewwidth - rx;
|
||||
rx = t;
|
||||
}
|
||||
|
||||
fixed_t l1 = xs_RoundToInt(centerxwidebig_f / (ny - yoff));
|
||||
fixed_t l2 = xs_RoundToInt(centerxwidebig_f / (ny + yoff));
|
||||
for (; voxptr < voxend; voxptr = (kvxslab_t *)((BYTE *)voxptr + voxptr->zleng + 3))
|
||||
{
|
||||
const BYTE *col = voxptr->col;
|
||||
int zleng = voxptr->zleng;
|
||||
int ztop = voxptr->ztop;
|
||||
fixed_t z1, z2;
|
||||
|
||||
if (ztop < minslabz)
|
||||
{
|
||||
int diff = minslabz - ztop;
|
||||
ztop = minslabz;
|
||||
col += diff;
|
||||
zleng -= diff;
|
||||
}
|
||||
if (ztop + zleng > maxslabz)
|
||||
{
|
||||
int diff = ztop + zleng - maxslabz;
|
||||
zleng -= diff;
|
||||
}
|
||||
if (zleng <= 0) continue;
|
||||
|
||||
j = (ztop << 15) - syoff;
|
||||
if (j < 0)
|
||||
{
|
||||
k = j + (zleng << 15);
|
||||
if (k < 0)
|
||||
{
|
||||
if ((voxptr->backfacecull & oand32) == 0) continue;
|
||||
z2 = MulScale32(l2, k) + centery; /* Below slab */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((voxptr->backfacecull & oand) == 0) continue; /* Middle of slab */
|
||||
z2 = MulScale32(l1, k) + centery;
|
||||
}
|
||||
z1 = MulScale32(l1, j) + centery;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((voxptr->backfacecull & oand16) == 0) continue;
|
||||
z1 = MulScale32(l2, j) + centery; /* Above slab */
|
||||
z2 = MulScale32(l1, j + (zleng << 15)) + centery;
|
||||
}
|
||||
|
||||
if (z2 <= z1) continue;
|
||||
|
||||
if (zleng == 1)
|
||||
{
|
||||
yinc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (z2-z1 >= 1024) yinc = FixedDiv(zleng, z2 - z1);
|
||||
else yinc = (((1 << 24) - 1) / (z2 - z1)) * zleng >> 8;
|
||||
}
|
||||
// [RH] Clip each column separately, not just by the first one.
|
||||
for (int stripwidth = MIN<int>(countof(z1a), rx - lx), lxt = lx;
|
||||
lxt < rx;
|
||||
(lxt += countof(z1a)), stripwidth = MIN<int>(countof(z1a), rx - lxt))
|
||||
{
|
||||
// Calculate top and bottom pixels locations
|
||||
for (int xxx = 0; xxx < stripwidth; ++xxx)
|
||||
{
|
||||
if (zleng == 1)
|
||||
{
|
||||
yplc[xxx] = 0;
|
||||
z1a[xxx] = MAX<int>(z1, daumost[lxt + xxx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (z1 < daumost[lxt + xxx])
|
||||
{
|
||||
yplc[xxx] = yinc * (daumost[lxt + xxx] - z1);
|
||||
z1a[xxx] = daumost[lxt + xxx];
|
||||
}
|
||||
else
|
||||
{
|
||||
yplc[xxx] = 0;
|
||||
z1a[xxx] = z1;
|
||||
}
|
||||
}
|
||||
z2a[xxx] = MIN<int>(z2, dadmost[lxt + xxx]);
|
||||
}
|
||||
// Find top and bottom pixels that match and draw them as one strip
|
||||
for (int xxl = 0, xxr; xxl < stripwidth; )
|
||||
{
|
||||
if (z1a[xxl] >= z2a[xxl])
|
||||
{ // No column here
|
||||
xxl++;
|
||||
continue;
|
||||
}
|
||||
int z1 = z1a[xxl];
|
||||
int z2 = z2a[xxl];
|
||||
// How many columns share the same extents?
|
||||
for (xxr = xxl + 1; xxr < stripwidth; ++xxr)
|
||||
{
|
||||
if (z1a[xxr] != z1 || z2a[xxr] != z2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(flags & DVF_OFFSCREEN))
|
||||
{
|
||||
// Draw directly to the screen.
|
||||
R_DrawSlab(xxr - xxl, yplc[xxl], z2 - z1, yinc, col, (ylookup[z1] + lxt + xxl) * pixelsize + dc_destorg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record the area covered and possibly draw to an offscreen buffer.
|
||||
dc_yl = z1;
|
||||
dc_yh = z2 - 1;
|
||||
dc_count = z2 - z1;
|
||||
dc_iscale = yinc;
|
||||
for (int x = xxl; x < xxr; ++x)
|
||||
{
|
||||
OffscreenCoverageBuffer->InsertSpan(lxt + x, z1, z2);
|
||||
if (!(flags & DVF_SPANSONLY))
|
||||
{
|
||||
dc_x = lxt + x;
|
||||
rt_initcols(OffscreenColorBuffer + (dc_x & ~3) * OffscreenBufferHeight);
|
||||
dc_source = col;
|
||||
dc_source2 = nullptr;
|
||||
dc_texturefrac = yplc[xxl];
|
||||
hcolfunc_pre();
|
||||
}
|
||||
}
|
||||
}
|
||||
xxl = xxr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
** Voxel rendering
|
||||
** Copyright (c) 1998-2016 Randy Heit
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -33,4 +34,28 @@ namespace swrenderer
|
|||
kvxslab_t *R_GetSlabStart(const FVoxelMipLevel &mip, int x, int y);
|
||||
kvxslab_t *R_GetSlabEnd(const FVoxelMipLevel &mip, int x, int y);
|
||||
kvxslab_t *R_NextSlab(kvxslab_t *slab);
|
||||
|
||||
void R_DeinitRenderVoxel();
|
||||
|
||||
// [RH] A c-buffer. Used for keeping track of offscreen voxel spans.
|
||||
struct FCoverageBuffer
|
||||
{
|
||||
struct Span
|
||||
{
|
||||
Span *NextSpan;
|
||||
short Start, Stop;
|
||||
};
|
||||
|
||||
FCoverageBuffer(int size);
|
||||
~FCoverageBuffer();
|
||||
|
||||
void Clear();
|
||||
void InsertSpan(int listnum, int start, int stop);
|
||||
Span *AllocSpan();
|
||||
|
||||
FMemArena SpanArena;
|
||||
Span **Spans; // [0..NumLists-1] span lists
|
||||
Span *FreeSpans;
|
||||
unsigned int NumLists;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue