//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- #define GPUInstancing 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; /// /// Contains a list of Generic Props. /// Locations of these props are loaded from a LocationMap, listed in the Prop xml data for the level. /// Generic Props use instancing, and consequently draw much faster than stand alone GameObjects. /// public class PropList : GameObject { // Type information private string type; private List gameObjectList; // CpuObjects run physics and collision on the cpu // The instance data itself 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), }; /// /// Constructor for a PropList. /// public PropList() { vertexDeclaration = new VertexDeclaration(Statics.SystemSettings.graphics.GraphicsDevice, Elements); // Create an Object and Processor //gpu_Processor = new GpuProcessor(); //gpuObject = new GpuObjectList(); gameObjectList = new List(); } /// /// Loads a prop for each xml defined color in the xml defined LocationMap image. /// /// Prop xml node. /// ObjectLibrary that these props belong to. /// True if load was successful public override bool Load(XmlNode objectNode, ObjectLibrary objectLibrary) { // Set up Model Manager type = objectNode.Attributes["type"].Value; bool success = objectLibrary.modelManager.AddNewModel(type, objectNode.Attributes["model"].Value, objectNode.Attributes["texture"].Value, objectNode.Attributes["bumpTexture"].Value); int response = int.Parse(objectNode.Attributes["collisionResponse"].Value); Enums.CollisionResponses currentResponse; if (response == 4) { currentResponse = Enums.CollisionResponses.NONE; } else if (response == 3) { currentResponse = Enums.CollisionResponses.MANNALOSS; } else if (response == 2) { currentResponse = Enums.CollisionResponses.MANNABONUS; } else if (response == 1) { currentResponse = Enums.CollisionResponses.HEALTHLOSS; } else { currentResponse = Enums.CollisionResponses.HEALTHBONUS; } float collisionMultiplier = float.Parse(objectNode.Attributes["collisionMultiplier"].Value); // Return unsuccessfully if can't load user supplied XML data if (!success) { return false; } // 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); // 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; } // Game Attributes gameObject.isCollectable = bool.Parse(objectNode.Attributes["isCollectable"].Value); gameObject.isKey = bool.Parse(objectNode.Attributes["isKey"].Value); // Start Type properties gameObject.mass.gameObjectPointer = gameObject; gameObject.objectModelName = type; // Get terrain height at position float yPosition = objectLibrary.terrain.GetTerrainHeight(w * vertexmapToObjectmapRelationship, h * vertexmapToObjectmapRelationship); // Physics 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 = new Vector3((int)(float.Parse(objectNode.Attributes["maxScale"].Value))); gameObject.mass.mass = float.Parse(objectNode.Attributes["mass"].Value); gameObject.mass.isMoving = false; // Collision gameObject.collisionWithPlayerResponse = currentResponse; gameObject.collisionMultiplier = collisionMultiplier; // Instancing 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 gameObject.objectValues.Tangent = new Vector4(gameObject.mass.currentPosition, 0.0f); // Add the prop to the prop list gameObjectList.Add(gameObject); } } // Check to see if list is empty // Happens if XML color value is not found if (gameObjectList.Count <= 0) return false; else { instanceData = new VertexFogBinormalTangent[gameObjectList.Count]; for (int i = 0; i < gameObjectList.Count; i++) { instanceData[i] = gameObjectList[i].objectValues; } vertexBuffer = new VertexBuffer(Statics.SystemSettings.graphics.GraphicsDevice, typeof(VertexFogBinormalTangent), instanceData.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(instanceData); return true; } } //public void AddNewObject(GameObject gameObject) //{ // 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 // gameObject.objectModelName = type; //} /// /// Updates this list of props. /// /// ObjectLibrary which these props belong to. public override void Update(ref ObjectLibrary objectLibrary) { // Physics? // Collision? // Use booleans loaded from xml... } /// /// Manages drawing all the props in this list. /// /// Contains model info. /// Shader technique to use when drawing these props. 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); // Set the vertex declaration Statics.SystemSettings.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration; Statics.SystemSettings.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length); // Tell the 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); base.DrawInstancedTriStrips(modelInfo.model, technique, vertexDeclaration.GetVertexStrideSize(0)); #endif } } } // Legacy Code :) // public void DrawShadow(ModelManager modelManager) // { // if (instanceData.Length == 0) // { // return; // } //#if !XBOX360 // GetUpdatedInstanceData(); // ModelInfo modelInfo = new ModelInfo(); // modelInfo = modelManager.GetModelInfo(type); // // Set the values of the shader // ShaderParameters.modelTexture1.SetValue(modelInfo.currentTexture); // ShaderParameters.bumpTexture1.SetValue(modelInfo.bumpTexture); // ShaderParameters.World.SetValue(Matrix.Identity); // // Set the vertex declaration // Statics.SystemSettings.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration; // Statics.SystemSettings.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length); // Statics.SystemSettings.graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(1); // // Tell the GPU how many times to run through the instance data and set the stream. // Statics.SystemSettings.graphics.GraphicsDevice.Vertices[1].SetSource(instanceBuffer, 0, vertexDeclaration.GetVertexStrideSize(1)); // // Draw the model // foreach (ModelMesh mesh in modelInfo.model.Meshes) // { // // Set the index buffer // Statics.SystemSettings.graphics.GraphicsDevice.Indices = mesh.IndexBuffer; // // Tell the GPU how many times to run through the vertex data and set the stream. // Statics.SystemSettings.graphics.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, 0, vertexDeclaration.GetVertexStrideSize(0)); // foreach (ModelMeshPart part in mesh.MeshParts) // { // part.Effect.CurrentTechnique = part.Effect.Techniques["InstancedShadowMap"]; // part.Effect.Begin(); // for (int k = 0; k < part.Effect.CurrentTechnique.Passes.Count; k++) // { // EffectPass pass = part.Effect.CurrentTechnique.Passes[k]; // pass.Begin(); // Statics.SystemSettings.graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, // part.BaseVertex, // 0, // part.NumVertices, // part.StartIndex, // part.PrimitiveCount); // pass.End(); // } // part.Effect.End(); // } // } //#endif // }