//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynterEngine.ObjectLib { #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; using System.Diagnostics; #endregion using Globals; using GameObjects; using Physics; using PhysicsGpu; /// /// GpuObjectList contains a list of GpuObjects. /// It takes an object at a time and holds it till ConvertToVariables is called, at which time it transfers converts the data into textures. /// After this initialization, GpuObjects can still be added by using ConvertSubsetToVariables. /// public class GpuObjectList : GameObject { // Type information private string type; /// /// A list of GpuVariables used in our algorithm. /// public List variables = new List(); /// /// GpuProcessor is used to process each gpu object each pass /// public GpuProcessor gpu_Processor; /// /// List of mass objects being converted to GpuVariables. /// private List masses = new List(); /// /// A forceMap simulating wind currents. /// private GpuWindMap windMap = new GpuWindMap(); /// /// Spacial Data Structure used in Gpu Collision algorithm. /// public SpatialMap locationMap; // Draw Shader ======================================================================================= private EffectParameter scaleRange; // To save the Scale Range to ElementalGPU private EffectParameter minimumValue; // To save the Minimum Value to ElementalGPU private EffectParameter cpScaleRangeY; private EffectParameter cpScaleMinY; private EffectParameter currentPositionParam; // To save the CurrentPosition texture to ElementalGPU // Update Shader ===================================================================================== private EffectParameter gpu_scaleMinY; private EffectParameter gpu_scaleRangeY; private EffectParameter playerPositionParam; // Current Player Position private EffectParameter gpu_mass; // The instance data itself private List instanceList; private List removeObjects; private List addObjects; private VertexFogBinormalTangent[] instanceData; // Tells the GPU how to format the streams private VertexElement[] Elements = new VertexElement[] { new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement(0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0), new VertexElement(0, sizeof(float) * 6, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0), new VertexElement(1, 0, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.Fog, 0), new VertexElement(1, sizeof(float) * 4, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.Binormal, 0), new VertexElement(1, sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.Tangent, 0), }; /// /// GpuObjectList constructor. /// Creates a list of GpuVariables used in Physics and Collision. /// public GpuObjectList() { vertexDeclaration = new VertexDeclaration(Statics.SystemSettings.graphics.GraphicsDevice, Elements); gpu_Processor = new GpuProcessor(); // Get Draw Handles currentPositionParam = ShaderParameters.effect_draw.Parameters["CurrentPosition"]; scaleRange = ShaderParameters.effect_draw.Parameters["scaleRange"]; minimumValue = ShaderParameters.effect_draw.Parameters["minimumValue"]; cpScaleRangeY = ShaderParameters.effect_update.Parameters["cpScaleRangeY"]; cpScaleMinY = ShaderParameters.effect_update.Parameters["cpScaleMinY"]; gpu_scaleMinY = ShaderParameters.effect_update.Parameters["scaleMinY"]; gpu_scaleRangeY = ShaderParameters.effect_update.Parameters["scaleRangeY"]; playerPositionParam = ShaderParameters.effect_update.Parameters["playerPosition"]; gpu_mass = ShaderParameters.effect_update.Parameters["mass"]; // Create Location Map locationMap = new SpatialMap(ShaderParameters.effect_update, "SpatialMain", "LocationMap", Enums.GpuProcessorMode.Spatial, true, 0, 100); // Create Variables and add to the Object variables.Add(new Vec3(ShaderParameters.effect_update, "TotalForce", "TotalForce", Enums.GpuProcessorMode.Indexed, true, -Statics.TerrainSettings.collisionMapSize, Statics.TerrainSettings.collisionMapSize)); variables.Add(new Vec3(ShaderParameters.effect_update, "Acceleration", "Acceleration", Enums.GpuProcessorMode.Indexed, true, -Statics.TerrainSettings.collisionMapSize, Statics.TerrainSettings.collisionMapSize)); variables.Add(new Vec3(ShaderParameters.effect_update, "Velocity", "Velocity", Enums.GpuProcessorMode.Indexed, true, -Statics.TerrainSettings.collisionMapSize, Statics.TerrainSettings.collisionMapSize)); variables.Add(new Quat(ShaderParameters.effect_update, "Rotation", "Rotation", Enums.GpuProcessorMode.Indexed, true, -100, 100)); variables.Add(new Vec3(ShaderParameters.effect_update, "CurrentPosition", "CurrentPosition", Enums.GpuProcessorMode.Indexed, true, -Statics.TerrainSettings.collisionMapSize, Statics.TerrainSettings.collisionMapSize)); variables.Add(new Vec3(ShaderParameters.effect_update, "Dummy", "Dummy", Enums.GpuProcessorMode.Indexed, true, -Statics.TerrainSettings.collisionMapSize, Statics.TerrainSettings.collisionMapSize)); variables.Add(new Vec1(ShaderParameters.effect_update, "", "Radius", Enums.GpuProcessorMode.Indexed, false, 0, 100)); variables.Add(new Vec1(ShaderParameters.effect_update, "", "Scale", Enums.GpuProcessorMode.Indexed, false, 0, 100)); variables.Add(new Vec1(ShaderParameters.effect_update, "", "Mass", Enums.GpuProcessorMode.Indexed, false, 0, 100)); removeObjects = new List(); addObjects = new List(); } /// /// Override load function, parses and loads xml data. /// /// GpuObject xml data. /// ObjectLibrary that this list belongs to. /// True if load was successful public override bool Load(XmlNode objectNode, ObjectLibrary objectLibrary) { // Set up Model Manager type = objectNode.Attributes["type"].Value; objectLibrary.modelManager.AddNewModel(type, objectNode.Attributes["model"].Value, objectNode.Attributes["texture"].Value, objectNode.Attributes["bumpTexture"].Value); // Get the Location Map Texture2D locationMap = Statics.SystemSettings.content.Load(objectNode.Attributes["locationMap"].Value); int length = locationMap.Width * locationMap.Width; Color[] locationColorValues = new Color[length]; locationMap.GetData(locationColorValues); Random rand = new Random(); // Precalculate the vertexmap/locationmap ratio for use in the for loop below float vertexmapToObjectmapRelationship = Statics.TerrainSettings.vertexMapSize / locationMap.Width; // Create a ruler 1 terrain mod long (distance between verticies float terrainModWidth = Statics.TerrainSettings.terrainScaleFactor * vertexmapToObjectmapRelationship; // Get the color value of the node int mapColorR = int.Parse(objectNode.Attributes["red"].Value); int mapColorG = int.Parse(objectNode.Attributes["green"].Value); int mapColorB = int.Parse(objectNode.Attributes["blue"].Value); Vector3 scale = new Vector3((int)(float.Parse(objectNode.Attributes["maxScale"].Value))); float mass = float.Parse(objectNode.Attributes["mass"].Value); bool isCollectable = bool.Parse(objectNode.Attributes["isCollectable"].Value); bool isKey = bool.Parse(objectNode.Attributes["isKey"].Value); // For each pixel of the treeMap for (int l = 0; l < length; l++) { // If the color matches create a prop if (locationColorValues[l].R == mapColorR && locationColorValues[l].G == mapColorG && locationColorValues[l].B == mapColorB) { // Get the 2D location from 1D array int h = l % locationMap.Width; int w = (int)l / locationMap.Width; // Create Object based on type matching in GameObjectTypes GameObject gameObject = new GameObject(); if (!objectLibrary.CreateGameObjectType(objectNode, ref gameObject)) { // GameObject could not be created return false; } // Start Type properties gameObject.mass.gameObjectPointer = gameObject; gameObject.objectModelName = type; // Get terrain height at position float yPosition = objectLibrary.terrain.GetTerrainHeight(w * vertexmapToObjectmapRelationship, h * vertexmapToObjectmapRelationship); // Set the object world properties Vector3 locpos = new Vector3(w * terrainModWidth, yPosition, h * terrainModWidth); Vector3 refpos = new Vector3(w * terrainModWidth, yPosition, h * terrainModWidth - 1); gameObject.mass.SetPosition(locpos, refpos); gameObject.mass.Rotate(0, (float)(2 * Math.PI * rand.NextDouble())); gameObject.mass.scale = scale; gameObject.mass.mass = mass; gameObject.mass.isMoving = false; gameObject.isCollectable = isCollectable; gameObject.isKey = isKey; gameObject.objectValues = new VertexFogBinormalTangent(); gameObject.objectValues.Fog = new Vector4(gameObject.mass.scale, 0.0f); // Store the scale gameObject.objectValues.Binormal = new Vector4(gameObject.mass.currentRotation.X, gameObject.mass.currentRotation.Y, gameObject.mass.currentRotation.Z, gameObject.mass.currentRotation.W); // Store the quaternion rotation // Add mass to attach tangent masses.Add(gameObject.mass); variables[0].AddProperty(gameObject.mass.totalForce); variables[1].AddProperty(gameObject.mass.acceleration); variables[2].AddProperty(gameObject.mass.velocity); variables[3].AddProperty(gameObject.mass.currentRotation); variables[4].AddProperty(gameObject.mass.currentPosition); variables[5].AddProperty(Vector3.Zero); // Dummy Texture variables[6].AddProperty(gameObject.mass.boundingVolume.radius); variables[7].AddProperty(gameObject.mass.scale); variables[8].AddProperty(gameObject.mass.mass); } } if (masses.Count > 0) { // Add a list of CPU Objects to the GPU Object ConvertToVariables(); // HACK gpu_mass.SetValue(masses[0].mass / 100.0f); instanceList = new List(); for (int i = 0; i < masses.Count; i++) { instanceList.Add(masses[i].gameObjectPointer.objectValues); } instanceData = new VertexFogBinormalTangent[instanceList.Count]; instanceList.CopyTo(instanceData); vertexBuffer = new VertexBuffer(Statics.SystemSettings.graphics.GraphicsDevice, typeof(VertexFogBinormalTangent), instanceData.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(instanceData); } // Add Wind Map windMap.Load(objectNode.Attributes["windMap"].Value); return true; } /// /// Adds a mass object to be converted to a GpuObject. /// Used by attack methods. /// /// Mass being added. public void AddMass(Mass mass) { //RetrieveValues(); masses.Add(mass); variables[0].AddProperty(mass.totalForce); variables[1].AddProperty(mass.acceleration); variables[2].AddProperty(mass.velocity); variables[3].AddProperty(mass.currentRotation); variables[4].AddProperty(mass.currentPosition); variables[5].AddProperty(Vector3.Zero); // Dummy Texture variables[6].AddProperty(mass.boundingVolume.radius); variables[7].AddProperty(mass.scale); variables[8].AddProperty(mass.mass); // Set Tangents for // Store the translation // Set Tangents for int i = masses.Count - 1; mass.gameObjectPointer.objectValues.Tangent = new Vector4((float)i % 256 / 256, (float)((int)i / 256) / 256, 0, 0); addObjects.Add(mass.gameObjectPointer.objectValues); ConvertSubsetToVariables(i, 1); } /// /// Remove a mass object from the GpuObjectList. /// /// Mass to be removed. public void RemoveMass(Mass mass) { int index; index = masses.IndexOf(mass); masses.Remove(mass); removeObjects.Add(mass.gameObjectPointer.objectValues); variables[0].ClearProperty(index); variables[1].ClearProperty(index); variables[2].ClearProperty(index); variables[3].ClearProperty(index); variables[4].ClearProperty(index); variables[5].ClearProperty(index); // Dummy Texture variables[6].ClearProperty(index); variables[7].ClearProperty(index); variables[8].ClearProperty(index); ConvertSubsetToVariables(index, 1); } /// /// Convert a list of GameObjects into a Gpu Object /// private void ConvertToVariables() { variables[0].SetTexData(); // totalForce variables[1].SetTexData(); // acceleration variables[2].SetTexData(); // velocity variables[3].SetTexData(); // rotation variables[4].SetTexData(); // currentPosition variables[5].SetTexData(); // dummy variables[6].SetTexData(); // radius variables[7].SetTexData(); // scale variables[8].SetTexData(); // mass // Set Tangents for for (int i = 0; i < masses.Count; i++) { // Store the translation masses[i].gameObjectPointer.objectValues.Tangent = new Vector4((float)i % 256 / 256, (float)((int)i / 256) / 256, 0, 0); } } private void RetrieveValues() { // Unscale the Gpu Objectvariables for (int variableCount = 0; variableCount < variables.Count; variableCount++) { variables[variableCount].UnScale(); } // Get current position for each object for (int massCount = 0; massCount < masses.Count; massCount++) { masses[massCount].totalForce = new Vector3(variables[0].properties[massCount].X, variables[0].properties[massCount].Y, variables[0].properties[massCount].Z); masses[massCount].acceleration = new Vector3(variables[1].properties[massCount].X, variables[1].properties[massCount].Y, variables[1].properties[massCount].Z); masses[massCount].velocity = new Vector3(variables[2].properties[massCount].X, variables[2].properties[massCount].Y, variables[2].properties[massCount].Z); masses[massCount].currentRotation = new Quaternion(variables[3].properties[massCount].X, variables[3].properties[massCount].Y, variables[3].properties[massCount].Z, variables[3].properties[massCount].W); masses[massCount].currentPosition = new Vector3(variables[4].properties[massCount].X, variables[4].properties[massCount].Y, variables[4].properties[massCount].Z); masses[massCount].scale = new Vector3(variables[7].properties[massCount].X); masses[massCount].mass = variables[8].properties[massCount].X; } } private void ConvertSubsetToVariables(int index, int count) { variables[0].SetSubTexData(index, count); // totalForce variables[1].SetSubTexData(index, count); // acceleration variables[2].SetSubTexData(index, count); // velocity variables[3].SetSubTexData(index, count); // rotation variables[4].SetSubTexData(index, count); // currentPosition variables[5].SetSubTexData(index, count); // dummy variables[6].SetSubTexData(index, count); // radius variables[7].SetSubTexData(index, count); // scale variables[8].SetSubTexData(index, count); // mass } /// /// Update using GpuProcessor. /// /// ObjectLibrary that this list belongs to. public void Update(ObjectLibrary objectLibrary) { // Calc the player's current position Vector2 playerPos2d = new Vector2( Statics.PlayerSettings.playerPosition.X, Statics.PlayerSettings.playerPosition.Z ) / new Vector2(Statics.TerrainSettings.collisionMapSize) / new Vector2(2.0f) + new Vector2(0.5f); playerPositionParam.SetValue(playerPos2d); // Set Wind Map handle in shader windMap.SetWindMap(ShaderParameters.effect_update); // Set Scale and Min Value range ShaderParameters.scaleRange.SetValue(variables[4].scaleRange); ShaderParameters.minimumValue.SetValue(variables[4].minimumValue); cpScaleRangeY.SetValue(variables[4].scaleRange); cpScaleMinY.SetValue(variables[4].minimumValue); gpu_scaleMinY.SetValue(objectLibrary.terrain.terrainScaleMinY); gpu_scaleRangeY.SetValue(objectLibrary.terrain.terrainScaleMaxY - objectLibrary.terrain.terrainScaleMinY); gpu_Processor.ExecuteRTT(this, objectLibrary); } /// /// Override Draw function /// /// ModelManager containing this objects model info. /// Shader technique to draw this object with. public override void Draw(ModelManager modelManager, string technique) { #if !XBOX360 ModelInfo modelInfo = modelManager.GetModelInfo(type); ShaderParameters.modelTexture1.SetValue(modelInfo.currentTexture); ShaderParameters.bumpTexture1.SetValue(modelInfo.bumpTexture); // Transfer Current Position Reference from Update Effect to Draw Effect currentPositionParam.SetValue(variables[4]._read); if (removeObjects.Count != 0) { for (int i = 0; i < removeObjects.Count; i++) { instanceList.Remove(removeObjects[i]); } instanceList.CopyTo(instanceData); vertexBuffer = new VertexBuffer(Statics.SystemSettings.graphics.GraphicsDevice, typeof(VertexFogBinormalTangent), instanceData.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(instanceData); removeObjects.Clear(); } if (addObjects.Count != 0) { for (int i = 0; i < addObjects.Count; i++) { instanceList.Add(addObjects[i]); } instanceData = new VertexFogBinormalTangent[instanceList.Count]; instanceList.CopyTo(instanceData); vertexBuffer = new VertexBuffer(Statics.SystemSettings.graphics.GraphicsDevice, typeof(VertexFogBinormalTangent), instanceData.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(instanceData); addObjects.Clear(); } // Set the vertex declaration Statics.SystemSettings.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration; Statics.SystemSettings.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length); // Tell GPU how many times to run through the instance data and set the stream. Statics.SystemSettings.graphics.GraphicsDevice.Vertices[1].SetSource(vertexBuffer, 0, vertexDeclaration.GetVertexStrideSize(1)); Statics.SystemSettings.graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(1); // Draw the model base.DrawInstancedTriStrips(modelInfo.model, technique, vertexDeclaration.GetVertexStrideSize(0)); #endif } } }