#include xray

export _default;
export _std_aop;
export _gamma_flash;
export _gamma_fade;
export _flares;
export _vengine;
export _shotmark;
export _shadow_vol;
export _lmap;
export _sky;
export _auto;
export _wallmark;
export _shadow;

void _auto(char *format);

// Internal function
// Set defaults for stage 0
void reset_stage0()
{
	xrBlendFunc	(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
	xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_CURRENT);
}

// Default Shader - defines the most common render-states to render an texture
void _default()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
	xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
	xrLimitStage	(1);
	xrEndPass	();
}

void _shadow()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_ZERO, BLEND_SRCCOLOR);	// modulate
	xrColorFunc	(0,TA_TEXTURE, TOP_ADD,		TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
	xrLimitStage	(1);
	xrEndPass	();
}

void _wallmark()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
	xrColorFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrLimitStage	(1);
	xrEndPass	();
}

void _sky()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_ONE, BLEND_ONE);
	xrColorFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_DISABLE,	TA_DIFFUSE);
	xrColorFunc	(1,TA_TEXTURE, TOP_ADD,		TA_CURRENT);
	xrAlphaFunc	(1,TA_TEXTURE, TOP_DISABLE,	TA_DIFFUSE);
	xrLimitStage	(2);
	xrEndPass	();
}

// Menu, Font&others - main difference - AlphaOp setted up as modulate
void _std_aop()
{
	xrBeginPass	();
	reset_stage0();
	xrAlphaFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrLimitStage(1);
	xrEndPass	();
}

// Gamma control emulation
void _gamma_flash()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_ONE, BLEND_INVSRCCOLOR);
	xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrLimitStage(1);
	xrEndPass	();
}

void _gamma_fade()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_ZERO, BLEND_INVSRCCOLOR);
	xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrLimitStage(1);
	xrEndPass	();
}

void _flares()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_ONE, BLEND_INVSRCCOLOR);
	xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_CURRENT);
	xrLimitStage(1);
	xrEndPass	();
}

void _vengine()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_SRCCOLOR, BLEND_ONE);
	xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
	xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_CURRENT);
	xrLimitStage(1);
	xrEndPass	();
}

void _shotmark()
{
	_std_aop();
}

// Since destcolor=SRCBLEND * SRC_COLOR + DESTBLEND * DEST_COLOR,
// this should result in the tri color being completely dropped
void _shadow_vol()
{
	xrBeginPass	();
	xrBlendFunc	(BLEND_ZERO, BLEND_ONE);
	xrLimitStage(0);
	xrEndPass	();
}

void _lmap()
{
	if (dwNumTStages>=2) {
		xrBeginPass	();
		xrBlendFunc	(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
		xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
		xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG2,	TA_DIFFUSE);
		xrColorFunc	(1,TA_TEXTURE, TOP_MODULATE,	TA_CURRENT);
		xrAlphaFunc	(1,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
		xrLimitStage(2);
		xrEndPass	();
	} else {
		// First pass: base texture
		xrBeginPass	();
		xrBlendFunc	(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
		xrColorFunc	(0,TA_TEXTURE, TOP_MODULATE,	TA_DIFFUSE);
		xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG2,	TA_DIFFUSE);
		xrLimitStage(1);
		xrEndPass	();

		// Second pass: lightmap-style texture
		xrBeginPass	();
		xrBlendFunc	(BLEND_ZERO, BLEND_SRCCOLOR);	// modulate
		xrColorFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
		xrAlphaFunc	(0,TA_TEXTURE, TOP_SELECTARG1,	TA_DIFFUSE);
		xrLimitStage(1); // really doesn't need this call
		xrEndPass	();
	}
}

//-------------------------------------------------- 
//Programmable shader starts here
//   params: char* in format "MABL"

int	isFirst(int pass)
{
	if (pass%dwNumTStages == 0) return true;
	else						return false;
}
int	isLast(int pass)
{
	if (pass%dwNumTStages == (dwNumTStages-1))	return true;
	else										return false;
}

void	Parse(int op, int stage, int bFirst) {
	if (bFirst) {
		// Use diffuse color of primitives
		switch (op)
		{
		case 'L':
		case 'l':
			xrBlendFunc	(BLEND_ONE, BLEND_ZERO);
			xrColorFunc	(stage,TA_TEXTURE, TOP_ADD,		   TA_DIFFUSE);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_SELECTARG2, TA_DIFFUSE);
			break;
		case 'M':	// multiplicative blend
		case 'm':	// multiplicative blend
			xrBlendFunc	(BLEND_ZERO, BLEND_SRCCOLOR);
			xrColorFunc	(stage,TA_TEXTURE, TOP_MODULATE,   TA_DIFFUSE);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_SELECTARG1, TA_DIFFUSE);
			break;
		case 'A':	// additive blend
		case 'a':	// additive blend
			xrBlendFunc	(BLEND_ONE, BLEND_ONE);
			xrColorFunc	(stage,TA_TEXTURE, TOP_MODULATE,   TA_DIFFUSE);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_SELECTARG1, TA_DIFFUSE);
			break;
		case 'B':	// alpha-blend
		case 'b':	// alpha-blend
			xrBlendFunc	(BLEND_SRCALPHA,   BLEND_INVSRCALPHA);
			xrColorFunc	(stage,TA_TEXTURE, TOP_MODULATE,   TA_DIFFUSE);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_SELECTARG1, TA_DIFFUSE);
			break;
		}
	} else {
		switch (op)
		{
		case 'L':
		case 'l':
			msg("Invalid shader operation '%c' at stage %d",op,stage);
			break;
		case 'M':	// multiplicative blend
		case 'm':	// multiplicative blend
			xrColorFunc	(stage,TA_TEXTURE, TOP_MODULATE,	TA_CURRENT);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_MODULATE,	TA_CURRENT);
			break;
		case 'A':	// additive blend
		case 'a':	// additive blend
			xrColorFunc	(stage,TA_TEXTURE, TOP_ADD,			TA_CURRENT);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_MODULATE,	TA_CURRENT);
			break;
		case 'B':	// alpha-blend
		case 'b':	// alpha-blend
			xrColorFunc	(stage,TA_TEXTURE, TOP_BLENDTEXTUREALPHA, TA_CURRENT);
			xrAlphaFunc	(stage,TA_TEXTURE, TOP_MODULATE,	TA_CURRENT);
			break;
		}
	}
}

void _auto(char *format)
{
	int		iCurrentPass;
	char	*pF;
	int		bInside;
	DWORD	stage;

	pF				= format;
	iCurrentPass	= 0;
	bInside			= false;
	while	(*pF) {
		stage = iCurrentPass%dwNumTStages;
		if (isFirst(iCurrentPass)) {
			bInside	= true;
			xrBeginPass	();
			Parse((int)*pF,(int)stage,(int)true);
		} else {
			Parse((int)*pF,(int)stage,(int)false);
		}
		if (isLast(iCurrentPass)) {
			bInside = false;
			xrLimitStage(stage+1);
			xrEndPass	();
		}

		iCurrentPass++;
		pF++;
	}
	if (bInside) {
		xrLimitStage(iCurrentPass%dwNumTStages);
		xrEndPass	();
	}
}
