//--------------------------------------------------------------------------------------------------------------------------------------------------- // // 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); } } }