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