in doom_py/src/vizdoom/src/r_things.cpp [2557:2876]
void R_DrawVoxel(fixed_t globalposx, fixed_t globalposy, fixed_t globalposz, angle_t viewang,
fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t dasprang,
fixed_t daxscale, fixed_t dayscale, FVoxel *voxobj,
lighttable_t *colormap, 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 = Scale(centerxwide, yaspectmul, 160);
const double centerxwide_f = centerxwide;
const double centerxwidebig_f = centerxwide_f * 65536*65536*8;
// Convert to Build's coordinate system.
globalposx = globalposx >> 12;
globalposy = -globalposy >> 12;
globalposz = -globalposz >> 8;
dasprx = dasprx >> 12;
daspry = -daspry >> 12;
dasprz = -dasprz >> 8;
// 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);
cosang = finecosine[viewang >> ANGLETOFINESHIFT] >> 2;
sinang = -finesine[viewang >> ANGLETOFINESHIFT] >> 2;
sprcosang = finecosine[dasprang >> ANGLETOFINESHIFT] >> 2;
sprsinang = -finesine[dasprang >> ANGLETOFINESHIFT] >> 2;
R_SetupDrawSlab(colormap);
// Select mip level
i = abs(DMulScale6(dasprx - globalposx, cosang, daspry - globalposy, sinang));
i = DivScale6(i, MIN(daxscale, dayscale));
j = FocalLengthX >> 3;
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, baseyaspectmul);
daxscale = FixedDiv(daxscale, yaspectmul);
daxscale = Scale(daxscale, xdimenscale, centerxwide << 9);
dayscale = Scale(dayscale, FixedMul(xdimenscale, viewingrangerecip), centerxwide << 9);
daxscalerecip = (1<<30) / daxscale;
dayscalerecip = (1<<30) / dayscale;
x = FixedMul(globalposx - dasprx, daxscalerecip);
y = FixedMul(globalposy - daspry, daxscalerecip);
backx = (DMulScale10(x, sprcosang, y, sprsinang) + mip->PivotX) >> 8;
backy = (DMulScale10(y, sprcosang, x, -sprsinang) + mip->PivotY) >> 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(mip->PivotX, sprcosang, mip->PivotY, -sprsinang);
y = (daspry - globalposy) - DMulScale18(mip->PivotY, sprcosang, mip->PivotX, 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)) + (mip->PivotZ << 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 = ksgn(ys-backy)+ksgn(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 + 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_texturefrac = yplc[xxl];
hcolfunc_pre();
}
}
}
xxl = xxr;
}
}
}
}
}
}
}