#define LINEAR_CLAMP_MAP(x) \
		MipFilter[x] = LINEAR; \
		MagFilter[x] = LINEAR; \
		MinFilter[x] = LINEAR; \
		AddressU[x] = CLAMP; \
		AddressV[x] = CLAMP

#define LINEAR_WRAP_MAP(x) \
		MipFilter[x] = LINEAR; \
		MagFilter[x] = LINEAR; \
		MinFilter[x] = LINEAR; \
		AddressU[x] = WRAP; \
		AddressV[x] = WRAP

#define DIFF_MAP LINEAR_WRAP_MAP(0)
#define NORM_MAP LINEAR_CLAMP_MAP(1)
#define CHAN_MAP LINEAR_CLAMP_MAP(2)
#define APP_MAP LINEAR_CLAMP_MAP(3)

#define DEPTH_ENABLE \
		ZEnable = TRUE; \
		ZWriteEnable = TRUE

#define DEPTH_DISABLE \
		ZEnable = FALSE; \
		ZWriteEnable = FALSE

#define ALPHA_BLEND_ENABLE \
		AlphaBlendEnable = TRUE; \
		SrcBlend = SRCALPHA; \
		DestBlend = INVSRCALPHA

#define ALPHA_BLEND_DISABLE \
		AlphaBlendEnable = FALSE; \
		SrcBlend = ONE; \
		DestBlend = ZERO

#define STENCIL_ENABLE  StencilEnable = TRUE
#define STENCIL_DISABLE StencilEnable = FALSE
#define CULL_DISABLE CullMode = NONE
#define CULL_ENABLE  CullMode = CW
#define CULL_REVERSE CullMode = CCW

sampler DiffMap : register(s0);
sampler NormMap : register(s1);
sampler ChanMap : register(s2);
sampler AppMap  : register(s3);
sampler ShadowMap : register(s4);

float4x4 o2pMat		: WORLDVIEWPROJECTION;	 // object to perspective matrix
float4x4 o2wMat		: WORLD;				 // object to world matrix

float4x4 mat0		: MAT0;
float4x4 mat1		: MAT1;

#ifdef _OPENFIST_
float4   xyzw0		: XYZW0;
float4	 wLitPos	: LPOS0;
float3	 cLitClr    : LCLR0;
float    nLitInt    : LINT0;
float    nAmbInt    : AMBINT;
float3	 cAmbClr    : AMBCLR;
#else
float4	 wLitPos//	: LPOS0
<
    //string SasUiControl     = "Numeric";        // a.k.a. UIWidget
    //string SasUiLabel       = "Light Position"; // a.k.a. UIName
    //string SasUiDescription = "The position of light";
    // bool SasUiVisible = false; //XSI bug
    string SasBindAddress = "Sas.PointLight[0].Position";
>;// = { 100, 100, 100, 0 };

float3	 cLitClr
<
    //string SasUiControl     = "ColorPicker";
    //string SasUiLabel       = "Light Color"; // XSI bug
    //string SasUiDescription = "The color of the light";
    string SasBindAddress = "Sas.PointLight[0].Color"; //"Light01Color";//"Sas.Light[0].Color";
>;/// = {1.0f, 0.85f, 0.85f};

float nLitInt// : LINT
<
    string SasUiControl = "Numeric";
    string SasUiLabel   = "Light Intensity";
    float SasUiMax = 1.0f;
    float SasUiMin = 0.0f;
> = { 1.0f };

float3	 cAmbClr// : AMBCLR
<
    string SasUiControl     = "ColorPicker";
    string SasUiLabel       = "Ambient Light Color"; // XSI bug
    string SasUiDescription = "The color of the ambient light";
    //string SasBindAddress = "Sas.AmbientLight[0].Color"; XSI Bug - AmbientLight is slammed to 0.4,,,
> = {0.85f, 0.85f, 1.0f};

float nAmbInt// : AMBLINT
<
    string SasUiControl     = "Numeric";
    string SasUiLabel       = "Ambient Light Intensity";
    float SasUiMax = 1.0f;
    float SasUiMin = 0.0f;
