//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynter.Stream
{
#region Using Statements
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion
///
/// Gpu-based Terrain normal processing class
///
public class TerrainNormalStuff
{
private Viewport generateNormalsViewport;
// Vertex Buffer
private VertexDeclaration vertexDeclaration; // Vertex Declaration
private VertexBuffer vertexBuffer;
private VertexPositionTexture[] vertices;
private RenderTarget2D renderTarget1;
private DepthStencilBuffer depthBuff;
///
/// Constructor
///
/// Texture width
/// Texture height
public TerrainNormalStuff(int textureWidth, int textureHeight)
{
// Set up the Indexed viewport
generateNormalsViewport.X = 0;
generateNormalsViewport.Y = 0;
generateNormalsViewport.Width = textureWidth;
generateNormalsViewport.Height = textureHeight;
generateNormalsViewport.MinDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MinDepth;
generateNormalsViewport.MaxDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MaxDepth;
GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
// Create a 4 point vertex buffer
vertices = new VertexPositionTexture[4];
vertexDeclaration = new VertexDeclaration(gd, VertexPositionTexture.VertexElements);
vertexBuffer = new VertexBuffer(gd, VertexPositionTexture.SizeInBytes * 4, BufferUsage.None);
// Create quad with width and height = 1
vertices[0] = new VertexPositionTexture(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f));
vertices[1] = new VertexPositionTexture(new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f));
vertices[2] = new VertexPositionTexture(new Vector3(1.0f, 1.0f, 0.0f), new Vector2(1.0f, 0.0f));
vertices[3] = new VertexPositionTexture(new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 0.0f));
// Set the data
vertexBuffer.SetData(vertices);
}
///
/// Generate the normal map from the height map
///
/// Output normal map
/// Input height map
public void GenerateTerrainNormals(ref Texture2D normalMap, Texture2D heightMap)
{
GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
// Create the render target and the depth stencil buffer
renderTarget1 = new RenderTarget2D(gd, heightMap.Width, heightMap.Height, 1, SurfaceFormat.Vector4, RenderTargetUsage.DiscardContents);
depthBuff = new DepthStencilBuffer(gd, heightMap.Width, heightMap.Height, DepthFormat.Depth16);
// Setup view and projection matrixes
Matrix matrixProjection = Matrix.CreateOrthographic(generateNormalsViewport.Width, generateNormalsViewport.Height, 1, 5);
Matrix matrixPosition = Matrix.CreateScale(generateNormalsViewport.Width, generateNormalsViewport.Height, 1) *
Matrix.CreateTranslation(-generateNormalsViewport.Width / 2.0f, -generateNormalsViewport.Height / 2.0f, 0.0f);
Matrix matrixView = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up);
// Set graphics related stuff
gd.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionTexture.SizeInBytes);
gd.SetRenderTarget(0, renderTarget1);
DepthStencilBuffer old = gd.DepthStencilBuffer;
gd.DepthStencilBuffer = depthBuff;
gd.Clear(ClearOptions.Target, Color.White, 1.0f, 0);
gd.Viewport = generateNormalsViewport;
gd.VertexDeclaration = vertexDeclaration;
gd.RenderState.DepthBufferEnable = false;
// Set all the different shader parameter for normal generation
ShaderParameters.TerrainNormalFX.ViewProj.SetValue(matrixView * matrixProjection);
ShaderParameters.TerrainNormalFX.World.SetValue(matrixPosition);
ShaderParameters.TerrainNormalFX.heightMapTexture.SetValue(heightMap);
ShaderParameters.TerrainNormalFX.effect.CurrentTechnique = ShaderParameters.TerrainNormalFX.effect.Techniques["GenerateTerrainNormals"];
// Render our quad for normal generation
ShaderParameters.TerrainNormalFX.effect.Begin();
foreach (EffectPass pass in ShaderParameters.TerrainNormalFX.effect.CurrentTechnique.Passes)
{
pass.Begin();
gd.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
pass.End();
}
ShaderParameters.TerrainNormalFX.effect.End();
// Reset to the screen render target and depth buffer
gd.SetRenderTarget(0, null);
gd.DepthStencilBuffer = old;
// Retrieve the normal map from our render target
normalMap = renderTarget1.GetTexture();
// Dispose of the rendertarget and the depthbuffer to free up memory
renderTarget1.Dispose();
depthBuff.Dispose();
}
}
}