float4x4 gTransform : WORLDVIEWPROJECTION; Texture2D gSpriteTexture; float2 gTextureSize; SamplerState samPoint { Filter = MIN_MAG_MIP_POINT; AddressU = WRAP; AddressV = WRAP; }; BlendState EnableBlending { BlendEnable[0] = TRUE; SrcBlend = SRC_ALPHA; DestBlend = INV_SRC_ALPHA; }; RasterizerState BackCulling { CullMode = BACK; }; //SHADER STRUCTS //************** struct VS_DATA { int Channel : TEXCOORD2; //Texture Channel float3 Position : POSITION; //Left-Top Character Quad Starting Position float4 Color : COLOR; //Color of the vertex float2 TexCoord : TEXCOORD0; //Left-Top Character Texture Coordinate on Texture float2 CharSize : TEXCOORD1; //Size of the character (in screenspace) }; struct GS_DATA { float4 Position : SV_POSITION; //HOMOGENEOUS clipping space position float4 Color : COLOR; //Color of the vertex float2 TexCoord : TEXCOORD0; //Texcoord of the vertex int Channel : TEXCOORD1; //Channel of the vertex }; //VERTEX SHADER //************* VS_DATA MainVS(VS_DATA input) { return input; } //GEOMETRY SHADER //*************** void CreateVertex(inout TriangleStream<GS_DATA> triStream, float3 pos, float4 col, float2 texCoord, int channel) { //Create a new GS_DATA object GS_DATA gsData = (GS_DATA) 0; //Fill in all the fields gsData.Position = mul(float4(pos, 1), gTransform); gsData.Color = col; gsData.TexCoord = texCoord; gsData.Channel = channel; //Append it to the TriangleStream triStream.Append(gsData); } [maxvertexcount(4)] void MainGS(point VS_DATA vertex[1], inout TriangleStream<GS_DATA> triStream) { //Create a Quad using the character information of the given vertex //Note that the Vertex.CharSize is in screenspace, TextureCoordinates aren't ;) [Range 0 > 1] float2 clipSize = vertex[0].CharSize / gTextureSize; //1. Vertex Left-Top CreateVertex(triStream, vertex[0].Position, vertex[0].Color, vertex[0].TexCoord, vertex[0].Channel); //2. Vertex Right-Top CreateVertex(triStream, vertex[0].Position + float3(vertex[0].CharSize.x, 0.0f, 0.0f), vertex[0].Color, vertex[0].TexCoord + float2(clipSize.x, 0.0f), vertex[0].Channel); //3. Vertex Left-Bottom CreateVertex(triStream, vertex[0].Position + float3(0.0f, vertex[0].CharSize.y, 0.0f), vertex[0].Color, vertex[0].TexCoord + float2(0.0f, clipSize.y), vertex[0].Channel); //4. Vertex Right-Bottom CreateVertex(triStream, vertex[0].Position + float3(vertex[0].CharSize.x, vertex[0].CharSize.y, 0.0f), vertex[0].Color, vertex[0].TexCoord + float2(clipSize.x, clipSize.y), vertex[0].Channel); } //PIXEL SHADER //************ float4 MainPS(GS_DATA input) : SV_TARGET { //Sample the texture and return the correct channel [Vertex.Channel] //You can iterate a float4 just like an array, using the index operator float4 pixelColor = gSpriteTexture.Sample(samPoint, input.TexCoord)[input.Channel]; //Also, don't forget to colorize ;) [Vertex.Color] pixelColor *= input.Color; return pixelColor; } DepthStencilState EnableDepth { DepthEnable = TRUE; DepthWriteMask = ALL; }; // Default Technique technique10 Default { pass p0 { SetRasterizerState(BackCulling); SetBlendState(EnableBlending, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF); SetDepthStencilState(EnableDepth, 0); SetVertexShader(CompileShader(vs_4_0, MainVS())); SetGeometryShader(CompileShader(gs_4_0, MainGS())); SetPixelShader(CompileShader(ps_4_0, MainPS())); } }