//--------------------------------------------------------------------------------------------------------------------------------------------------- // // 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; #endregion public class Renderer { public static Matrix matrixModelView; // View Matrix public static Matrix matrixProjection; // Projection Matrix RenderTarget2D renderTarget; // Primary Render target RenderTarget2D shadowMapTarget; // Primary Render target Effect AAEffect; // Effect to render the Render Target to a quad on-screen HeadsUpDisplay viewPortBorders = new HeadsUpDisplay(); //Texture2D shadowMap; private VertexBuffer vertexBuffer; // Buffer to store vertices public VertexPositionNormalTexture[] vertices; // Array to store vertex Position, Normal and Texture information private VertexDeclaration vertexDeclaration; // Vertex Declaration public static Matrix lightView1; public static Matrix lightView2; public static Matrix lightProj; public static bool zoomEnabled = false; public static bool HIJACK_VIEWPORT = false; public static bool currentPlayerDead = false; public Renderer() { GraphicsDevice graphicsDevice = ElementalGame.graphics.GraphicsDevice; // Primary render targets. Everything drawn in the player viewport's will be rendered to these targets shadowMapTarget = new RenderTarget2D(graphicsDevice, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, SurfaceFormat.Color); renderTarget = new RenderTarget2D(graphicsDevice, ElementalGame.graphics.GraphicsDevice.Viewport.Width,//ElementalGame.caps.MaxTextureWidth, ElementalGame.graphics.GraphicsDevice.Viewport.Height,//ElementalGame.caps.MaxTextureHeight, 1, SurfaceFormat.Color); // Anti-Aliasing shader effect for rendering the quad to the screen AAEffect = ElementalGame.content.Load("Shaders/ElementalGPU"); // Create Vertex Declaration, Buffer, and Array vertexDeclaration = new VertexDeclaration(graphicsDevice, VertexPositionNormalTexture.VertexElements); vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.SizeInBytes * 4, ResourceUsage.Dynamic, ResourceManagementMode.Manual); vertices = new VertexPositionNormalTexture[4]; // Create quad with width and height = 1 vertices[0] = new VertexPositionNormalTexture(new Vector3(0.0f, 0.0f, 0), new Vector3(0.0f, 0.0f, 1), new Vector2(0, 1.0f)); vertices[1] = new VertexPositionNormalTexture(new Vector3(1.0f, 0.0f, 0), new Vector3(1.0f, 0.0f, 1), new Vector2(1.0f, 1.0f)); vertices[2] = new VertexPositionNormalTexture(new Vector3(1.0f, 1.0f, 0), new Vector3(1.0f, 1.0f, 1), new Vector2(1.0f, 0)); vertices[3] = new VertexPositionNormalTexture(new Vector3(0.0f, 1.0f, 0), new Vector3(0.0f, 1.0f, 1), new Vector2(0, 0)); // Set the data vertexBuffer.SetData(vertices); // Setup HUD for borders viewPortBorders.AddImageDisplay(ElementalGame.content.Load("_textures/black"), new Vector2(0, XML.SystemSettings.GAME_WINDOW_HEIGHT / 2.0f - 10), XML.SystemSettings.GAME_WINDOW_WIDTH, 20, new Color(255, 255, 255, 150), true); viewPortBorders.AddImageDisplay(ElementalGame.content.Load("_textures/black"), new Vector2(XML.SystemSettings.GAME_WINDOW_WIDTH / 2.0f - 10, 0), 20, XML.SystemSettings.GAME_WINDOW_HEIGHT, new Color(255, 255, 255, 150), true); } // Render to the render target once for each user's viewport calling ObjectLibrary's draw functions and // at the same time render the depth buffer to another render target public void Draw(ObjectLibrary objectLibrary, List viewportList) { GraphicsDevice graphicsDevice = ElementalGame.graphics.GraphicsDevice; objectLibrary.GetDrawObjects(); if (XML.SystemSettings.enableShadowMap1) { graphicsDevice.SetRenderTarget(0, shadowMapTarget); // Turn on Render To Texture graphicsDevice.RenderState.DepthBufferEnable = true; // Enable depth buffering // Clear both the render target and the depth buffer graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0); // Do shadow mapping only if the graphics card can handle it graphicsDevice.Viewport = ElementalGame.defaultViewport; // Set the View port Vector3 lightPosition1 = new Vector3(XML.LevelSettings.lightInfo1.M11, XML.LevelSettings.lightInfo1.M12, XML.LevelSettings.lightInfo1.M13); Vector3 targetLocation1 = new Vector3(Terrain.collisionMapSize / 4.0f, 0.0f, Terrain.collisionMapSize / 4.0f); Vector3 lightPosition2 = new Vector3(XML.LevelSettings.lightInfo2.M11, XML.LevelSettings.lightInfo2.M12, XML.LevelSettings.lightInfo2.M13); Vector3 targetLocation2 = new Vector3(Terrain.collisionMapSize * 3.0f / 4.0f, 0.0f, Terrain.collisionMapSize * 3.0f / 4.0f); // Calculate the player's ModelView Matrix lightView1 = Matrix.CreateLookAt(lightPosition1, targetLocation1, objectLibrary.humans[0].mass.upVector); lightView2 = Matrix.CreateLookAt(lightPosition2, targetLocation2, objectLibrary.humans[0].mass.upVector); // Calculate the player's Projection Matrix lightProj = Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 2.0f, graphicsDevice.Viewport.Width / graphicsDevice.Viewport.Height, 0.3f, 100000f); ShaderParameters.LightViewProj1.SetValue(lightView1 * lightProj); ShaderParameters.LightViewProj2.SetValue(lightView2 * lightProj); ShaderParameters.zMaxDepth.SetValue(XML.LevelSettings.zMaxDepth); // Switch to each player's viewport and draw the scene from their perspective objectLibrary.DrawShadow(); graphicsDevice.ResolveRenderTarget(0); // Gets the Rendered Texture and store it in the RenderTarget variable //shadowMap = shadowMapTarget.GetTexture(); // Retrieve the Shadow map from our Render Target ShaderParameters.shadowTexture1.SetValue(shadowMapTarget.GetTexture()); } if (XML.SystemSettings.enableShadowMap2) { graphicsDevice.SetRenderTarget(0, shadowMapTarget); // Turn on Render To Texture graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0); ShaderParameters.LightViewProj1.SetValue(lightView2 * lightProj); // Switch to each players viewport and draw the scene from their perspective objectLibrary.DrawShadow(); graphicsDevice.ResolveRenderTarget(0); //shadowMap2 = shadowMapTarget2.GetTexture(); //shadowMap1.Save("shadow1.png", ImageFileFormat.Png); //shadowMap2.Save("shadow2.png", ImageFileFormat.Png); ShaderParameters.shadowTexture2.SetValue(shadowMapTarget.GetTexture()); ShaderParameters.LightViewProj1.SetValue(lightView1 * lightProj); } graphicsDevice.SetRenderTarget(0, renderTarget); // Turn on Render To Texture graphicsDevice.Clear(Color.TransparentBlack); // Draw all objects for each player's viewport for (int i = 0; i < viewportList.Count; i++) { graphicsDevice.Viewport = viewportList[i]; // Set the View port graphicsDevice.Clear(Color.TransparentBlack); // Clear it //hijack code.. just take it out #region NOT_IN_USE //if (HIJACK_VIEWPORT && i == 0 && objectLibrary.bots.Count > 0 && objectLibrary.bots[0].IsAlive()) //{ // // Calculate the Light's ModelView Matrix // matrixModelView = Matrix.CreateLookAt(objectLibrary.bots[0].mass.currentPosition + objectLibrary.bots[0].mass.normalVector * 2, // objectLibrary.bots[0].mass.currentPosition + objectLibrary.bots[0].mass.normalVector * 3, // objectLibrary.bots[0].mass.upVector); //} //else #endregion { // Calculate the player's ModelView Matrix matrixModelView = Matrix.CreateLookAt(objectLibrary.humans[i].mass.currentPosition, objectLibrary.humans[i].mass.currentPosition + objectLibrary.humans[i].mass.normalVector, objectLibrary.humans[i].mass.upVector); } // Calculate the player's Projection Matrix matrixProjection = Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 4, viewportList[i].Width / viewportList[i].Height, 0.3f, 100000f); ShaderParameters.ViewProj.SetValue(matrixModelView * matrixProjection); ShaderParameters.EyePostion.SetValue(Matrix.Invert(matrixModelView)); ShaderParameters.playerIsDead.SetValue(!objectLibrary.humans[i].IsAlive()); currentPlayerDead = !objectLibrary.humans[i].IsAlive(); // Switch to each players viewport and draw the scene from their perspective objectLibrary.Draw(i); } graphicsDevice.ResolveRenderTarget(0); // Gets the Rendered Texture and store it in the RenderTarget variable ShaderParameters.modelTexture1.SetValue(renderTarget.GetTexture()); // Set the primary render target to modelTexture1 graphicsDevice.SetRenderTarget(0, null); // Reset the Render Target Matrix proj, pos; if (zoomEnabled) { proj = Matrix.CreateOrthographic(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, 10000); // Setup world matrix pos = Matrix.CreateScale(graphicsDevice.Viewport.Width * 2, graphicsDevice.Viewport.Height * 2, 1) * Matrix.CreateTranslation(-graphicsDevice.Viewport.Width, -graphicsDevice.Viewport.Height, 0.0f); } else { proj = Matrix.CreateOrthographic(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, 10000); // Setup world matrix pos = Matrix.CreateScale(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1) * Matrix.CreateTranslation(-graphicsDevice.Viewport.Width / 2.0f, -graphicsDevice.Viewport.Height / 2.0f, 0.0f); } graphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes); // Clear the screen graphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0f, 0); // Setup view and projection matrixes Matrix view = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up); // Set all the different shader parameter for Anti-Aliasing ShaderParameters.ViewProj.SetValue(view * proj); // Pass the calculated world * view * proj matrix ShaderParameters.World.SetValue(pos); AAEffect.CurrentTechnique = AAEffect.Techniques["FullScreenAntiAliasing"]; // Set the technique to use in the shader to AA // Render our quad AAEffect.Begin(); foreach (EffectPass pass in AAEffect.CurrentTechnique.Passes) { pass.Begin(); graphicsDevice.VertexDeclaration = vertexDeclaration; graphicsDevice.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2); pass.End(); } AAEffect.End(); //end the global sprite batch ElementalGame.spriteBatch.End(); // Once this is done, draw each player's HUD on top of everything for (int i = 0; i < XML.SystemSettings.TOTAL_PLAYERS; i++) { ElementalGame.spriteBatch.Begin(SpriteBlendMode.AlphaBlend); graphicsDevice.Viewport = viewportList[i]; // Set the View port // Calculate the player's ModelView Matrix matrixModelView = Matrix.CreateLookAt(objectLibrary.humans[i].mass.currentPosition, objectLibrary.humans[i].mass.currentPosition + objectLibrary.humans[i].mass.normalVector, objectLibrary.humans[i].mass.upVector); // Calculate the player's Projection Matrix matrixProjection = Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 4, viewportList[i].Width / viewportList[i].Height, 0.3f, 100000f); if (objectLibrary.humans[i].IsAlive()) { //Draw the HUD for this human player objectLibrary.humans[i].HUD.Draw(); objectLibrary.DrawTargets(i); } else { //Draw the dead HUD for dead player objectLibrary.humans[i].deadHUD.Draw(); } ElementalGame.spriteBatch.End(); } graphicsDevice.Viewport = ElementalGame.defaultViewport; //start again ElementalGame.spriteBatch.Begin(SpriteBlendMode.AlphaBlend); //draw the borders if (XML.SystemSettings.TOTAL_PLAYERS < 3) { viewPortBorders.UpdateImageDraw(1, false); } else { viewPortBorders.UpdateImageDraw(1, true); } if (XML.SystemSettings.TOTAL_PLAYERS > 1) { viewPortBorders.Draw(); } } } }