Kernel-based dithering of MDL affine triangles

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
mankrip
Posts: 924
Joined: Fri Jul 04, 2008 3:02 am

Kernel-based dithering of MDL affine triangles

Post by mankrip »

This one requires more work. The code is completely unoptimized, and there's no perspective correction.

Creating new cvars and other required variables is up to you.

Here's the code:

Code: Select all

// mankrip - d_dither - begin
int dither_kernel[2][2][2] =
{
	{
		{
			 -8192
		,	-24576
		}
	,	{
			 24576
		,	 -8192
		}
	}
,	{
		{
			  8192
		,	 24576
		}
	,	{
			-24576
		,	  8192
		}
	}
};
int shading_dither_kernel[2][2] =
// same as dither_kernel[X][Y][0] >> 7
// set to >> 7 for less accuracy and more smoothness
{
	{
		 -8192 >> 7
	,	 24576 >> 7
	}
,	{
		  8192 >> 7
	,	-24576 >> 7
	}
};
// mankrip - d_dither - end
/*
================
D_PolysetDrawSpans8
================
*/
void D_PolysetDrawSpans8_ColorKeyed (void)
{
	spanpackage_t
		* pspanpackage = pstart
		;
	int
		lcount
	,	lsfrac
	,	ltfrac
	,	llight
	,	lzi
		;
	short
		* lpz
		;
	byte
		* lpdest
	,	* lptex
		;
	// mankrip - begin
	int
		dith_switch
		;
	// mankrip - end

	do
	{
		lcount = d_aspancount - pspanpackage->count;

		errorterm += erroradjustup;
		if (errorterm >= 0)
		{
			errorterm -= erroradjustdown;
			d_aspancount += d_countextrastep;
		}
		else
			d_aspancount += ubasestep;

		if (lcount)
		{
			lpdest = pspanpackage->pdest;
			// mankrip - begin
			u = (int) (lpdest - (byte *)d_viewbuffer);
			Y = (u / screenwidth) & 1; // v & 1;
			X = (u % screenwidth) & 1; // u & 1;
			dith_switch = X;
			// mankrip - end
			lptex = pspanpackage->ptex;
			lpz = pspanpackage->pz;
			lsfrac = pspanpackage->sfrac;
			ltfrac = pspanpackage->tfrac;
			llight = pspanpackage->light;
			lzi = pspanpackage->zi;

			do
			{
				if ((lzi >> 16) >= *lpz)
				if (*lptex != TRANSPARENT_COLOR) // mankrip - transparent pixels in alias models
				{
					if (d_dither.value)
					{
						idiths = (lsfrac + dither_kernel[dith_switch][Y][0]) >> 16;
						iditht = (ltfrac + dither_kernel[dith_switch][Y][1]) >> 16;
					}
					else
					{
						idiths = lsfrac >> 16;
						iditht = ltfrac >> 16;
					}
					if (r_fullbright.value)
						llight = 63; // for debug
					dith_switch = !dith_switch;
					*lpdest = ((byte *)acolormap)[*(lptex + idiths         + iditht         * r_affinetridesc.skinwidth) + ( (llight + ( (d_ditherlight.value) ? (shading_dither_kernel[dith_switch][Y]) : 0)) & 0xFF00)]; // mankrip
					*lpz = lzi >> 16;
				}
				lpdest++;
				lpz++;
				lzi		+= r_zistepx;
				llight	+= r_lstepx;
				lsfrac	+= r_sstepx; // s += sstep; // mankrip
				ltfrac	+= r_tstepx; // t += tstep; // mankrip
			} while (--lcount);
		}
		pspanpackage++;
	} while (pspanpackage->count != -999999);
}
And here's the code for padding the MDL skins. Padding is only performed on the top and on the bottom of the skin, because if the skin width changes, the texture mapping gets more innacurate. As a plus, this code finds, fixes and warns about bad skin vertices:

Code: Select all

void * Mod_LoadAliasSkin (void * pin, int *pskinindex, int skinwidth, int skinheight, aliashdr_t *pheader)
{
	int
		i
	,	skinsize = skinheight * skinwidth
		;
	byte	*pskin, *pinskin;
	unsigned short	*pusskin;

	pskin = Hunk_AllocName (  skinwidth      * (skinheight + 4) * r_pixbytes, loadname); // mankrip
	pinskin = (byte *)pin;
	*pskinindex = (byte *)pskin - (byte *)pheader;

	RemapBackwards_Pixels (pinskin, skinsize); // mankrip
	if (r_pixbytes == 1)
	{
		// mankrip - begin
		// copy the top line twice
		Q_memcpy (pskin            , pinskin, skinwidth);
		Q_memcpy (pskin + skinwidth, pinskin, skinwidth);
		// copy the bottom line twice
		Q_memcpy (pskin + (skinheight + 2) * skinwidth, pinskin + (skinheight - 1) * skinwidth, skinwidth);
		Q_memcpy (pskin + (skinheight + 3) * skinwidth, pinskin + (skinheight - 1) * skinwidth, skinwidth);
		// copy the center
		Q_memcpy (pskin + 2 * skinwidth, pinskin, skinsize);
		// mankrip - end
	}
	else
		Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n", r_pixbytes);

	pinskin += skinsize;

	return (void *)pinskin;
}

void Mod_LoadAliasModel (model_t *mod, void *buffer)
{
[...]
	// mankrip - begin
	int
		s
	,	t
	,	badverts = 0
		;
	// mankrip - end
[...]
	pmodel->skinheight += 4; // mankrip - extra for dithering

	// set base s and t vertices
[...]
	for (i=0 ; i<pmodel->numverts ; i++)
	{
		pstverts[i].onseam = LittleLong (pinstverts[i].onseam);
		// mankrip - begin
		// extra for dithering
		s = LittleLong (pinstverts[i].s);
		if (s < 0)
		{
			badverts = true;
			s = 0;
		}
		else if (s > pmodel->skinwidth - 1)
		{
			badverts = true;
			s = pmodel->skinwidth - 1;
		}

		t = LittleLong (pinstverts[i].t) + 2;
		if (t < 2)
		{
			badverts = true;
			t = 2;
		}
		else if (t > pmodel->skinheight - 5)
		{
			badverts = true;
			t = pmodel->skinheight - 5;
		}
		// put s and t in 16.16 format
		pstverts[i].s = (s << 16);
		pstverts[i].t = (t << 16);
		// mankrip - end
	}
	// mankrip - begin
	if (badverts)
		Con_Printf ("Mod_LoadAliasModel:\n %s has bad skin verts\n", mod->name);
	// mankrip - end
[...]
}
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
Post Reply