//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {License Information: Creative Commons} //--------------------------------------------------------------------------------------------------------------------------------------------------- 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 vertex of one square // private VertexBuffer vertexBuffer; // 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 VertexFogBinormalTangentWeightTess[] 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; // 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), new VertexElement(1, sizeof(float) * 12, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.BlendWeight, 0), new VertexElement(1, sizeof(float) * 16, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.Color, 0), }; public GameObjectList() { gameObjectList = new List(); vertexDeclaration = new VertexDeclaration(ElementalGame.graphics.GraphicsDevice, Elements); instanceData = new VertexFogBinormalTangentWeightTess[0]; } private GameObject CreateGenericObject(Mass.ObjectType objectType) { GameObject retVal = new GameObject(); switch (objectType) { case Mass.ObjectType.CIRCLE: retVal = new Circle(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.CUBE: retVal = new Cube(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.CYLINDER: retVal = new Cylinder(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.PARTICLE: retVal = new Particle(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.PROP: retVal = new Prop(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.PYRAMID: retVal = new Pyramid(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.QUAD: retVal = new Quad(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.SPHERE: retVal = new Sphere(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.SKYSPHERE: retVal = new SkySphere(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.TERRAIN: retVal = new Terrain(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; case Mass.ObjectType.TRIANGLE: retVal = new Triangle(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); break; default: break; } return retVal; } 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) { GameObject gameObject = CreateGenericObject(objectType); 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 x/z position Vector3 locpos = new Vector3(w * terrainModWidth, 1.0f, h * terrainModWidth); Vector3 refpos = new Vector3(w * terrainModWidth, 1.0f, h * terrainModWidth-1); // Set Y to terrain height float yPosition = objectLibrary.terrain.GetTerrainHeight(w * vertexmapToObjectmapRelationship, h * vertexmapToObjectmapRelationship); locpos.Y = yPosition; refpos.Y = yPosition; // Set the position 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); 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 (!gameObject.isCollectable) //{ Matrix matrix = Matrix.CreateScale(gameObject.mass.scale) * Matrix.CreateFromQuaternion(gameObject.mass.currentRotation) * Matrix.CreateTranslation(gameObject.mass.currentPosition); gameObject.objectValues = new VertexFogBinormalTangentWeightTess(); gameObject.objectValues.Fog = new Vector4(matrix.M11, matrix.M12, matrix.M13, matrix.M14); // Store the scale gameObject.objectValues.Binormal = new Vector4(matrix.M21, matrix.M22, matrix.M23, matrix.M24); // Store the quaternion rotation gameObject.objectValues.Tangent = new Vector4(matrix.M31, matrix.M32, matrix.M33, matrix.M34); // Store the translation gameObject.objectValues.BlendWeight = new Vector4(matrix.M41, matrix.M42, matrix.M43, matrix.M44); // Store the fourth row //} ObjectLibrary.lookupMap.SetPosition(gameObject.mass); //ObjectLibrary.lookupMap.AddDynamic(gameObject.mass); // Add the prop to the prop list gameObjectList.Add(gameObject); } } } public void RotatePosition_HackFix(ref Color[] locationColorValues) { } 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 VertexFogBinormalTangentWeightTess[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(VertexFogBinormalTangentWeightTess), instanceData.Length, ResourceUsage.None, ResourceManagementMode.Automatic); instanceBuffer.SetData(instanceData); // Set the vertex declaration ElementalGame.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration; ElementalGame.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length); // 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)); ElementalGame.graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(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 { part.Effect.CurrentTechnique = part.Effect.Techniques["BasicLightingInstancedShaderMain"]; } 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 DrawTriangleStrips(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 (gameObjectList.Count != instanceData.Length) { instanceData = new VertexFogBinormalTangentWeightTess[gameObjectList.Count]; instanceBuffer = new VertexBuffer(ElementalGame.graphics.GraphicsDevice, typeof(VertexFogBinormalTangentWeightTess), instanceData.Length, ResourceUsage.None, ResourceManagementMode.Automatic); } for (int i = 0; i < gameObjectList.Count; i++) { instanceData[i] = gameObjectList[i].objectValues; } //instanceList.CopyTo(instanceData); instanceBuffer.SetData(instanceData); // Set the vertex declaration ElementalGame.graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration; ElementalGame.graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(instanceData.Length); // 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)); ElementalGame.graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(1); // Draw the model foreach (ModelMesh mesh in modelInfo.model.Meshes) { // Set the index buffer ElementalGame.graphics.GraphicsDevice.Indices = mesh.IndexBuffer; int numPrimitives; if (mesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) { numPrimitives = mesh.IndexBuffer.SizeInBytes / sizeof(ushort); } else { numPrimitives = mesh.IndexBuffer.SizeInBytes / sizeof(int); } numPrimitives -= 2; // 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 { part.Effect.CurrentTechnique = part.Effect.Techniques["BasicLightingInstancedShaderMain"]; } 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.TriangleStrip, part.BaseVertex, 0, part.NumVertices, part.StartIndex, numPrimitives); pass.End(); } part.Effect.End(); } } #endif } public void Update(ObjectLibrary objectLibrary) { 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, ElementalGame.dt); gameObjectList[i].objectValues = new VertexFogBinormalTangentWeightTess(); Matrix matrix = Matrix.CreateScale(gameObjectList[i].mass.scale) * Matrix.CreateFromQuaternion(gameObjectList[i].mass.currentRotation) * Matrix.CreateTranslation(gameObjectList[i].mass.currentPosition); gameObjectList[i].objectValues.Fog = new Vector4(matrix.M11, matrix.M12, matrix.M13, matrix.M14); // Store the first row gameObjectList[i].objectValues.Binormal = new Vector4(matrix.M21, matrix.M22, matrix.M23, matrix.M24); // Store the second row gameObjectList[i].objectValues.Tangent = new Vector4(matrix.M31, matrix.M32, matrix.M33, matrix.M34); // Store the third row gameObjectList[i].objectValues.BlendWeight = new Vector4(matrix.M41, matrix.M42, matrix.M43, matrix.M44); // Store the fourth row } } } } }