//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
#define GPUInstancing
namespace ElementalGame
{
#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
public class GameObjectList
{
public string type;
private List gameObjectList;
// Holds the instance data
private VertexBuffer instanceBuffer;
// Holds indices for rendering a square
// private IndexBuffer indexBuffer;
// A valid vertex declaration so the device knows what to do
private VertexDeclaration vertexDeclaration;
// The instance data itself
private VertexFogBinormalTangent[] instanceData;
// Render To Texture, 2D Orthographic, or 3D Oriented Quads
public enum GenericRenderType { RTT, ORTHOGRAPHIC, INGAME }
public GenericRenderType renderType = GenericRenderType.INGAME; // By default set to in-game...
public static Texture2D particleHotEarthTex;
public static Texture2D particleHotEarthTexBump;
public static Texture2D particleColdEarthTex;
public static Texture2D particleColdEarthTexBump;
public static Texture2D particleHotWaterTex;
public static Texture2D particleHotWaterTexBump;
public static Texture2D particleColdWaterTex;
public static Texture2D particleColdWaterTexBump;
public static Texture2D particleHotAirTex;
public static Texture2D particleHotAirTexBump;
public static Texture2D particleColdAirTex;
public static Texture2D particleColdAirTexBump;
public GpuProcessor gpu_Processor;
public GpuObject gpuObject;
// 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),
};
public GameObjectList()
{
gameObjectList = new List();
// Create an Object and Processor
gpu_Processor = new GpuProcessor();
gpuObject = new GpuObject();
Effect effect = ElementalGame.content.Load("PhysicsGPU/GpuCollisionPhysics");
// Create Variables and add to the
gpuObject.AddVariable(new Vec3(effect, "TotalForce", "totalForce"));
gpuObject.AddVariable(new Vec3(effect, "Acceleration", "acceleration"));
gpuObject.AddVariable(new Vec3(effect, "Velocity", "velocity"));
gpuObject.AddVariable(new Quat(effect, "Rotation", "rotation"));
gpuObject.AddVariable(new Vec3(effect, "LastPosition", "lastPosition"));
gpuObject.AddVariable(new Vec3(effect, "CurrentPosition", "position"));
gpuObject.AddVariable(new Vec3(effect, "Dummy", "dummy"));
gpuObject.AddVariable(new Vec1(effect, "Radius", "radius"));
gpuObject.AddVariable(new Vec1(effect, "Scale", "scale"));
gpuObject.AddVariable(new Vec1(effect, "Mass", "mass"));
}
public void LoadParticleTextures()
{
particleHotAirTex = ElementalGame.content.Load("_textures/AirParticleFire");
particleHotAirTexBump = ElementalGame.content.Load("_textures/AirParticleFire_bump");
particleColdAirTex = ElementalGame.content.Load("_textures/AirParticleCold");
particleColdAirTexBump = ElementalGame.content.Load("_textures/AirParticleCold_bump");
// Load Earth Textures
particleHotEarthTex = ElementalGame.content.Load("_textures/EarthParticleLava");
particleHotEarthTexBump = ElementalGame.content.Load("_textures/EarthParticleLava_bump");
particleColdEarthTex = ElementalGame.content.Load("_textures/EarthParticleFrozen");
particleColdEarthTexBump = ElementalGame.content.Load("_textures/EarthParticleFrozen_bump");
// Load Water Textures
particleHotWaterTex = ElementalGame.content.Load("_textures/WaterParticleBoiling");
particleHotWaterTexBump = ElementalGame.content.Load("_textures/WaterParticleBoiling_bump");
particleColdWaterTex = ElementalGame.content.Load("_textures/WaterParticleIce");
particleColdWaterTexBump = ElementalGame.content.Load("_textures/WaterParticleIce_bump");
}
public void LoadGenerics(XmlNode objectNode, ObjectLibrary objectLibrary, Mass.ObjectType objectType)
{
Effect effect = ElementalGame.content.Load("Shaders/ElementalGPU");
type = objectNode.Attributes["type"].Value;
// Get the Location Map
Texture2D locationMap = ElementalGame.content.Load(objectNode.Attributes["locationMap"].Value);
int length = locationMap.Width * locationMap.Width;
Color[] locationColorValues = new Color[length];
locationMap.GetData(locationColorValues);
Random rand = new Random();
// 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);
// Precalculate the vertexmap/locationmap ratio for use in the for loop below
float vertexmapToObjectmapRelationship = Terrain.vertexMapSize / locationMap.Width;
// Create a ruler 1 terrain mod long (distance between verticies
float terrainModWidth = Terrain.terrainScaleFactor * vertexmapToObjectmapRelationship;
objectLibrary.modelManager.AddNewModel(type,
ElementalGame.content.Load(objectNode.Attributes["model"].Value),
ElementalGame.content.Load(objectNode.Attributes["texture"].Value),
ElementalGame.content.Load(objectNode.Attributes["bumpTexture"].Value),
effect,
GameObject.materialDiffuse,
GameObject.materialSpecular);
// 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)
{
// Create Object based on type
GameObject gameObject = new GameObject();
switch (objectType)
{
case Mass.ObjectType.GPU_OBJECT:
gameObject = new MetaObject(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]);
break;
case Mass.ObjectType.PARTICLE:
gameObject = new Particle(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]);
break;
case Mass.ObjectType.PROP:
gameObject = new Prop(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]);
break;
case Mass.ObjectType.SKYSPHERE:
gameObject = new SkySphere(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]);
break;
case Mass.ObjectType.TERRAIN:
gameObject = new Terrain(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]);
break;
default:
break;
}
gameObject.mass.objectType = objectType;
gameObject.mass.gameObjectPointer = gameObject;
gameObject.objectModelName = type;
// Get the 2D location from 1D array
int h = l % locationMap.Width;
int w = (int)l / locationMap.Width;
// Get terrain height at position
float yPosition = objectLibrary.terrain.GetTerrainHeight(w * vertexmapToObjectmapRelationship,
h * vertexmapToObjectmapRelationship);
// Set x, y, and z position
Vector3 locpos = new Vector3(w * terrainModWidth, yPosition, h * terrainModWidth);
Vector3 refpos = new Vector3(w * terrainModWidth, yPosition, h * terrainModWidth - 1);
// Set the object world properties
gameObject.mass.SetPosition(locpos, refpos);
gameObject.mass.Rotate(0, (float)(2 * Math.PI * rand.NextDouble()));
gameObject.mass.scale = (int)(float.Parse(objectNode.Attributes["maxScale"].Value));
gameObject.mass.mass = float.Parse(objectNode.Attributes["mass"].Value);
gameObject.mass.isMoving = false;
// Can Object be collected
gameObject.isCollectable = bool.Parse(objectNode.Attributes["isCollectable"].Value);
// Is the Object a level key
gameObject.isKey = bool.Parse(objectNode.Attributes["isKey"].Value);
gameObject.objectValues = new VertexFogBinormalTangent();
gameObject.objectValues.Fog = new Vector4(new Vector3(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); // Store the translation
// If key, make it float
if (gameObject.isKey)
{
gameObject.mass.objectType = Mass.ObjectType.KEY;
gameObject.mass.currentPosition.Y += 30.0f;
gameObject.mass.objectHeight = 30.0f;
gameObject._boundingSphere.Center = gameObject.mass.currentPosition;
gameObject._boundingSphere.Radius = gameObject.mass.scale;
}
// If a traiangle, float and rotate it
if (gameObject.mass.objectType == Mass.ObjectType.GPU_OBJECT)
{
gameObject.mass.currentPosition.Y += 30.0f;
gameObject.mass.Rotate((float)Math.PI, 0.0f);
// Add the prop to the prop list
gameObjectList.Add(gameObject);
}
else
{
// Add the prop to the prop list
gameObjectList.Add(gameObject);
}
}
}
if (gameObjectList.Count > 0)
{
if (gameObjectList[0].mass.objectType == Mass.ObjectType.GPU_OBJECT)
{
// Add a list of CPU Objects to the GPU Object
gpuObject.ConvertToVariables(gameObjectList);
// Finalize the GPU Object
gpuObject.SetTextData();
}
}
}
public void AddNewObject(GameObject gameObject)
{
gameObject.objectModelName = type;
gameObjectList.Add(gameObject);
}
public void GetUpdatedInstanceData()
{
for (int i = 0; i < gameObjectList.Count; i++)
{
instanceData[i].Tangent = gameObjectList[i].GetCurrentPosition();
}
instanceBuffer.SetData(instanceData);
}
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
ElementalGame.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration;
ElementalGame.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length);
ElementalGame.graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(1);
// Tell the GPU how many times to run through the instance data and set the stream.
ElementalGame.graphics.GraphicsDevice.Vertices[1].SetSource(instanceBuffer, 0, vertexDeclaration.GetVertexStrideSize(1));
// Draw the model
foreach (ModelMesh mesh in modelInfo.model.Meshes)
{
// Set the index buffer
ElementalGame.graphics.GraphicsDevice.Indices = mesh.IndexBuffer;
// Tell the GPU how many times to run through the vertex data and set the stream.
ElementalGame.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();
ElementalGame.graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
part.BaseVertex,
0,
part.NumVertices,
part.StartIndex,
part.PrimitiveCount);
pass.End();
}
part.Effect.End();
}
}
#endif
}
public void Draw(ModelManager modelManager)
{
if ((gameObjectList.Count == 0))
{
return;
}
//if (instanceList.Count == 0 && !gameObjectList[0].isCollectable)
//{
// return;
//}
#if !XBOX360
ModelInfo modelInfo = new ModelInfo();
modelInfo = modelManager.GetModelInfo(type);
// Set the textures in the shader
if (gameObjectList[0].mass.objectType == Mass.ObjectType.PARTICLE)
{
ShaderParameters.modelTexture1.SetValue(particleColdAirTex);
ShaderParameters.modelTexture2.SetValue(particleHotAirTex);
ShaderParameters.modelTexture3.SetValue(particleColdEarthTex);
ShaderParameters.modelTexture4.SetValue(particleHotEarthTex);
ShaderParameters.modelTexture5.SetValue(particleColdWaterTex);
ShaderParameters.modelTexture6.SetValue(particleHotWaterTex);
ShaderParameters.bumpTexture1.SetValue(particleColdAirTexBump);
ShaderParameters.bumpTexture2.SetValue(particleHotAirTexBump);
ShaderParameters.bumpTexture3.SetValue(particleColdEarthTexBump);
ShaderParameters.bumpTexture4.SetValue(particleHotEarthTexBump);
ShaderParameters.bumpTexture5.SetValue(particleColdWaterTexBump);
ShaderParameters.bumpTexture6.SetValue(particleHotWaterTexBump);
}
else
{
ShaderParameters.modelTexture1.SetValue(modelInfo.currentTexture);
ShaderParameters.bumpTexture1.SetValue(modelInfo.bumpTexture);
}
// Lighting
ShaderParameters.coreShininess.SetValue(7000.0f);
ShaderParameters.coreMaterialDiffuse.SetValue(modelInfo.materialDiffuse);
ShaderParameters.coreMaterialSpecular.SetValue(modelInfo.materialSpecular);
// If Collectable =========================================================================
//if (gameObjectList[0].isCollectable)
//{
// For each game object
//foreach (GameObject gameObject in gameObjectList)
//{
// gameObject.matrix = Matrix.CreateScale(gameObject.mass.scale) *
// Matrix.CreateFromQuaternion(gameObject.mass.currentRotation) *
// Matrix.CreateTranslation(gameObject.mass.currentPosition);
// ShaderParameters.World.SetValue(gameObject.matrix);
// // Draw the model
// foreach (ModelMesh mesh in modelInfo.model.Meshes)
// {
// foreach (Effect currentEffect in mesh.Effects)
// {
// currentEffect.CurrentTechnique = currentEffect.Techniques["BasicLightingShaderMain"];
// }
// mesh.Draw();
// }
//}
//}
// If Indexed
//else
{
//instanceList = new List();
instanceData = new VertexFogBinormalTangent[gameObjectList.Count];
for (int i = 0; i < gameObjectList.Count; i++)
{
instanceData[i] = gameObjectList[i].objectValues;
}
//instanceList.CopyTo(instanceData);
instanceBuffer = new VertexBuffer(ElementalGame.graphics.GraphicsDevice,
typeof(VertexFogBinormalTangent),
instanceData.Length,
ResourceUsage.None,
ResourceManagementMode.Automatic);
instanceBuffer.SetData(instanceData);
vertexDeclaration = new VertexDeclaration(ElementalGame.graphics.GraphicsDevice, Elements);
// Set the vertex declaration
ElementalGame.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration;
ElementalGame.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length);
ElementalGame.graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(1);
// Tell the GPU how many times to run through the instance data and set the stream.
ElementalGame.graphics.GraphicsDevice.Vertices[1].SetSource(instanceBuffer, 0, vertexDeclaration.GetVertexStrideSize(1));
// Draw the model
foreach (ModelMesh mesh in modelInfo.model.Meshes)
{
// Set the index buffer
ElementalGame.graphics.GraphicsDevice.Indices = mesh.IndexBuffer;
// Tell the GPU how many times to run through the vertex data and set the stream.
ElementalGame.graphics.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, 0, vertexDeclaration.GetVertexStrideSize(0));
foreach (ModelMeshPart part in mesh.MeshParts)
{
if (gameObjectList[0].mass.objectType == Mass.ObjectType.PARTICLE)
{
part.Effect.CurrentTechnique = part.Effect.Techniques["InstancedParticleShaderMain"];
}
else
{
#if !GPUInstancing
part.Effect.CurrentTechnique = part.Effect.Techniques["BasicLightingInstancedShaderMain"];
#else
part.Effect.CurrentTechnique = part.Effect.Techniques["GPUPhysixInstancedShaderMain"];
#endif
}
part.Effect.Begin();
for (int k = 0; k < part.Effect.CurrentTechnique.Passes.Count; k++)
{
EffectPass pass = part.Effect.CurrentTechnique.Passes[k];
pass.Begin();
ElementalGame.graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
part.BaseVertex,
0,
part.NumVertices,
part.StartIndex,
part.PrimitiveCount);
pass.End();
}
part.Effect.End();
}
}
}
#endif
}
public void Update(ObjectLibrary objectLibrary, float dt)
{
for (int i = 0; i < gameObjectList.Count; i++)
{
if (gameObjectList[i].mass.deadObject)
{
gameObjectList[i].mass.deadObject = false;
gameObjectList.Remove(gameObjectList[i]);
i--;
}
}
if (gameObjectList.Count == 0)
{
return;
}
if (gameObjectList[0].isKey)
{
for (int i = 0; i < gameObjectList.Count; i++)
{
gameObjectList[i].mass.Rotate(0.0f, dt);
gameObjectList[i].objectValues.Binormal = new Vector4(gameObjectList[i].mass.currentRotation.X,
gameObjectList[i].mass.currentRotation.Y,
gameObjectList[i].mass.currentRotation.Z,
gameObjectList[i].mass.currentRotation.W); // Store the quaternion rotation
}
}
// ======== Added for GPU Physics
if (gameObjectList[0].mass.objectType == Mass.ObjectType.GPU_OBJECT)
{
// GPU physics update hook
gpu_Processor.ExecuteRTT(dt, gpuObject, objectLibrary);
#if !GPUInstancing
// Set up instance positions
gpuObject.RetrieveCurrentPositions(ref gameObjectList);
#endif
for (int i = 0; i < gameObjectList.Count; i++)
{
// Update the List
gameObjectList[i].Update(objectLibrary, dt);
#if GPUInstancing
// Set up instance tangents
gameObjectList[i].objectValues.Tangent = new Vector4((float)i % 128 / 127.0f, (float)((int)i / 128) / 127, 0, 0);
#endif
}
}
}
}
}