> = { 0.3f };

float4   xyzw0		: XYZW0
<
    string SasUiControl = "Slider";
    string SasUiLabel   = "Fade Amount (for Unlit Fade)";
    float SasUiMax = 1.0f;
    float SasUiMin = 0.0f;
> = { 1.0f, 0, 0, 0 };
#endif


float4	 wCamPos	: CAMERAPOSITION;
float4   bBoneTrans[96] : BONETRANS;
float4 b2oBoneQuats[96] : BONEROTS;



//variable prefix 'n' = value/numbers (no space),
//				  'o' = object space,
//				  'w' = world space,
//				  'v' = view space,
//				  't' = tangent space,
//				  'p' = perspective space (final- screen space)
//                'c' = color space [0...1]
//                'b' = bone space (each bone's origin)

/*-----------------------------------------------------------------------------------
||		Generic Lighting Equations
\*----------------------------------------------------------------------------------*/


float3 CalcLitClr(float3 surfaceClr, float3 litClr, float litInt)
{
    return surfaceClr * litClr.rgb * litInt;
}

float3 CalcLitClr(float3 surfaceClr, float3 litClr, float litInt, float3 toLit, float3 normal)
{
	return CalcLitClr(surfaceClr, litClr, litInt) * saturate(dot( normal, toLit ));
}

float3 CalcLitClr(float3 surfaceClr, float3 litClr, float litInt, float3 toLit, float3 normal, float3 halfAngle, float specularity, float glossiness = 0.5f)
{
	const int MaxGlossiness = 4096;

	float nSpecularIncidence = saturate(dot( normal, halfAngle ));
	float nSpecContribution	 = pow(nSpecularIncidence, pow((MaxGlossiness*glossiness), glossiness)); //normalizes visual glossiness, such that 0.5 glossiness appears about half as glossy as 1.0
	float3 specularLitClr = nSpecContribution * litInt * litClr * specularity;
	return CalcLitClr(surfaceClr, litClr, litInt, toLit, normal) + specularLitClr;
}

/*-----------------------------------------------------------------------------------
||		Generic Math Equations
\*----------------------------------------------------------------------------------*/

//the scalar is stored in the w
float4 mulQuat(float4 q2, float4 q1) // this function is taken from a math book that multiplies right to left, so by swapping q2 and q1 in the parameter list, this algorithm becomes left to right
{
	float s1 = q1.w;
	float s2 = q2.w;

	float3 v1 = q1.xyz;
	float3 v2 = q2.xyz;

	//mathematically written: s1*s2 - dot(v1,v2) + s1*v2 + s2*v1 + cross(v1, v2)
	return float4(s1*v2 + s2*v1 + cross(v1, v2), s1*s2 - dot(v1,v2));
}

// quaternion conjugate
float4 conjugate(float4 q) { return float4(-q.x, -q.y, -q.z, q.w); }
float4 rotateVecByQuat(float4 v, float4 q) { return mulQuat( mulQuat(conjugate(q), v), q ); }

// bone to object space transform (rotates vert around the bone center and than transforms it to a position [weighted for 4 bones])
float4 b2oTransform(float4 bPos, float4 nBlendIdxs, float4 nBlendWgts)
{
    float4 oPos = float4(0,0,0,0);
    int bone;
    bone = nBlendIdxs.x; oPos += (rotateVecByQuat(bPos, b2oBoneQuats[bone]) + bBoneTrans[bone]) * nBlendWgts.x;
    bone = nBlendIdxs.y; oPos += (rotateVecByQuat(bPos, b2oBoneQuats[bone]) + bBoneTrans[bone]) * nBlendWgts.y;
    bone = nBlendIdxs.w; oPos += (rotateVecByQuat(bPos, b2oBoneQuats[bone]) + bBoneTrans[bone]) * nBlendWgts.w;
    bone = nBlendIdxs.z; oPos += (rotateVecByQuat(bPos, b2oBoneQuats[bone]) + bBoneTrans[bone]) * nBlendWgts.z;
    oPos.w = 1;
    return oPos;
}

