//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynter.Stream.PhysicsGpu
{
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;
#endregion
///
/// Vertex structure for GPU Physics updates
///
public struct VertexPosition
{
///
/// Vertex position
///
public Vector3 position;
}
///
/// 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 VertexPositionTexture[] 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 VertexPosition[] point_vertices; // Array to store vertex Position, Normal and Texture information
private VertexDeclaration point_vertexDeclaration; // Vertex Declaration
// Update Shader ==================================================================================
public static float gravity = 0.0f; // Stores value modifiable through controller
private int UPDATE_TIME_MILLI = 100;
private Stopwatch runUpdateTimer = new Stopwatch();
// Tells the GPU how to format the streams
private VertexElement[] Elements = new VertexElement[]
{
new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
};
// ================================\ Methods /=====================================================
// ================================================================================================
///
/// GpuProcessor constructor sets up Quad and Quad of Points mechanics.
///
public GpuProcessor()
{
//// Get Draw Handles
//currentPositionParam = effect_draw.Parameters["CurrentPosition"];
//scaleRange = effect_draw.Parameters["scaleRange"];
//minimumValue = effect_draw.Parameters["minimumValue"];
// Create geometry used in render passes
CreateQuad();
CreatePoints();
runUpdateTimer.Reset();
runUpdateTimer.Start();
}
private void CreateQuad()
{
// Set up the Indexed viewport
IndexedViewport.X = 0;
IndexedViewport.Y = 0;
IndexedViewport.Width = Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE;
IndexedViewport.Height = Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE;
IndexedViewport.MinDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MinDepth;
IndexedViewport.MaxDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MaxDepth;
GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
// Create a 4 point vertex buffer
quad_vertices = new VertexPositionTexture[4];
quad_vertexDeclaration = new VertexDeclaration(gd, VertexPositionTexture.VertexElements);
quad_vertexBuffer = new VertexBuffer(gd, VertexPositionTexture.SizeInBytes * 4, BufferUsage.WriteOnly);
// Create quad with width and height = 1
quad_vertices[0] = new VertexPositionTexture(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 VertexPositionTexture(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 VertexPositionTexture(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 VertexPositionTexture(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_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE;
SpatialViewport.Height = Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE;
SpatialViewport.MinDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MinDepth;
SpatialViewport.MaxDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MaxDepth;
float spatMap = 1.0f / (float)Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE;
ShaderParameters.UpdateFX.invSpatMapHeight.SetValue(spatMap);
ShaderParameters.UpdateFX.invSpatMapWidth.SetValue(spatMap);
GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
point_vertices = new VertexPosition[Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE];
point_vertexDeclaration = new VertexDeclaration(gd, Elements);
point_vertexBuffer = new VertexBuffer(gd,
typeof(VertexPosition),
Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics_Stream.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_Stream.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].position = new Vector3(((float)i / pixelLength), ((float)j / pixelLength), 0.0f);
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.
///
/// location map
/// List of gpu variables
// CLEAN: REMOVE BOTH PARAMETERS, REPLACE WITH SINGLE GPU OBJECT
public void ExecuteRTT(SpatialMap locationMap, List variables)
{
// Set Gravity
//gravity += objectLibrary.humans[0].playerController.gameInput.GetGPUGravityButton;
ShaderParameters.UpdateFX.gravity.SetValue(gravity);
if (runUpdateTimer.ElapsedMilliseconds >= UPDATE_TIME_MILLI)
{
runUpdateTimer.Reset();
runUpdateTimer.Start();
// Spatial Updates
ShaderParameters.UpdateFX.effect.CurrentTechnique = ShaderParameters.UpdateFX.effect.Techniques[locationMap.technique];
ExecuteSpatialRTT(locationMap._writeRenderTarget, locationMap._depthBuff);
locationMap.SwapBuffers();
//locationMap.WriteToFile();
// Indexed Updates
for (int i = 0; i < variables.Count; i++)
{
if (variables[i].isDynamic)
{
if (variables[i].processorMode == Enums_Stream.GpuProcessorMode.Indexed)
{
ShaderParameters.UpdateFX.effect.CurrentTechnique = ShaderParameters.UpdateFX.effect.Techniques[variables[i].technique];
ExecuteIndexedRTT(variables[i]._writeRenderTarget);
variables[i].SwapBuffers();
//variables[i].WriteToFile();
}
if (variables[i].technique == "Velocity")
{
//variables[i].WriteToFile();
}
}
}
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SetRenderTarget(0, null);
}
}
private void ExecuteIndexedRTT( RenderTarget2D renderTarget)
{
// Set up Graphics Device
GraphicsDevice g = Statics_Stream.RenderSettings.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.UpdateFX.effect.Parameters["ViewProj"].SetValue(view * proj);
// Set Quad Vertex Buffer
g.Vertices[0].SetSource(quad_vertexBuffer, 0, quad_vertexDeclaration.GetVertexStrideSize(0));
// Set and clear RTT texture
g.SetRenderTarget(0, renderTarget);
g.Clear(ClearOptions.Target, Color.TransparentWhite, 1.0f, 0);
// Draw Quad
ShaderParameters.UpdateFX.effect.Begin();
foreach (EffectPass pass in ShaderParameters.UpdateFX.effect.CurrentTechnique.Passes)
{
pass.Begin();
g.VertexDeclaration = quad_vertexDeclaration;
g.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
pass.End();
}
ShaderParameters.UpdateFX.effect.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_Stream.RenderSettings.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.UpdateFX.effect.Parameters["ViewProj"].SetValue(view * proj);
// Set Points Vertex Buffer
g.Vertices[0].SetSource(point_vertexBuffer, 0, point_vertexDeclaration.GetVertexStrideSize(0));
// 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.UpdateFX.effect.Begin();
foreach (EffectPass pass in ShaderParameters.UpdateFX.effect.CurrentTechnique.Passes)
{
pass.Begin();
g.VertexDeclaration = point_vertexDeclaration;
g.DrawPrimitives(PrimitiveType.PointList, 0, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE);
pass.End();
}
ShaderParameters.UpdateFX.effect.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);
}
}
}