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:
|
// DESCRIPTION:
|
||||||
// Refresh of things, i.e. objects represented by sprites.
|
// 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>
|
#include <stdio.h>
|
||||||
|
@ -85,29 +79,6 @@ namespace swrenderer
|
||||||
{
|
{
|
||||||
using namespace drawerargs;
|
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,
|
// Sprite rotation 0 is facing the viewer,
|
||||||
// rotation 1 is one angle turn CLOCKWISE around the axis.
|
// rotation 1 is one angle turn CLOCKWISE around the axis.
|
||||||
|
@ -128,9 +99,6 @@ FTexture *WallSpriteTile;
|
||||||
// INITIALIZATION FUNCTIONS
|
// INITIALIZATION FUNCTIONS
|
||||||
//
|
//
|
||||||
|
|
||||||
int OffscreenBufferWidth, OffscreenBufferHeight;
|
|
||||||
BYTE *OffscreenColorBuffer;
|
|
||||||
FCoverageBuffer *OffscreenCoverageBuffer;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -148,6 +116,7 @@ static int vsprcount;
|
||||||
void R_DeinitSprites()
|
void R_DeinitSprites()
|
||||||
{
|
{
|
||||||
R_DeinitVisSprites();
|
R_DeinitVisSprites();
|
||||||
|
R_DeinitRenderVoxel();
|
||||||
|
|
||||||
// Free vissprites sorter
|
// Free vissprites sorter
|
||||||
if (spritesorter != NULL)
|
if (spritesorter != NULL)
|
||||||
|
@ -156,19 +125,6 @@ void R_DeinitSprites()
|
||||||
spritesortersize = 0;
|
spritesortersize = 0;
|
||||||
spritesorter = NULL;
|
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;
|
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
|
// R_ProjectSprite
|
||||||
// Generates a vissprite for a thing if it might be visible.
|
// 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;
|
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
|
** Voxel rendering
|
||||||
|
** Copyright (c) 1998-2016 Randy Heit
|
||||||
** Copyright (c) 2016 Magnus Norddahl
|
** Copyright (c) 2016 Magnus Norddahl
|
||||||
**
|
**
|
||||||
** This software is provided 'as-is', without any express or implied
|
** This software is provided 'as-is', without any express or implied
|
||||||
|
@ -39,6 +40,13 @@
|
||||||
|
|
||||||
namespace swrenderer
|
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)
|
void R_DrawVisVoxel(vissprite_t *sprite, int minZ, int maxZ, short *cliptop, short *clipbottom)
|
||||||
{
|
{
|
||||||
R_SetColorMapLight(sprite->Style.BaseColormap, 0, sprite->Style.ColormapNum << FRACBITS);
|
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
|
** Voxel rendering
|
||||||
|
** Copyright (c) 1998-2016 Randy Heit
|
||||||
** Copyright (c) 2016 Magnus Norddahl
|
** Copyright (c) 2016 Magnus Norddahl
|
||||||
**
|
**
|
||||||
** This software is provided 'as-is', without any express or implied
|
** 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_GetSlabStart(const FVoxelMipLevel &mip, int x, int y);
|
||||||
kvxslab_t *R_GetSlabEnd(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);
|
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