//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// 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.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.Xml;
#endregion
///
/// GpuVariable is basic data structure used in gpu processing.
/// Generally, it will contain a texture in which each pixel represents a single property from an object.
/// This system aggregates variables of like type into a single texture... eg- one texture holds all velocity variables across multiple objects.
/// This texture is then processed using a simple shader that acts uniformly across all pixels, making for a RISC approach to gpu processing.
///
public class GpuVariable : GpuVariableInterface
{
#region Interfacing
///
/// Texture used by Gpu to read values in.
/// Swapped with write texture each pass.
///
public Texture2D _read { get { return read; } set { read = value; } }
///
/// Texture used by Gpu to write values out.
/// Swapped with read texture each pass.
///
public Texture2D _write { get { return write; } set { write = value; } }
///
/// Gpu handle that sets either the read texture each pass after it is swapped with the write texture.
///
public EffectParameter _gpuPointer { get { return gpuPointer; } set { gpuPointer = value; } }
///
/// A render target for the write texture.
///
public RenderTarget2D _writeRenderTarget { get { return writeRenderTarget; } set { writeRenderTarget = value; } }
///
/// A render target for the read texture.
///
public RenderTarget2D _readRenderTarget { get { return readRenderTarget; } set { readRenderTarget = value; } }
///
/// Needed in case the game window resolution is less than the spatial map resolution.
/// If this is the case, the original depth buffer used with the game window also needs to be swapped when we run
/// our update pass
///
public DepthStencilBuffer _depthBuff { get { return depthBuff; } set { depthBuff = value; } }
#endregion
#region Standard Variables
private Texture2D read;
private Texture2D write;
private Texture2D swapTexture;
private RenderTarget2D writeRenderTarget;
private RenderTarget2D readRenderTarget;
private DepthStencilBuffer depthBuff;
private RenderTarget2D swapTarget;
#endregion
// Vector4 array holds properties that we pass to gpu texture
Vector4[] texValues;
int texIndex;
int maxCount;
///
/// Shader technique (aka- program) to use with this variable.
///
public string technique;
private EffectParameter gpuPointer;
///
/// Shader variable associated with this GpuVariable.
///
public string gpuParamName;
private string outTexName;
///
/// Minimum numerical value of data being added to this texture.
///
public float minimumValue;
///
/// Range of numerical data being added to this texture.
///
public float scaleRange;
///
/// Data being added to this texture.
///
public List properties = new List();
///
/// Tells GpuProcessor to execute this GpuVariable using either Quad or Quad of Points processing.
///
public Enums_Stream.GpuProcessorMode processorMode;
///
/// Tells GpuProcessor whether it should update this GpuVariable.
///
public bool isDynamic;
///
/// GpuVariable constructor.
///
public GpuVariable()
{
// Empty Constructor
}
///
/// Creates a structure for executing a single pass on the shader hardware.
/// Each GpuVariable contains a multiple instances of the same data.
/// Eg - velocity
///
/// Technique to use.
/// The Effect Parameter for this variable.
/// Process using Spatial or Indexed processing technique.
/// Update this Variable each frame.
/// Minimum value of data added using AddProperty methods.
/// Maximum value of data added using AddProperty methods.
public GpuVariable(string shadeTechnique, EffectParameter gpuParameterPointer,
Enums_Stream.GpuProcessorMode ProcessorMode, bool Update, float minValue, float maxValue)
{
// Store info
technique = shadeTechnique;
outTexName = shadeTechnique;
processorMode = ProcessorMode;
isDynamic = Update;
GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
if (ProcessorMode == Enums_Stream.GpuProcessorMode.Indexed)
{
// Create Render Targets
writeRenderTarget = new RenderTarget2D(gd, Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE, Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE, 1, SurfaceFormat.Vector4);
readRenderTarget = new RenderTarget2D(gd, Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE, Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE, 1, SurfaceFormat.Vector4);
depthBuff = new DepthStencilBuffer(gd, Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE, Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE, DepthFormat.Depth24);
texValues = new Vector4[Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE];
maxCount = Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE;
}
else if (ProcessorMode == Enums_Stream.GpuProcessorMode.Spatial)
{
// Create Render Targets
writeRenderTarget = new RenderTarget2D(gd, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE, 1, SurfaceFormat.Vector4);
readRenderTarget = new RenderTarget2D(gd, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE, 1, SurfaceFormat.Vector4);
depthBuff = new DepthStencilBuffer(gd, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE, Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE, DepthFormat.Depth24);
texValues = new Vector4[Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE];
maxCount = Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.SPATIAL_TARGET_SIZE;
}
texIndex = 0;
DepthStencilBuffer temp = gd.DepthStencilBuffer;
// Clear out textures
gd.SetRenderTarget(0, readRenderTarget);
gd.DepthStencilBuffer = depthBuff;
gd.Clear(ClearOptions.Target, Color.TransparentBlack, 1.0f, 0);
gd.SetRenderTarget(0, null);
read = readRenderTarget.GetTexture();
gd.SetRenderTarget(0, writeRenderTarget);
gd.Clear(ClearOptions.Target, Color.TransparentBlack, 1.0f, 0);
gd.SetRenderTarget(0, null);
write = writeRenderTarget.GetTexture();
gd.DepthStencilBuffer = temp;
// Turn off RTT
// Set pointer to shader variable
gpuPointer = gpuParameterPointer;
// Save the min value for decompression
minimumValue = minValue;
// Get the data range
if (minimumValue < 0.0f)
{
scaleRange = maxValue;
}
else
{
scaleRange = maxValue - minimumValue;
}
}
#region Add Property
///
/// Add a single property to the GpuVariable, before setting texture data.
///
/// A value to add to the texture.
public virtual void AddProperty(float value)
{
properties.Add(new Vector4(value, scaleRange, scaleRange, scaleRange));
}
///
/// Add a single property to the GpuVariable, before setting texture data.
///
/// A value to add to the texture.
public virtual void AddProperty(Vector2 value)
{
properties.Add(new Vector4(value.X, value.Y, scaleRange, scaleRange));
}
///
/// Add a single property to the GpuVariable, before setting texture data.
///
/// A value to add to the texture.
public virtual void AddProperty(Vector3 value)
{
properties.Add(new Vector4(value.X, value.Y, value.Z, scaleRange));
}
///
/// Add a single property to the GpuVariable, before setting texture data.
///
/// A value to add to the texture.
public virtual void AddProperty(Vector4 value)
{
properties.Add(new Vector4(value.X, value.Y, value.Z, value.W));
}
///
/// Add a single property to the GpuVariable, before setting texture data.
///
/// A value to add to the texture.
public virtual void AddProperty(Quaternion value)
{
properties.Add(new Vector4(value.X, value.Y, value.Z, value.W));
}
#endregion
#region Clear Property
///
/// Removes a value from the property list at specified index.
///
/// Index at which to remove property.
public virtual void ClearProperty(int value)
{
properties[value] = new Vector4(-scaleRange);
}
#endregion
///
/// Set the texture with all added properties.
/// Scales values based on minValue and maxValue, to between 0-1.
///
public virtual void SetTexData()
{
// Copy values from properties to texture
for (int i = 0; i < properties.Count; i++)
{
texValues[i].X = (properties[i].X ) / scaleRange;
texValues[i].Y = (properties[i].Y ) / scaleRange;
texValues[i].Z = (properties[i].Z ) / scaleRange;
texValues[i].W = (properties[i].W ) / scaleRange;
}
texIndex = properties.Count;
// Initialize both textures with values
read.SetData(texValues);
write.SetData(texValues);
gpuPointer.SetValue(read);
}
///
/// Adds a property to texture while it is in use.
/// Used by attack methods.
///
/// Location in properties list to begin adding data to texture.
/// Number of properties to add from list.
public virtual void SetSubTexData(int startIndex, int count)
{
for (int i = startIndex; i < startIndex + count; i++)
{
if (texIndex >= maxCount)
{
// Restart from top of texture
texIndex = 0;
}
texValues[texIndex].X = (properties[i].X ) / scaleRange;
texValues[texIndex].Y = (properties[i].Y ) / scaleRange;
texValues[texIndex].Z = (properties[i].Z ) / scaleRange;
texValues[texIndex].W = (properties[i].W ) / scaleRange;
Rectangle rect = new Rectangle(texIndex % 256, (int)texIndex / 256, 1, 1);
read.SetData(0, rect, texValues, texIndex, 1, SetDataOptions.Discard);
write.SetData(0, rect, texValues, texIndex, 1, SetDataOptions.Discard);
texIndex++;
}
gpuPointer.SetValue(read);
}
///
/// Unscale the data coming out of the texture to it's original scale.
///
public virtual void UnScale()
{
// Vector4 array holds properties that we pass to gpu texture
Vector4[] texValues = new Vector4[Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE * Statics_Stream.GPU_ProcessorSettings.INDEXED_TARGET_SIZE];
write.GetData(texValues);
// Copy values from properties to texture
for (int i = 0; i < properties.Count; i++)
{
properties[i] = (texValues[i] * scaleRange);
}
}
///
/// Swap the read and write textures.
/// This is required b/c the gpu does not guarentee that we can read and write to the same texture in the same pass.
///
public void SwapBuffers()
{
// Swap the textures
swapTexture = read;
read = write;
write = swapTexture;
// Swap the render targets
swapTarget = readRenderTarget;
readRenderTarget = writeRenderTarget;
writeRenderTarget = swapTarget;
// Reset GPU Variable
gpuPointer.SetValue(read);
}
///
/// Debug function that writes the read and write textures to files named using the outTexName value.
///
public void WriteToFile()
{
write.Save(outTexName + "_Write.dds", ImageFileFormat.Dds);
read.Save(outTexName + "_Read.dds", ImageFileFormat.Dds);
}
}
}