float4 sumRotations(float4 v, float4 nBlendIdxs, float4 nBlendWgts)
{
    float4 sum = float4(0,0,0,0);
    int bone;
    bone = nBlendIdxs.x; sum += rotateVecByQuat(v, b2oBoneQuats[bone]) * nBlendWgts.x;
    bone = nBlendIdxs.y; sum += rotateVecByQuat(v, b2oBoneQuats[bone]) * nBlendWgts.y;
    bone = nBlendIdxs.z; sum += rotateVecByQuat(v, b2oBoneQuats[bone]) * nBlendWgts.z;
    bone = nBlendIdxs.w; sum += rotateVecByQuat(v, b2oBoneQuats[bone]) * nBlendWgts.w;
    return sum;
}

/*+---------------------------------------------------------------------------------------+*\
||                  Composite An Alpha Quad Into the Scene
\*+---------------------------------------------------------------------------------------+*/

struct CompositeInOut
{
    float4 pPos  : POSITION;  // vertex pPos
    float4 tTex  : TEXCOORD0;
};

CompositeInOut vsComposite(CompositeInOut vIn)
{
    return vIn;
};

float4 psComposite(CompositeInOut pIn) : COLOR0
{
    return tex2D(DiffMap, pIn.tTex);
    //float4 app  =  tex2D(AppMap, pIn.tTex);
    //float4 fff       = diff; fff+=float4(0, 0.01f, 0, 0);
    //return app*(1-diff.a) + diff*diff.a; //float4(fff.a, fff.a, fff.a, 1);
}

technique Composite
{
    pass P0
    {
		LINEAR_CLAMP_MAP(0);
		APP_MAP;

		DEPTH_DISABLE;
		ALPHA_BLEND_ENABLE;
		STENCIL_DISABLE;

        vertexshader = compile vs_2_0 vsComposite();
        pixelshader  = compile ps_2_0 psComposite();
    }
}

/*+---------------------------------------------------------------------------------------+*\
||  CompositeMask - Composites An Alpha-Textured Quad Using an Image Mask (white=opaque, black=clear)
\*+---------------------------------------------------------------------------------------+*/

struct CompositeMaskInOut
{
    float4 pPos  : POSITION;  // vertex pPos
    float4 tTex  : TEXCOORD0;
};

CompositeMaskInOut vsCompositeMask(CompositeMaskInOut vIn)
{
    return vIn;
};

float4 psCompositeMask(CompositeMaskInOut pIn) : COLOR0
{
    float4 cImageColor = tex2D(DiffMap, pIn.tTex); // reg 0
    float4 cMaskColor  = tex2D(NormMap, pIn.tTex); // reg 1
    float  nMaskValue  = cMaskColor.r*cMaskColor.a;
    return float4(cImageColor.r*nMaskValue,
                  cImageColor.g*nMaskValue,
                  cImageColor.b*nMaskValue,
                  cImageColor.a           );
}

technique CompositeMask
{
    pass P0
    {
		LINEAR_CLAMP_MAP(0);
		APP_MAP;

		DEPTH_DISABLE;
		ALPHA_BLEND_ENABLE;
		STENCIL_DISABLE;

        vertexshader = compile vs_2_0 vsCompositeMask();
        pixelshader  = compile ps_2_0 psCompositeMask();
    }
}

/*-----------------------------------------------------------------------------------
||		CompositeGlowMap   Composites a Glow map into the scene
\*----------------------------------------------------------------------------------*/

struct CompositeGlowMapIn
{
	float4 oPos : POSITION;
	float2 tTex : TEXCOORD0; // UVs
};

struct CompositeGlowMapOut
{
	float4 pPos : POSITION;
	float2 tTex : TEXCOORD0;
};

CompositeGlowMapOut vsCompositeGlowMap(CompositeGlowMapIn vIn)
{
	CompositeGlowMapOut vOut;
	vOut.pPos = mul(vIn.oPos, o2pMat);
	vOut.tTex = vIn.tTex;
		return vOut;
}

