/// <summary>
/// Screen quad vertex struct.
/// Contains a transformed position and texture coord.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ScreenQuadVertex
{
/// <summary>
/// The position of the vertex.
/// </summary>
private Vector4 PositionInternal;
/// <summary>
/// The texcoord for the vertex.
/// </summary>
private Vector2 TexCoordInternal;
/// <summary>
/// Constructor for the ScreenQuadVertex.
/// Takes a position (Vector3), and a texcoord (Vector2).
/// </summary>
/// <param name="X"></param>
/// <param name="Y"></param>
/// <param name="Z"></param>
/// <param name="U"></param>
/// <param name="V"></param>
public ScreenQuadVertex(Single X, Single Y, Single Z, Single U, Single V)
{
this.PositionInternal = new Vector4(X, Y, Z, 1.0f);
this.TexCoordInternal = new Vector2(U, V);
}
/// <summary>
/// Retieves the stride in bytes for ScreenQuadVertex.
/// </summary>
public static int StrideSize
{
get { return Marshal.SizeOf(typeof(ScreenQuadVertex)); }
}
}
/// <summary>
/// ScreenQuad class to render a full screen quad.
/// </summary>
public class ScreenQuad
{
/// <summary>
/// ScreenQuad vertex declaration, matching the ScreenQuadVertex struct.
/// </summary>
private readonly VertexElement[] ScreenQuadVertexElementsInternal = new VertexElement[]
{
new VertexElement(0, 0, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.PositionTransformed, 0),
new VertexElement(0, 16, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0),
};
/// <summary>
/// VertexDeclaration for the full screen quad (ScreenQuadVertex).
/// </summary>
private VertexDeclaration VertexDeclarationInternal = null;
/// <summary>
/// Vertex buffer to hold the 4 vertices of the screen quad.
/// </summary>
private VertexBuffer VertexBufferInternal = null;
/// <summary>
/// ScreenQuad constructor, takes a device.
/// Creates the vertex declaration, and the vertex buffer.
/// </summary>
/// <param name="device"></param>
public ScreenQuad(GraphicsDevice device)
{
//Create the vertex declaration using ScreenQuadVertexElements
this.VertexDeclarationInternal = new VertexDeclaration(device, this.ScreenQuadVertexElementsInternal);
//Create the vertex buffer, with 4 vertices
this.VertexBufferInternal = new VertexBuffer(device, typeof(ScreenQuadVertex), 4, ResourceUsage.None, ResourcePool.Default);
}
/// <summary>
/// Draw the full screen quad at the specified width and height.
/// Texcoords default to 0,0 and 1,1.
///
/// Vertex positions are offset by -0.5f.
/// </summary>
/// <param name="device"></param>
/// <param name="width"></param>
/// <param name="height"></param>
public void Draw(GraphicsDevice device, Single width, Single height)
{
//Right and bottom vertex position, offset for texel mapping.
float pixelToTexelX = 0.5f / width;
float pixelToTexelY = 0.5f / height;
//Create 4 new vertices
ScreenQuadVertex[] quadVerts = new ScreenQuadVertex[4];
//Lock the vertex buffer into quadVerts
this.VertexBufferInternal.GetData<ScreenQuadVertex>(quadVerts);
//Fill in the data for the 4 quad verts
quadVerts[0] = new ScreenQuadVertex(width, height, 0.5f, 1.0f - pixelToTexelX, 1.0f - pixelToTexelY);
quadVerts[1] = new ScreenQuadVertex(width, 0.0f, 0.5f, 1.0f - pixelToTexelX, -pixelToTexelY);
quadVerts[2] = new ScreenQuadVertex(0.0f, height, 0.5f, -pixelToTexelX, 1.0f - pixelToTexelY);
quadVerts[3] = new ScreenQuadVertex(0.0f, 0.0f, 0.5f, -pixelToTexelX, -pixelToTexelY);
//Unlock the vertex buffer
this.VertexBufferInternal.SetData<ScreenQuadVertex>(quadVerts);
//Whether the depth buffer was enabled or not
bool depthBufferEnabled = false;
if (device.RenderState.DepthBufferEnable == true)
{
//Disabled the depth buffer for renderin the quad
device.RenderState.DepthBufferEnable = false;
//flag that we disabled the depth buffer, so we can reset it to true
depthBufferEnabled = true;
}
//Whether the cull mode was changed
bool cullModeChanged = false;
CullMode cullMode = device.RenderState.CullMode;
if (cullMode != CullMode.CullClockwiseFace)
{
device.RenderState.CullMode = CullMode.CullClockwiseFace;
cullModeChanged = true;
}
//Set the vertex declaration
device.VertexDeclaration = this.VertexDeclarationInternal;
//Set the stream source to the quad vertex buffer with the correct stride.
device.Vertices[0].SetSource(this.VertexBufferInternal, 0, ScreenQuadVertex.StrideSize);
device.Vertices[0].VertexStride = ScreenQuadVertex.StrideSize;
//No indices are needed to render the 4 quad verts
device.Indices = null;
//Render the screen quad as 2 trianglestrips
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
//If the depth buffer was originally enabled, enable it again
if (depthBufferEnabled == true)
{
//Enable the depth buffer
device.RenderState.DepthBufferEnable = true;
}
//If the cullmode was changed, reset it
if (cullModeChanged == true)
{
//Set the cullmode back to its original value
device.RenderState.CullMode = cullMode;
}
}
/// <summary>
/// Draw the full screen quad at the specified width and height.
/// The Single parameters set the texcoords for the quad vertices.
///
/// Vertex positions are offset by -0.5f.
/// </summary>
/// <param name="device"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="left"></param>
/// <param name="top"></param>
/// <param name="bottom"></param>
/// <param name="right"></param>
public void Draw(GraphicsDevice device, Single width, Single height,
Single left, Single top, Single bottom, Single right)
{
//Right and bottom vertex position, offset for texel mapping.
float pixelToTexelX = 0.5f / width;
float pixelToTexelY = 0.5f / height;
//Create 4 new vertices
ScreenQuadVertex[] quadVerts = new ScreenQuadVertex[4];
//Lock the vertex buffer into quadVerts
this.VertexBufferInternal.GetData<ScreenQuadVertex>(quadVerts);
//Fill in the data for the 4 quad verts
quadVerts[0] = new ScreenQuadVertex(width, height, 0.5f, right - pixelToTexelX, bottom - pixelToTexelY);
quadVerts[1] = new ScreenQuadVertex(width, 0.0f, 0.5f, right - pixelToTexelX, top - pixelToTexelY);
quadVerts[2] = new ScreenQuadVertex(0.0f, height, 0.5f, left - pixelToTexelX, bottom - pixelToTexelY);
quadVerts[3] = new ScreenQuadVertex(0.0f, 0.0f, 0.5f, left - pixelToTexelX, top - pixelToTexelY);
//Unlock the vertex buffer
this.VertexBufferInternal.SetData<ScreenQuadVertex>(quadVerts);
//Whether the depth buffer was enabled or not
bool depthBufferEnabled = false;
if (device.RenderState.DepthBufferEnable == true)
{
//Disabled the depth buffer for renderin the quad
device.RenderState.DepthBufferEnable = false;
//flag that we disabled the depth buffer, so we can reset it to true
depthBufferEnabled = true;
}
//Whether the cull mode was changed
bool cullModeChanged = false;
CullMode cullMode = device.RenderState.CullMode;
if (cullMode != CullMode.CullClockwiseFace)
{
device.RenderState.CullMode = CullMode.CullClockwiseFace;
cullModeChanged = true;
}
//Set the vertex declaration
device.VertexDeclaration = this.VertexDeclarationInternal;
//Set the stream source to the quad vertex buffer with the correct stride.
device.Vertices[0].SetSource(this.VertexBufferInternal, 0, ScreenQuadVertex.StrideSize);
device.Vertices[0].VertexStride = ScreenQuadVertex.StrideSize;
//No indices are needed to render the 4 quad verts
device.Indices = null;
//Render the screen quad as 2 trianglestrips
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
//If the depth buffer was originally enabled, enable it again
if (depthBufferEnabled == true)
{
//Enable the depth buffer
device.RenderState.DepthBufferEnable = true;
}
//If the cullmode was changed, reset it
if (cullModeChanged == true)
{
//Set the cullmode back to its original value
device.RenderState.CullMode = cullMode;
}
}
/// <summary>
/// Dispose the components of the screen quad
/// </summary>
public void Dispose()
{
//If the vertex declaration is not null, dispose it
if (this.VertexDeclarationInternal != null)
{
this.VertexDeclarationInternal.Dispose();
this.VertexDeclarationInternal = null;
}
//If the the vertex buffer is not null, dispose it
if (this.VertexBufferInternal != null)
{
this.VertexBufferInternal.Dispose();
this.VertexBufferInternal = null;
}
}
}