
// The data structure from the vertex shader to the geometry shader
struct VS_to_GS {
	float4 Pos : SV_POSITION;
	float Selection : COLOR;
};

// The data structure from the geometry shader to the pixel shader
struct GS_to_PS {
	float4 Pos : SV_POSITION;
	float2 Pos_Quad : TEXCOORD0;
	float Selection : COLOR;
};

// Edit preview
#define RadiansPerDegree 0.01745329252f
#define PV_A (Arg[0].xy)
#define PV_B (Arg[1].xy)
#define PV_DataIndex round(Arg[1].w)
	#define DataIndex_Pos 0
	#define DataIndex_UV1 1
	#define DataIndex_UV2 2
#define PV_Func round(Arg[0].w)
	#define Func_None 0
	#define Func_Move 1
	#define Func_Rotate 2
	#define Func_Scale 3
float2 Rotate2D(float2 V, float Degrees) {
	float Radians;
	Radians = Degrees * RadiansPerDegree;
	return float2((V.x * cos(Radians)) + (V.y * -sin(Radians)), (V.x * sin(Radians)) + (V.y * cos(Radians)));
}
float2 EditPreview_UV(float2 UV,float Selection) {
	float2 TransUV = float2(0.0f, 0.0f);
	if (PV_DataIndex == DataIndex_UV2) {
		switch(PV_Func) {
		case Func_None:
			// Do nothing
			TransUV = UV;
		break;
		case Func_Move:
			// Move by A
			TransUV = UV + PV_A;
		break;
		case Func_Rotate:
			TransUV = Rotate2D((UV - PV_B), PV_A.x) + PV_B;
		break;
		case Func_Scale:
			// Scale by A around B
			TransUV = ((UV - PV_B) * PV_A) + PV_B;
		break;
		}
	} else {
		// Do nothing
		TransUV = UV;
	}
	return lerp(UV,TransUV,Selection);
}

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_to_GS VS( VS_structure input ) {
	VS_to_GS output = (VS_to_GS)0;
	
	// Convert vertice positions from object space to 2D projection
	output.Pos = mul(float4(EditPreview_UV(input.Tex.zw,input.Selected),0.0f,1.0f),WorldToImage);
	
	output.Selection = input.Selected;
	
	return output;
}

#define THICKNESS 3.8f

//--------------------------------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------------------------------
[maxvertexcount(24)]
void GS( triangle VS_to_GS input[3], inout TriangleStream<GS_to_PS> TriStream ) {
	GS_to_PS output = (GS_to_PS)0;
	int I;
	int J;
	for( I = 0; I < 3; I++ ) {
		J = (I + 1) % 3;
		
		float2 Direction = normalize(input[I].Pos.xy - input[J].Pos.xy);
		float2 OffsetA = float2(Direction.x * THICKNESS / Dimensions.x, Direction.y * THICKNESS / Dimensions.y);
		float2 OffsetB = float2(Direction.y * THICKNESS / Dimensions.x, -Direction.x * THICKNESS / Dimensions.y);
		
		output.Selection = input[I].Selection;
		output.Pos = input[I].Pos + float4(OffsetB + OffsetA,0.0f,0.0f);
		output.Pos_Quad = float2(1.0f, 1.0f);
		TriStream.Append( output );
		output.Pos = input[I].Pos + float4(-OffsetB + OffsetA,0.0f,0.0f);
		output.Pos_Quad = float2(-1.0f, 1.0f);
		TriStream.Append( output );
		output.Pos = input[I].Pos + float4(OffsetB,0.0f,0.0f);
		output.Pos_Quad = float2(1.0f, 0.0f);
		TriStream.Append( output );
		output.Pos = input[I].Pos + float4(-OffsetB,0.0f,0.0f);
		output.Pos_Quad = float2(-1.0f, 0.0f);
		TriStream.Append( output );
		
		output.Selection = input[J].Selection;
		output.Pos = input[J].Pos + float4(OffsetB,0.0f,0.0f);
		output.Pos_Quad = float2(1.0f, 0.0f);
		TriStream.Append( output );
		output.Pos = input[J].Pos + float4(-OffsetB,0.0f,0.0f);
		output.Pos_Quad = float2(-1.0f, 0.0f);
		TriStream.Append( output );
		output.Selection = input[J].Selection;
		output.Pos = input[J].Pos + float4(OffsetB - OffsetA,0.0f,0.0f);
		output.Pos_Quad = float2(1.0f, -1.0f);
		TriStream.Append( output );
		output.Pos = input[J].Pos + float4(-OffsetB - OffsetA,0.0f,0.0f);
		output.Pos_Quad = float2(-1.0f, -1.0f);
		TriStream.Append( output );

		TriStream.RestartStrip();
	}
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( GS_to_PS input) : SV_Target {
	return float4(InstanceColor.rgb, InstanceColor.a * input.Selection * saturate(1.0f - length(input.Pos_Quad)));
}