float4 psCompositeGlowMap(CompositeGlowMapOut pIn) : COLOR0
{
	return tex2D(DiffMap, pIn.tTex);
}

// Renders a full screen quad with a glow map
technique CompositeGlowMap
{
	pass p0
	{
		LINEAR_CLAMP_MAP(0);

		DEPTH_DISABLE;
		//ALPHA_BLEND_ENABLE;
		STENCIL_DISABLE;
        CULL_ENABLE;

        AlphaBlendEnable = TRUE;
		SrcBlend = SRCALPHA;
		DestBlend = ONE;
		BlendOp = ADD;

		VertexShader = compile vs_2_0 vsCompositeGlowMap();
		PixelShader = compile ps_2_0 psCompositeGlowMap();
	}

}




/*+---------------------------------------------------------------------------------------+*\
||                                  Cone Filter Blur
\*+---------------------------------------------------------------------------------------+*/

// this is the slow version, doing things in the pixel shader
struct ConeFilterBlurIn
{
    float4 pPos  : POSITION;
    float4 tTex  : TEXCOORD0;
};

struct ConeFilterBlurOut
{
    float4 tTex  : TEXCOORD0;
    float4 pPos   : POSITION;
};

/* this is the correct version - optimized in the vert shader
struct ConeFilterBlurIn
{
    float4 pPos  : POSITION;
    float4 tTex  : TEXCOORD0;
};

struct ConeFilterBlurOut
{
    float4 pPos   : POSITION;
    float4 top    : TEXCOORD0;
    float4 bottom : TEXCOORD1;
};
*/
ConeFilterBlurOut vsConeFilterBlur(ConeFilterBlurIn vIn)
{
    ConeFilterBlurOut vOut;
    vOut.pPos  = vIn.pPos;
    vOut.tTex = vIn.tTex;

/* the vertex shader is currently not run through our post processing pipe line, so i will dupe this code in the vert shader
	float2 pixelSize = xyzw0.xy;
	float  currentIteration = xyzw0.z;

    float2 halfPixelSize = pixelSize * 0.5f;
    float2 dUV = (pixelSize * currentIteration) -  halfPixelSize;

    // i don't know why i have to do this (?)
    float4 mytTex = vIn.tTex;
    //mytTex.x = mytTex.x + halfPixelSize;
    //mytTex.y = mytTex.y + halfPixelSize;

    vOut.pPos  = vIn.pPos;
    vOut.top.xy    = float2(mytTex.x - dUV.x, mytTex.y - dUV.y);
    vOut.top.zw    = float2(mytTex.x + dUV.x, mytTex.y - dUV.y);
    vOut.bottom.xy = float2(mytTex.x - dUV.x, mytTex.y + dUV.y);
    vOut.bottom.zw = float2(mytTex.x + dUV.x, mytTex.y + dUV.y);*/
	    return vOut;
};

float4 psConeFilterBlur(ConeFilterBlurOut pIn) : COLOR0
{
    float4 color = {0.0f, 0.0f, 0.0f, 0.0f};

	float2 pixelSize = xyzw0.xy;
	float  currentIteration = xyzw0.z;

    float2 halfPixelSize = pixelSize * 0.5f;
    float2 dUV = (pixelSize * currentIteration) -  halfPixelSize;

    float4 top;
    float4 bottom;

    top.xy    = float2(pIn.tTex.x - dUV.x, pIn.tTex.y - dUV.y);
    top.zw    = float2(pIn.tTex.x + dUV.x, pIn.tTex.y - dUV.y);
    bottom.xy = float2(pIn.tTex.x - dUV.x, pIn.tTex.y + dUV.y);
    bottom.zw = float2(pIn.tTex.x + dUV.x, pIn.tTex.y + dUV.y);

    color += tex2D(DiffMap, top.xy);
    color += tex2D(DiffMap, top.zw);
    color += tex2D(DiffMap, bottom.xy);
    color += tex2D(DiffMap, bottom.zw);
    return color *= 0.25f;
}

