//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynterEngine.PhysicsGpu
{
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion
using Globals;
using ObjectLib;
///
/// GpuProcessor handles the rendering of GpuVariables.
/// Supports standard gpgpu "quad" technique to handle gather algorithms.
/// Also supports what we call a "quad of points" technique to handle scatter algorithms.
///
public class GpuProcessor
{
// Spatial and Indexed Viewports
private Viewport IndexedViewport;
private Viewport SpatialViewport;
// Quad Vertex Buffer =============================================================================
private VertexBuffer quad_vertexBuffer; // Buffer to store vertices
private VertexPositionNormalTexture[] quad_vertices; // Array to store vertex Position, Normal and Texture information
private VertexDeclaration quad_vertexDeclaration; // Vertex Declaration
// Point Vertex Buffer ============================================================================
private VertexBuffer point_vertexBuffer; // Buffer to store vertices
private VertexPositionNormalTexture[] point_vertices; // Array to store vertex Position, Normal and Texture information
private VertexDeclaration point_vertexDeclaration; // Vertex Declaration
// Update Shader ==================================================================================
private EffectParameter gpu_dt; // Time difference between frames
private EffectParameter gpu_Pass; // Keeps track of which physics-instruction pass we are on
private EffectParameter invSpatMapHeight;
private EffectParameter invSpatMapWidth;
private EffectParameter gpu_Gravity; // Manipulate gpu gravity remotely
private float gravity = 0.0f; // Stores value modifiable through controller
private EffectParameter gpu_HeightMap; // GPU version of terrain heightmap; shared with draw shader
private EffectParameter gpu_NormalMap; // GPU version of terrain normalmap; shared with draw shader
// ================================\ Methods /=====================================================
// ================================================================================================
///
/// GpuProcessor constructor sets up Quad and Quad of Points mechanics.
///
public GpuProcessor()
{
// Get Update Handles
gpu_Pass = ShaderParameters.effect_update.Parameters["IndexedPass"];
gpu_dt = ShaderParameters.effect_update.Parameters["dt"];
gpu_Gravity = ShaderParameters.effect_update.Parameters["gravity"];
invSpatMapHeight = ShaderParameters.effect_update.Parameters["invSpatMapHeight"];
invSpatMapWidth = ShaderParameters.effect_update.Parameters["invSpatMapWidth"];
//// Get Draw Handles
//currentPositionParam = effect_draw.Parameters["CurrentPosition"];
//scaleRange = effect_draw.Parameters["scaleRange"];
//minimumValue = effect_draw.Parameters["minimumValue"];
// Set up Terrain Maps
gpu_HeightMap = ShaderParameters.effect_update.Parameters["TerrainHeightMap"];
gpu_NormalMap = ShaderParameters.effect_update.Parameters["TerrainNormalMap"];
// Create geometry used in render passes
CreateQuad();
CreatePoints();
}
private void CreateQuad()
{
// Set up the Indexed viewport
IndexedViewport.X = 0;
IndexedViewport.Y = 0;
IndexedViewport.Width = Statics.GPU_ProcessorSettings.INDEXED_TARGET_SIZE;
IndexedViewport.Height = Statics.GPU_ProcessorSettings.INDEXED_TARGET_SIZE;
IndexedViewport.MinDepth = Statics.SystemSettings.graphics.GraphicsDevice.Viewport.MinDepth;
IndexedViewport.MaxDepth = Statics.SystemSettings.graphics.GraphicsDevice.Viewport.MaxDepth;
GraphicsDevice gd = Statics.SystemSettings.graphics.GraphicsDevice;
// Create a 4 point vertex buffer
quad_vertices = new VertexPositionNormalTexture[4];
quad_vertexDeclaration = new VertexDeclaration(gd, VertexPositionNormalTexture.VertexElements);
quad_vertexBuffer = new VertexBuffer(gd, VertexPositionNormalTexture.SizeInBytes * 4, BufferUsage.WriteOnly);
// Create quad with width and height = 1
quad_vertices[0] = new VertexPositionNormalTexture(new Vector3(-0.5f, -0.5f, 0),
new Vector3(-0.5f, -0.5f, 1),
new Vector2(0, 1.0f)); // 3rd quadrent
quad_vertices[1] = new VertexPositionNormalTexture(new Vector3(0.5f, -0.5f, 0),
new Vector3(0.5f, -0.5f, 1),
new Vector2(1.0f, 1.0f)); // 4th quadrent
quad_vertices[2] = new VertexPositionNormalTexture(new Vector3(0.5f, 0.5f, 0),
new Vector3(0.5f, 0.5f, 1),
new Vector2(1.0f, 0)); // 1st quadrent
quad_vertices[3] = new VertexPositionNormalTexture(new Vector3(-0.5f, 0.5f, 0),
new Vector3(-0.0f, 1.0f, 1),
new Vector2(0, 0)); // 2nd quadrent
// Set the data
quad_vertexBuffer.SetData(quad_vertices);
}
private void CreatePoints()
{
// Set up the Spatial viewport
SpatialViewport.X = 0;
SpatialViewport.Y = 0;
SpatialViewport.Width = Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE;
SpatialViewport.Height = Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE;
SpatialViewport.MinDepth = Statics.SystemSettings.graphics.GraphicsDevice.Viewport.MinDepth;
SpatialViewport.MaxDepth = Statics.SystemSettings.graphics.GraphicsDevice.Viewport.MaxDepth;
invSpatMapHeight.SetValue(1.0f / (float)Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE);
invSpatMapWidth.SetValue(1.0f / (float)Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE);
GraphicsDevice gd = Statics.SystemSettings.graphics.GraphicsDevice;
point_vertices = new VertexPositionNormalTexture[Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE];
point_vertexDeclaration = new VertexDeclaration(gd, VertexPositionNormalTexture.VertexElements);
point_vertexBuffer = new VertexBuffer(gd,
VertexPositionNormalTexture.SizeInBytes * Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE,
BufferUsage.WriteOnly);
// Row by row, create a point for each pixel between 0-1
int index = 0;
float pixelLength = Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE - 1.0f;
for (int j = 0; j <= pixelLength; j++)
{
for (int i = 0; i <= pixelLength; i++)
{
Vector3 pPos = new Vector3(((float)i / pixelLength), ((float)j / pixelLength), 0.0f);
Vector3 nPos = new Vector3(((float)i / pixelLength), ((float)j / pixelLength), 1.0f);
Vector2 tPos = new Vector2(((float)i / pixelLength), ((float)j / pixelLength));
point_vertices[index] = new VertexPositionNormalTexture(pPos, nPos, tPos);
index++;
}
}
// Set the data
point_vertexBuffer.SetData(point_vertices);
}
///
/// Executes a shader pass on a List of GpuVariables.
/// Each GpuVariable has enough information to tell the processor how to execute it.
/// Variables are processed in the order in which they occur in the list.
///
/// A list of variables to process.
/// ObjectLibrary containing terrain used in collision.
///
// CLEAN: REMOVE BOTH PARAMETERS, REPLACE WITH SINGLE GPU OBJECT
public void ExecuteRTT(GpuObjectList gpuObjectList, ObjectLibrary objectLibrary)
{
// Set Gravity
//gravity += objectLibrary.humans[0].playerController.gameInput.GetGPUGravityButton;
gpu_Gravity.SetValue(gravity);
// Set Change in Time
gpu_dt.SetValue(Statics.SystemSettings.dt);
// Set HeightMap, NormalMap, ForceMap, and Scale Values
gpu_HeightMap.SetValue(objectLibrary.terrain.heightMapTexture);
gpu_NormalMap.SetValue(objectLibrary.terrain.normalMapTexture);
// Spatial Updates
ShaderParameters.effect_update.CurrentTechnique = ShaderParameters.effect_update.Techniques[gpuObjectList.locationMap.technique];
ExecuteSpatialRTT(gpuObjectList.locationMap._writeRenderTarget, gpuObjectList.locationMap._depthBuff);
gpuObjectList.locationMap.SwapBuffers();
//gpuObjectList.locationMap.WriteToFile();
//// Indexed Updates
for (int i = 0; i < gpuObjectList.variables.Count; i++)
{
if (gpuObjectList.variables[i].isDynamic)
{
if (gpuObjectList.variables[i].processorMode == Enums.GpuProcessorMode.Indexed)
{
ShaderParameters.effect_update.CurrentTechnique = ShaderParameters.effect_update.Techniques[gpuObjectList.variables[i].technique];
ExecuteIndexedRTT(gpuObjectList.variables[i]._writeRenderTarget);
gpuObjectList.variables[i].SwapBuffers();
//gpuObjectList.variables[i].WriteToFile();
}
if (gpuObjectList.variables[i].processorMode == Enums.GpuProcessorMode.Spatial)
{
}
}
}
Statics.SystemSettings.graphics.GraphicsDevice.SetRenderTarget(0, null);
}
private void ExecuteIndexedRTT( RenderTarget2D renderTarget)
{
// Set up Graphics Device
GraphicsDevice g = Statics.SystemSettings.graphics.GraphicsDevice;
g.Viewport = IndexedViewport;
g.RenderState.DepthBufferEnable = false;
// Setup view and projection matrixes
Matrix proj = Matrix.CreateOrthographic(1.0f, 1.0f, 1, 5);
Matrix view = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, new Vector3(0, 1, 1));
ShaderParameters.effect_update.Parameters["ViewProj"].SetValue(view * proj);
// Set Quad Vertex Buffer
g.Vertices[0].SetSource(quad_vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes);
// Set and clear RTT texture
g.SetRenderTarget(0, renderTarget);
g.Clear(ClearOptions.Target, Color.TransparentWhite, 1.0f, 0);
// Draw Quad
ShaderParameters.effect_update.Begin();
foreach (EffectPass pass in ShaderParameters.effect_update.CurrentTechnique.Passes)
{
pass.Begin();
g.VertexDeclaration = quad_vertexDeclaration;
g.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
pass.End();
}
ShaderParameters.effect_update.End();
// Gets the Rendered Texture and store it in the RenderTarget variable
//g.ResolveRenderTarget(0);
g.SetRenderTarget(0, null);
//g.RenderState.DepthBufferEnable = true;
// Retrieve the Shadow map from our Render Target
//renderTargetTexture = renderTarget.GetTexture();
//renderTargetTexture.Save("indexedTexture.png", ImageFileFormat.Png);
}
private void ExecuteSpatialRTT(RenderTarget2D renderTarget, DepthStencilBuffer depthBuff)
{
// Set up Graphics Device
GraphicsDevice g = Statics.SystemSettings.graphics.GraphicsDevice;
g.Viewport = SpatialViewport;
g.RenderState.DepthBufferEnable = false;
// Setup view and projection matrixes
Matrix proj = Matrix.CreateOrthographic(1.0f, 1.0f, 0, 5);
Matrix view = Matrix.CreateLookAt(new Vector3(0.5f, 0.5f, -1.0f), new Vector3(0.5f, 0.5f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
ShaderParameters.effect_update.Parameters["ViewProj"].SetValue(view * proj);
ShaderParameters.effect_update.Parameters["gpuObjectScale"].SetValue(Statics.TerrainSettings.collisionMapSize);
// Set Points Vertex Buffer
g.Vertices[0].SetSource(point_vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes);
// Set and clear RTT texture
g.SetRenderTarget(0, renderTarget);
DepthStencilBuffer old = g.DepthStencilBuffer;
g.DepthStencilBuffer = depthBuff;
g.Clear(ClearOptions.Target, Color.TransparentWhite, 1.0f, 0);
// Draw Quad
ShaderParameters.effect_update.Begin();
foreach (EffectPass pass in ShaderParameters.effect_update.CurrentTechnique.Passes)
{
pass.Begin();
g.VertexDeclaration = point_vertexDeclaration;
g.DrawPrimitives(PrimitiveType.PointList, 0, Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE);
pass.End();
}
ShaderParameters.effect_update.End();
// Gets the Rendered Texture and store it in the RenderTarget variable
//g.ResolveRenderTarget(0);
g.SetRenderTarget(0, null);
g.DepthStencilBuffer = old;
//g.RenderState.DepthBufferEnable = true;
//renderTarget.GetTexture().Save("gpuPhysicsTex.png", ImageFileFormat.Png);
}
}
}