//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace ElementalGame
{
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion
public class GpuProcessor
{
// Spacial Data Structure
Vec4 locationMap;
// Spatial and Indexed Viewports
Viewport IndexedViewport;
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
public static int INDEXED_TARGET_SIZE = 256;
// 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
public static int SPATIAL_TARGET_SIZE = 512;
// Update Shader ==================================================================================
Effect effect_update; // The program handle
EffectParameter gpu_dt; // Time difference between frames
EffectParameter gpu_Pass; // Keeps track of which physics-instruction pass we are on
EffectParameter gpu_Gravity; // Manipulate gpu gravity remotely
float gravity = 0.0f; // Stores value modifiable through controller
EffectParameter gpu_HeightMap; // GPU version of terrain heightmap; shared with draw shader
EffectParameter gpu_NormalMap; // GPU version of terrain normalmap; shared with draw shader
Texture2D ForceMap; // Texture holding "wind" currents
EffectParameter ForceMapPointer; // Pointer for gpu
// Draw Shader ====================================================================================
Effect effect_draw; // The handle to ElementalGPU.fx
EffectParameter currentPositionParam; // To save the CurrentPosition texture to ElementalGPU
EffectParameter scaleRange; // To save the Scale Range to ElementalGPU
EffectParameter minimumValue; // To save the Minimum Value to ElementalGPU
bool initializeConstants = true;
// ================================\ Methods /=====================================================
// ================================================================================================
public GpuProcessor()
{
// Set up Uniform shader connections
effect_update = ElementalGame.content.Load("PhysicsGPU/GpuCollisionPhysics");
effect_draw = ElementalGame.content.Load("Shaders/ElementalGPU");
// Get Update Handles
gpu_Pass = effect_update.Parameters["IndexedPass"];
gpu_dt = effect_update.Parameters["dt"];
gpu_Gravity = effect_update.Parameters["gravity"];
// Get Draw Handles
currentPositionParam = effect_draw.Parameters["CurrentPosition"];
scaleRange = effect_draw.Parameters["scaleRange"];
minimumValue = effect_draw.Parameters["minimumValue"];
// Set up Terrain Maps
gpu_HeightMap = effect_update.Parameters["TerrainHeightMap"];
gpu_NormalMap = effect_update.Parameters["TerrainNormalMap"];
// Create Location Map
locationMap = new Vec4(effect_update, "LocationMap", "locationMap");
// Load the ForceMap
ForceMap = ElementalGame.content.Load("_textures/ForceMap");
ForceMapPointer = effect_update.Parameters["ForceMap"];
// Create geometry used in render passes
CreateQuad();
CreatePoints();
}
private void CreateQuad()
{
// Set up the Indexed viewport
IndexedViewport.X = 0;
IndexedViewport.Y = 0;
IndexedViewport.Width = INDEXED_TARGET_SIZE;
IndexedViewport.Height = INDEXED_TARGET_SIZE;
IndexedViewport.MinDepth = ElementalGame.graphics.GraphicsDevice.Viewport.MinDepth;
IndexedViewport.MaxDepth = ElementalGame.graphics.GraphicsDevice.Viewport.MaxDepth;
GraphicsDevice gd = ElementalGame.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,
ResourceUsage.None, ResourceManagementMode.Automatic);
// 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 = SPATIAL_TARGET_SIZE;
SpatialViewport.Height = SPATIAL_TARGET_SIZE;
SpatialViewport.MinDepth = ElementalGame.graphics.GraphicsDevice.Viewport.MinDepth;
SpatialViewport.MaxDepth = ElementalGame.graphics.GraphicsDevice.Viewport.MaxDepth;
GraphicsDevice gd = ElementalGame.graphics.GraphicsDevice;
point_vertices = new VertexPositionNormalTexture[SPATIAL_TARGET_SIZE * SPATIAL_TARGET_SIZE];
point_vertexDeclaration = new VertexDeclaration(gd, VertexPositionNormalTexture.VertexElements);
point_vertexBuffer = new VertexBuffer(gd, VertexPositionNormalTexture.SizeInBytes * SPATIAL_TARGET_SIZE * SPATIAL_TARGET_SIZE,
ResourceUsage.None, ResourceManagementMode.Automatic);
// Row by row, create a point for each pixel between 0-1
int index = 0;
float pixelLength = 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);
}
// Main
public void ExecuteRTT(float dt, GpuObject gpuObject, ObjectLibrary objectLibrary)
{
// Spatial Updates
effect_update.CurrentTechnique = effect_update.Techniques["SpatialMain"];
ExecuteSpatialRTT(ref locationMap.writeRenderTarget, ref locationMap.write);
locationMap.SwapBuffers();
//gpuObject.WriteToFile();
// Set Gravity
gravity += objectLibrary.humans[0].playerController.GetGPUGravityButton();
gpu_Gravity.SetValue(gravity);
// Set shader dt
gpu_dt.SetValue(dt);
// Set HeightMap and NormalMap
gpu_HeightMap.SetValue(objectLibrary.terrain.heightMapTexture);
gpu_NormalMap.SetValue(objectLibrary.terrain.normalMapTexture);
// Set ForceMap
ForceMapPointer.SetValue(ForceMap);
// Indexed Updates
effect_update.CurrentTechnique = effect_update.Techniques["IndexedMain"];
for (int i = 0; i <= 6; i++)
{
gpu_Pass.SetValue(i);
ExecuteIndexedRTT(ref gpuObject.variables[i].writeRenderTarget, ref gpuObject.variables[i].write);
gpuObject.variables[i].SwapBuffers();
//gpuObject.variables[i].WriteToFile();
}
// ================== MOVE OR REMOVE ========================
// Save texture to other fx file
// variables[5] = current position
currentPositionParam.SetValue(gpuObject.variables[5].write);
if (initializeConstants)
{
initializeConstants = false;
// Store the constants
scaleRange.SetValue(gpuObject.variables[5].scaleRange);
minimumValue.SetValue(gpuObject.variables[5].minimumValue);
}
ElementalGame.graphics.GraphicsDevice.SetRenderTarget(0, null);
}
private void ExecuteIndexedRTT(ref RenderTarget2D renderTarget, ref Texture2D renderTargetTexture)
{
// Set up Graphics Device
GraphicsDevice g = ElementalGame.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));
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
effect_update.Begin();
foreach (EffectPass pass in effect_update.CurrentTechnique.Passes)
{
pass.Begin();
g.VertexDeclaration = quad_vertexDeclaration;
g.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
pass.End();
}
effect_update.End();
// Gets the Rendered Texture and store it in the RenderTarget variable
g.ResolveRenderTarget(0);
//renderTarget.GetTexture().Save("indexedTexture.png", ImageFileFormat.Png);
// Retrieve the Shadow map from our Render Target
//renderTargetTexture = renderTarget.GetTexture();
//renderTargetTexture.Save("indexedTexture.png", ImageFileFormat.Png);
}
private void ExecuteSpatialRTT(ref RenderTarget2D renderTarget, ref Texture2D renderTargetTexture)
{
// Set up Graphics Device
GraphicsDevice g = ElementalGame.graphics.GraphicsDevice;
g.Viewport = SpatialViewport;
g.RenderState.DepthBufferEnable = false;
// Setup view and projection matrixes
Matrix proj = Matrix.CreateOrthographic(0.5f, 0.5f, 0, 5);
//Matrix view = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, new Vector3(0, 1, 1));
Matrix view = Matrix.CreateLookAt(new Vector3(0.75f, 0.75f, 1.0f), new Vector3(0.75f, 0.75f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
effect_update.Parameters["ViewProj"].SetValue(view * proj);
effect_update.Parameters["gpuObjectScale"].SetValue(Terrain.collisionMapSize);
// Set Points Vertex Buffer
g.Vertices[0].SetSource(point_vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes);
// Set and clear RTT texture
g.SetRenderTarget(0, renderTarget);
g.Clear(ClearOptions.Target, Color.TransparentWhite, 1.0f, 0);
// Draw Quad
effect_update.Begin();
foreach (EffectPass pass in effect_update.CurrentTechnique.Passes)
{
pass.Begin();
g.VertexDeclaration = point_vertexDeclaration;
g.DrawPrimitives(PrimitiveType.PointList, 0, SPATIAL_TARGET_SIZE * SPATIAL_TARGET_SIZE);
pass.End();
}
effect_update.End();
// Gets the Rendered Texture and store it in the RenderTarget variable
g.ResolveRenderTarget(0);
//renderTarget.GetTexture().Save("gpuPhysicsTex.png", ImageFileFormat.Png);
}
}
}