technique ConeFilterBlur
{
    pass P0
    {
		LINEAR_CLAMP_MAP(0); // Diffuse Map

		DEPTH_DISABLE;
		ALPHA_BLEND_DISABLE;
		STENCIL_DISABLE;

        vertexshader = compile vs_2_0 vsConeFilterBlur();
        pixelshader  = compile ps_2_0 psConeFilterBlur();
    }
}

/*+---------------------------------------------------------------------------------------+*\
||                                  Gaussian 3x3 Filter Blur
\*+---------------------------------------------------------------------------------------+*/

static const int kKernelSize = 9; // 3x3 kernel

static const float kPixelKernel[kKernelSize] =
{
	-4.0f, -3.0f, -2.0f,
    -1.0f, 0.0f, 1.0f,
    2.0f, 3.0f, 4.0f,
};

// r == (u² + v²) == blur radius
// N == Number of dimensions
// S == Standard deviation
// G(u,v) = (1 / (2pi * S²)^(N/2)) * e^(-r² / 2S²)
static const float kBlurWeights[kKernelSize] =
{
	0.00013382983f,
    0.0044318349,
    0.053990804,
    0.24196999,
    0.39894107,
    0.24196999,
    0.053990804,
    0.0044318349,
    0.00013382983,
};

float4 GaussianBlurVertPS(float2 uv : TEXCOORD0) : COLOR0
{
	float4 color = 0;

    for(int i = 0; i < kKernelSize; i++)
    {
        color += tex2D(DiffMap, uv + float2(0,(kPixelKernel[i]) / xyzw0.y)) * kBlurWeights[i];
    }

    return color;
}

float4 GaussianBlurHorzPS(float2 uv : TEXCOORD0) : COLOR0
{
	float4 color = 0;

    for(int i = 0; i < kKernelSize; i++)
    {
		color += tex2D(DiffMap, uv + float2((kPixelKernel[i]) / xyzw0.x, 0)) * kBlurWeights[i];
    }

    return color;
}

// Renders a quad aligned to screen in screen space
technique GaussianBlurVert
{
	pass p0
	{
		LINEAR_CLAMP_MAP(0); // Diffuse Map

		DEPTH_ENABLE;
		ALPHA_BLEND_DISABLE;
		STENCIL_DISABLE;

		VertexShader = compile vs_2_0 vsComposite();
		PixelShader  = compile ps_2_0 GaussianBlurVertPS();
	}
}

// Renders a quad aligned to screen in screen space
technique GaussianBlurHorz
{
	pass p0
	{
		LINEAR_CLAMP_MAP(0); // Diffuse Map

		DEPTH_ENABLE;
		ALPHA_BLEND_DISABLE;
		STENCIL_DISABLE;

		VertexShader = compile vs_2_0 vsComposite();
		PixelShader  = compile ps_2_0 GaussianBlurHorzPS();
	}
}

/*-----------------------------------------------------------------------------------
||		Sobel Filter   Edge Detection
\*----------------------------------------------------------------------------------*/

static const float kSobelFilterXAxis[kKernelSize] =
{
    -1.0f, 0.0f, 1.0f,
    -2.0f, 0.0f, 2.0f,
    -1.0f, 0.0f, 1.0f,
};

static const float kSobelFilterYAxis[kKernelSize] =
{
     1.0f,  2.0f,  1.0f,
     0.0f,  0.0f,  0.0f,
    -1.0f, -2.0f, -1.0f,
};

static const float3 kLuminanceConv = { 0.2125f, 0.7154f, 0.0721f };

float4 SobelFilterPS(float2 uv : TEXCOORD0) : COLOR0
{
	float4 diffuseColor = tex2D(DiffMap, uv);
	float4 color = 0;

    for(int i = 0; i < kKernelSize; i++)
    {
		float2 sobelFilterUV = { kSobelFilterXAxis[i] / xyzw0.x, kSobelFilterYAxis[i] / xyzw0.y };
        color += abs(diffuseColor - tex2D(DiffMap, uv + sobelFilterUV));
    }

    return saturate(dot(kLuminanceConv, color));
}

