//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- 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 shadowMapTarget1; // Primary Render target RenderTarget2D shadowMapTarget2; // Primary Render target Effect effect; // Effect to render the Render Target to a quad on-screen HeadsUpDisplay viewPortBorders = new HeadsUpDisplay(); Texture2D shadowMap1; Texture2D shadowMap2; 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 target. Everything drawn in the player viewport's will be rendered to this target shadowMapTarget1 = new RenderTarget2D(graphicsDevice, ElementalGame.graphics.GraphicsDevice.Viewport.Width, ElementalGame.graphics.GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color); shadowMapTarget2 = new RenderTarget2D(graphicsDevice, ElementalGame.graphics.GraphicsDevice.Viewport.Width, ElementalGame.graphics.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); // Secondary render target. This is being used to access the depth buffer from the graphics device //depthBuffer = new RenderTarget2D(graphicsDevice, // ElementalGame.caps.MaxTextureWidth, // ElementalGame.caps.MaxTextureHeight, // 1, // SurfaceFormat.Color); // Anti-Aliasing shader effect for rendering the quad to the screen effect = 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.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(0.0f, 1.0f)); vertices[1] = new VertexPositionNormalTexture(new Vector3(1.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 1.0f), new Vector2(1.0f, 1.0f)); vertices[2] = new VertexPositionNormalTexture(new Vector3(1.0f, 1.0f, 0.0f), new Vector3(1.0f, 1.0f, 1.0f), new Vector2(1.0f, 0.0f)); vertices[3] = new VertexPositionNormalTexture(new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 1.0f, 1.0f), new Vector2(0.0f, 0.0f)); // 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(SpriteBatch spriteBatch, ObjectLibrary objectLibrary, List viewportList) { GraphicsDevice graphicsDevice = ElementalGame.graphics.GraphicsDevice; objectLibrary.GetDrawObjects(); if (XML.SystemSettings.enableShadowMap1) { graphicsDevice.SetRenderTarget(0, shadowMapTarget1); // 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); // Shadow mapping 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 targetLocation1 = new Vector3(Terrain.collisionMapSize, 0.0f, Terrain.collisionMapSize * LIGHT_TARGET_Y1); //Vector3 upVector1 = Vector3.Cross(targetLocation1 - lightPosition1, Vector3.UnitZ); 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); //Vector3 targetLocation2 = new Vector3(Terrain.collisionMapSize * LIGHT_TARGET_X2, 0.0f, Terrain.collisionMapSize * LIGHT_TARGET_Y2); //Vector3 upVector2 = Vector3.Cross(targetLocation2 - lightPosition2, Vector3.UnitZ); // 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, ElementalGame.defaultViewport.Width / ElementalGame.defaultViewport.Height, 5.0f, 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 shadowMap1 = shadowMapTarget1.GetTexture(); // Retrieve the Shadow map from our Render Target ShaderParameters.shadowTexture1.SetValue(shadowMap1); } if (XML.SystemSettings.enableShadowMap2) { graphicsDevice.SetRenderTarget(0, shadowMapTarget2); // 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(); ShaderParameters.shadowTexture2.SetValue(shadowMap2); 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]; graphicsDevice.Clear(Color.TransparentBlack); // 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(); // =======================\ Game Object Draw / ================================ 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); 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); 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); graphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0f, 0); // Setup view and projection matrixes Matrix view = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up); Matrix worldViewProj = pos * view * proj; // Set all the different shader parameter for Anti-Aliasing ShaderParameters.ViewProj.SetValue(view * proj); ShaderParameters.World.SetValue(pos); effect.CurrentTechnique = effect.Techniques["FullScreenAntiAliasing"]; // Render our quad effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); graphicsDevice.VertexDeclaration = vertexDeclaration; graphicsDevice.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2); pass.End(); } effect.End(); 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++) { spriteBatch.Begin(SpriteBlendMode.AlphaBlend); graphicsDevice.Viewport = viewportList[i]; // 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(spriteBatch); objectLibrary.DrawTargets(i, spriteBatch); } else { //Draw the dead HUD for dead player objectLibrary.humans[i].deadHUD.Draw(spriteBatch); } spriteBatch.End(); } //draw the borders graphicsDevice.Viewport = ElementalGame.defaultViewport; spriteBatch.Begin(SpriteBlendMode.AlphaBlend); if (XML.SystemSettings.TOTAL_PLAYERS < 3) { viewPortBorders.UpdateImageDraw(1, false); } else{viewPortBorders.UpdateImageDraw(1, true);} if (XML.SystemSettings.TOTAL_PLAYERS > 1){viewPortBorders.Draw(spriteBatch);} } } }