void R_DrawVoxel()

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;
						}
					}
				}
			}
		}
	}
}