technique SobelFilter
{
	pass p0
	{
		MipFilter[0] = POINT;
		MagFilter[0] = POINT;
		MinFilter[0] = POINT;
		ZEnable = FALSE;
		StencilEnable = FALSE;
		AlphaBlendEnable = FALSE;
		AddressU[0]  = CLAMP;
		AddressV[0]  = CLAMP;
 		Vertexshader = compile vs_2_0 vsComposite();
		Pixelshader  = compile ps_2_0 SobelFilterPS();
	}
}

/*-----------------------------------------------------------------------------------
||		SSAA   Screen Space Anti-Alias
\*----------------------------------------------------------------------------------*/


float4 SSAAPS(float2 uv : TEXCOORD0) : COLOR0
{
    float4 blurmap = tex2D(AppMap, uv);

    float4 tap[9];
	float dx = (1.0f / xyzw0.x);
	float dy = (1.0f / xyzw0.y);

    // 0 1 2
    // 3 4 5
    // 6 7 8

	float4 d = float4(dx, dy, 0.0, -dy);

    tap[0] = tex2D(DiffMap, uv - d.xy);
	tap[1] = tex2D(DiffMap, uv - d.zy);
	tap[2] = tex2D(DiffMap, uv + d.xw);

	tap[3] = tex2D(DiffMap, uv - d.xz);
	tap[4] = tex2D(DiffMap, uv);
	tap[5] = tex2D(DiffMap, uv + d.xz);

	tap[6] = tex2D(DiffMap, uv - d.xw);
	tap[7] = tex2D(DiffMap, uv + d.zy);
	tap[8] = tex2D(DiffMap, uv + d.xy);

    float4 c;
    c = tap[0] + tap[1] + tap[2] + tap[3] + tap[4] + tap[5] + tap[6] + tap[7] + tap[8];
	c /= 9.0f;
	c.a = 1.0f;
    c = lerp(tap[4], c, blurmap.x);
    return saturate(c);
}

technique SSAA
{
	pass p0
	{
		MipFilter[0] = POINT;
		MagFilter[0] = POINT;
		MinFilter[0] = POINT;
		ZEnable = FALSE;
		StencilEnable = FALSE;
		AlphaBlendEnable = FALSE;
		AddressU[0]  = CLAMP;
		AddressV[0]  = CLAMP;
 		vertexshader = compile vs_2_0 vsComposite();
		pixelshader  = compile ps_2_0 SSAAPS();
	}
}

/*-----------------------------------------------------------------------------------
||		Canny Filter   Edge Detection
\*----------------------------------------------------------------------------------*/

float4 CannyEdgeStregthPS(float2 uv : TEXCOORD0) : COLOR0
{
    const float PI = 3.1415926535897932384626433832795;
    float4 tap[9];

    float dx = (1.0f / xyzw0.x);
	float dy = (1.0f / xyzw0.y);
	float4 d = float4(dx, dy, 0.0, -dy);

    // 0 1 2    X -1  0  1   Y  1  2  1
    // 3 4 5      -2  0  2      0  0  0
    // 6 7 8      -1  0  1     -1 -2 -1

    tap[0] = tex2D(DiffMap, uv - d.xy);
	tap[1] = tex2D(DiffMap, uv - d.zy);
	tap[2] = tex2D(DiffMap, uv + d.xw);

	tap[3] = tex2D(DiffMap, uv - d.xz);
	//tap[4] = tex2D(DiffMap, uv);
	tap[5] = tex2D(DiffMap, uv + d.xz);

	tap[6] = tex2D(DiffMap, uv - d.xw);
	tap[7] = tex2D(DiffMap, uv + d.zy);
	tap[8] = tex2D(DiffMap, uv + d.xy);

	float4 v	   = float4(-2.0, -1.0, 1.0, 2.0);
    float2 dir     = float2(0.0, 0.0);

    // X first
    dir.x += tap[0]* v.yyyy;
    dir.x += tap[2]* v.zzzz;

    dir.x += tap[3]* v.xxxx;
    dir.x += tap[5]* v.wwww;

    dir.x += tap[6]* v.yyyy;
    dir.x += tap[8]* v.zzzz;

    // Y next
    dir.y += tap[0]* v.zzzz;
    dir.y += tap[1]* v.wwww;
    dir.y += tap[2]* v.zzzz;

    dir.y += tap[6]* v.yyyy;
    dir.y += tap[7]* v.xxxx;
    dir.y += tap[8]* v.yyyy;

    return float4(0,0,0,0); // temp - return early so it compiles (i was getting a 'too many arithmetic slots' error)

    // Calc edge strength and direction
    //dir = dot(dir, 0.333333);

    // Used to be:
    // float mag = length(dir);
    // mag = saturate(mag);

    float mag = normalize(dir);
    //float mag = abs(dir.x) + abs(dir.y);

    float qd = 0.0;
    if(mag > 0.0)
    {
        float theta = atan2(dir.y, dir.x);
        qd = (abs(theta) / PI) + 0.125;

        if(qd >= 1.0) { qd = 0.0; }
        qd = saturate(qd);
    }

    return float4(mag, qd, 0.0, 1.0); // this is never being reached!!
}


technique CannyEdgeStrength
{
	pass p0
	{
		MipFilter[0] = POINT;
		MagFilter[0] = POINT;
		MinFilter[0] = POINT;
		ZEnable = FALSE;
		StencilEnable = FALSE;
		AlphaBlendEnable = FALSE;
		AddressU[0]  = CLAMP;
		AddressV[0]  = CLAMP;
 		vertexshader = compile vs_2_0 vsComposite();
		pixelshader  = compile ps_2_0 CannyEdgeStregthPS();
	}
}

float4 CannyEdgeNonmaximalSuppressionPS(float2 uv : TEXCOORD0) : COLOR0
{
    float PI = 3.1415926535897932384626433832795;

    // source format = { mag, dir, 0, 0 }

    float threshold = 0.1;
    float4 magdir = tex2D(DiffMap, uv);
    float mag = magdir.x;
    float dir = magdir.y;
    dir = floor(dir * 4);
    float4 fwd;
    float4 back;
    float4 color = float4(0.0, 0.0, 0.0, 0.0);

    //if(mag < threshold) { color = float4(0.0, 0.0, 0.0, 0.0); }

    float dx = (1.0f / xyzw0.x) * mag;
	float dy = (1.0f / xyzw0.y) * mag;
    float4 d = float4(dx, dy, 0.0, -dy);

    if(dir == 0)
    {
        fwd  = tex2D(DiffMap, uv - d.xz);
        back = tex2D(DiffMap, uv + d.xz);
    }
    else if(dir == 1)
    {
        fwd  = tex2D(DiffMap, uv + d.xw);
        back = tex2D(DiffMap, uv - d.xw);
    }
    else if(dir == 2)
    {
        fwd  = tex2D(DiffMap, uv - d.zy);
        back = tex2D(DiffMap, uv + d.zy);
    }
    else //if(dir == 3)
    {
        fwd  = tex2D(DiffMap, uv - d.xy);
        back = tex2D(DiffMap, uv + d.xy);
    }

    if((mag > fwd.x) || (mag > back.x))
        color = float4(mag, mag, mag, 1.0);

	if(mag < threshold) { color = float4(0.0, 0.0, 0.0, 0.0); }

    return color;
}

technique CannyEdgeNonmaximalSuppression
{
	pass p0
	{
		MipFilter[0] = POINT;
		MagFilter[0] = POINT;
		MinFilter[0] = POINT;
		ZEnable = FALSE;
		StencilEnable = FALSE;
		AlphaBlendEnable = FALSE;
		AddressU[0]  = CLAMP;
		AddressV[0]  = CLAMP;
 		vertexshader = compile vs_2_0 vsComposite();
		pixelshader  = compile ps_2_0 CannyEdgeNonmaximalSuppressionPS();
	}
}