//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynterEngine.Draw { #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 using UserInterface; using ObjectLib; using Globals; /// /// Handles all render operations /// public class Renderer { /// /// Used in Menu System /// public SpriteBatch spriteBatch; private HeadsUpDisplay viewPortBordersHUD = new HeadsUpDisplay(); private RenderTarget2D renderTarget; // Primary Render target private RenderTarget2D shadowMapTarget1; // Primary Render target private RenderTarget2D shadowMapTarget2; // Primary Render target private VertexBuffer vertexBuffer; // Buffer to store vertices private VertexPositionNormalTexture[] vertices; // Array to store vertex Position, Normal and Texture information private VertexDeclaration vertexDeclaration; // Vertex Declaration /// /// Constructor /// public Renderer() { GraphicsDevice graphicsDevice = Statics.SystemSettings.graphics.GraphicsDevice; // Primary render target. Everything drawn in the player viewport's will be rendered to this target shadowMapTarget1 = new RenderTarget2D(graphicsDevice, Statics.SystemSettings.graphics.GraphicsDevice.Viewport.Width, Statics.SystemSettings.graphics.GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color); shadowMapTarget2 = new RenderTarget2D(graphicsDevice, Statics.SystemSettings.graphics.GraphicsDevice.Viewport.Width, Statics.SystemSettings.graphics.GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color); renderTarget = new RenderTarget2D(graphicsDevice, Statics.SystemSettings.graphics.GraphicsDevice.Viewport.Width,//Statics.caps.MaxTextureWidth, Statics.SystemSettings.graphics.GraphicsDevice.Viewport.Height,//Statics.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, // Statics.caps.MaxTextureWidth, // Statics.caps.MaxTextureHeight, // 1, // SurfaceFormat.Color); // Set up the menu system components spriteBatch = new SpriteBatch(Statics.SystemSettings.graphics.GraphicsDevice); // Create Vertex Declaration, Buffer, and Array vertexDeclaration = new VertexDeclaration(graphicsDevice, VertexPositionNormalTexture.VertexElements); vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.SizeInBytes * 4, BufferUsage.WriteOnly); 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 viewPortBordersHUD.AddImageDisplay(Statics.SystemSettings.content.Load("Content/_textures/black"), new Vector2(0, Statics.RenderSettings.GAME_WINDOW_HEIGHT / 2.0f - 10), Statics.RenderSettings.GAME_WINDOW_WIDTH, 20, new Color(255, 255, 255, 150), true); viewPortBordersHUD.AddImageDisplay(Statics.SystemSettings.content.Load("Content/_textures/black"), new Vector2(Statics.RenderSettings.GAME_WINDOW_WIDTH / 2.0f - 10, 0), 20, Statics.RenderSettings.GAME_WINDOW_HEIGHT, new Color(255, 255, 255, 150), true); } #region Draw Pipeline Functions /// /// 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 /// /// ObjectLibrary public void Draw(ObjectLibrary objectLibrary) { // Set up state GraphicsDevice graphicsDevice = Statics.SystemSettings.graphics.GraphicsDevice; graphicsDevice.Clear(Color.Black); graphicsDevice.RenderState.DepthBufferEnable = true; // Enable Render To Texture graphicsDevice.SetRenderTarget(0, renderTarget); // Draw GameObjects to the framebuffer Draw_ObjectLibrary(graphicsDevice, objectLibrary); // Draw Post Process Sprites and HUD Draw_Sprites(graphicsDevice, objectLibrary); // Disable Render To Texture graphicsDevice.SetRenderTarget(0, null); // Store rendered image in modelTexture1 ShaderParameters.modelTexture1.SetValue(renderTarget.GetTexture()); // Set viewport matrices based on Zoom level SetZoomLevel(graphicsDevice); // Draw Post Process Shader Effects on modelTexture1 Draw_PostProcessEffects(graphicsDevice); // Draw Heads Up Display Draw_HUD(graphicsDevice, spriteBatch, objectLibrary); // Draw Boarders around the screen Draw_Borders(graphicsDevice, spriteBatch); } private void Draw_ObjectLibrary(GraphicsDevice graphicsDevice, ObjectLibrary objectLibrary) { // Draw all objects for each player's viewport for (int cameraNumber = 0; cameraNumber < Statics.RenderSettings.cameraList.Count; cameraNumber++) { graphicsDevice.Viewport = Statics.RenderSettings.cameraList[cameraNumber].viewport; graphicsDevice.Clear(new Color(15, 25, 20)); // Calculate the player's ModelView Matrix Statics.RenderSettings.matrixView = Statics.RenderSettings.cameraList[cameraNumber].GetViewMatrix(objectLibrary.humans[cameraNumber].mass); // Calculate the player's Projection Matrix Statics.RenderSettings.matrixProjection = Statics.RenderSettings.cameraList[cameraNumber].GetProjectionMatrix(); // Pass Matricies to Shader ShaderParameters.ViewProj.SetValue(Statics.RenderSettings.matrixView * Statics.RenderSettings.matrixProjection); ShaderParameters.EyePostion.SetValue(Matrix.Invert(Statics.RenderSettings.matrixView)); //===\ Game Object Draw / === objectLibrary.Draw(cameraNumber); } } private void Draw_Sprites(GraphicsDevice graphicsDevice, ObjectLibrary objectLibrary) { // Draw all objects for each player's viewport for (int playerIndex = 0; playerIndex < Statics.RenderSettings.cameraList.Count; playerIndex++) { Statics.SystemSettings.graphics.GraphicsDevice.Viewport = Statics.RenderSettings.cameraList[playerIndex].viewport; // Calculate the player's ModelView Matrix Statics.RenderSettings.matrixView = Matrix.CreateLookAt(objectLibrary.humans[playerIndex].mass.currentPosition, objectLibrary.humans[playerIndex].mass.currentPosition + objectLibrary.humans[playerIndex].mass.normalVector, objectLibrary.humans[playerIndex].mass.upVector); // Calculate the player's Projection Matrix Statics.RenderSettings.matrixProjection = Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 4, Statics.RenderSettings.cameraList[playerIndex].viewport.Width / Statics.RenderSettings.cameraList[playerIndex].viewport.Height, 0.3f, 100000f); // ObjectLibrary PostDraw_Sprites objectLibrary.Draw_Billboards(playerIndex); } } private void SetZoomLevel(GraphicsDevice graphicsDevice) { // If Zoom enables - HACKED ! if (Statics.RenderSettings.zoomEnabled) { Statics.RenderSettings.matrixProjection = Matrix.CreateOrthographic(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, 10000); Statics.RenderSettings.matrixPosition = Matrix.CreateScale(graphicsDevice.Viewport.Width * Statics.RenderSettings.zoomFactor, graphicsDevice.Viewport.Height * Statics.RenderSettings.zoomFactor, 1) * Matrix.CreateTranslation(-graphicsDevice.Viewport.Width, -graphicsDevice.Viewport.Height, 0.0f); } else { Statics.RenderSettings.matrixProjection = Matrix.CreateOrthographic(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, 10000); Statics.RenderSettings.matrixPosition = Matrix.CreateScale(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1) * Matrix.CreateTranslation(-graphicsDevice.Viewport.Width / 2.0f, -graphicsDevice.Viewport.Height / 2.0f, 0.0f); } } private void Draw_HUD(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch, ObjectLibrary objectLibrary) { // Draw each player's HUD on top of everything for (int i = 0; i < Statics.SystemSettings.TOTAL_PLAYERS; i++) { spriteBatch.Begin(SpriteBlendMode.AlphaBlend); graphicsDevice.Viewport = Statics.RenderSettings.cameraList[i].viewport; // Post Draw for Humans objectLibrary.PostDraw_HUD(i, spriteBatch); spriteBatch.End(); } } private void Draw_PostProcessEffects(GraphicsDevice graphicsDevice) { graphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes); graphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0f, 0); // Setup view and projection matrixes Statics.RenderSettings.matrixView = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up); // Set all the different shader parameter for Anti-Aliasing ShaderParameters.ViewProj.SetValue(Statics.RenderSettings.matrixView * Statics.RenderSettings.matrixProjection); ShaderParameters.World.SetValue(Statics.RenderSettings.matrixPosition); ShaderParameters.effect_draw.CurrentTechnique = ShaderParameters.effect_draw.Techniques["DrawQuad"]; // Render our quad ShaderParameters.effect_draw.Begin(); foreach (EffectPass pass in ShaderParameters.effect_draw.CurrentTechnique.Passes) { pass.Begin(); graphicsDevice.VertexDeclaration = vertexDeclaration; graphicsDevice.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2); pass.End(); } ShaderParameters.effect_draw.End(); } private void Draw_Borders(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch) { // Draw the borders on the screen graphicsDevice.Viewport = Statics.RenderSettings.defaultViewport; spriteBatch.Begin(SpriteBlendMode.AlphaBlend); if (Statics.SystemSettings.TOTAL_PLAYERS < 3) { viewPortBordersHUD.UpdateImageDraw(1, false); } else { viewPortBordersHUD.UpdateImageDraw(1, true); } if (Statics.SystemSettings.TOTAL_PLAYERS > 1) { viewPortBordersHUD.Draw(spriteBatch); } spriteBatch.End(); } #endregion #region Utilities /// /// Set up for 1280 or 1024 Resolution. /// Supports both 4:3 and Widescreen format /// public void AutoDetectResolution() { // Check the display mode to see how big the resolution int displayWidth = Statics.SystemSettings.graphics.GraphicsDevice.DisplayMode.Width; int displayHeight = Statics.SystemSettings.graphics.GraphicsDevice.DisplayMode.Height; #if XBOX360 Statics.RenderSettings.GAME_WINDOW_WIDTH = displayWidth; Statics.RenderSettings.GAME_WINDOW_HEIGHT = displayHeight; #else //Auto detect best resolution if (displayWidth >= 1280) { // 720p Statics.RenderSettings.GAME_WINDOW_WIDTH = 1280; if (displayHeight >= 1024) { // 4:3 resolution Statics.RenderSettings.GAME_WINDOW_HEIGHT = 1024; } else { // Widescreen Statics.RenderSettings.GAME_WINDOW_HEIGHT = 720; } } else if (displayWidth >= 1024) { // something in between Statics.RenderSettings.GAME_WINDOW_WIDTH = 1024; Statics.RenderSettings.GAME_WINDOW_HEIGHT = 768; } else { // Default to 480p if (displayWidth > 700) { Statics.RenderSettings.GAME_WINDOW_WIDTH = 800; } else { Statics.RenderSettings.GAME_WINDOW_WIDTH = 640; } if (displayHeight >= 600) { Statics.RenderSettings.GAME_WINDOW_HEIGHT = 600; } else { Statics.RenderSettings.GAME_WINDOW_HEIGHT = 480; } } #endif Statics.SystemSettings.graphics.PreferredBackBufferWidth = Statics.RenderSettings.GAME_WINDOW_WIDTH; Statics.SystemSettings.graphics.PreferredBackBufferHeight = Statics.RenderSettings.GAME_WINDOW_HEIGHT; Statics.SystemSettings.graphics.ApplyChanges(); } /// /// Set up the best settings for Window and ViewPort /// public void AutoDetectWindowAndDefaultViewport(GameWindow Window) { // Set up window Statics.RenderSettings.clientWidth = Window.ClientBounds.Width; Statics.RenderSettings.clientHeight = Window.ClientBounds.Height; Statics.RenderSettings.clientMinDepth = Statics.SystemSettings.graphics.GraphicsDevice.Viewport.MinDepth; Statics.RenderSettings.clientMaxDepth = Statics.SystemSettings.graphics.GraphicsDevice.Viewport.MaxDepth; // Set the default viewport Statics.RenderSettings.defaultViewport.X = 0; Statics.RenderSettings.defaultViewport.Y = 0; Statics.RenderSettings.defaultViewport.Width = Statics.RenderSettings.clientWidth; Statics.RenderSettings.defaultViewport.Height = Statics.RenderSettings.clientHeight; Statics.RenderSettings.defaultViewport.MinDepth = Statics.RenderSettings.clientMinDepth; Statics.RenderSettings.defaultViewport.MaxDepth = Statics.RenderSettings.clientMaxDepth; } /// /// Resets all the player viewports based on the number of players currently in-game /// /// Number of players public static void ResetViewports(int numPlayers) { Statics.RenderSettings.cameraList.Clear(); // All viewports needed for the players Camera blankCamera = new Camera(); int viewportWidth, viewportHeight; // Divide the viewport based on number of players if (numPlayers > 2) { // Divide width viewportWidth = Statics.RenderSettings.clientWidth / 2; } else { viewportWidth = Statics.RenderSettings.clientWidth; } if (numPlayers > 1) { // Divide height viewportHeight = Statics.RenderSettings.clientHeight / 2; } else { viewportHeight = Statics.RenderSettings.clientHeight; } // Assign each viewport its screen space for (int i = 0; i < numPlayers; i++) { if (numPlayers > 2) { blankCamera.viewport.X = (i % 2) * viewportWidth; blankCamera.viewport.Y = (i / 2) * viewportHeight; } else { blankCamera.viewport.X = 0; blankCamera.viewport.Y = (i % 2) * viewportHeight; } blankCamera.viewport.Width = viewportWidth; blankCamera.viewport.Height = viewportHeight; blankCamera.viewport.MinDepth = Statics.RenderSettings.clientMinDepth; blankCamera.viewport.MaxDepth = Statics.RenderSettings.clientMaxDepth; // Set the targeting reticle for the player based on this viewport //gameFlow.objectLibrary.humans[i].CreateHUD(newViewport, content); // Add to the global viewport list Statics.RenderSettings.cameraList.Add(blankCamera); } } /// /// Reset rendering options to support 3D drawing. /// public void DisableSpriteBatches() { // Make sure culling is off Statics.SystemSettings.graphics.GraphicsDevice.RenderState.CullMode = CullMode.None; // Fix the render state post drawing sprite batch Statics.SystemSettings.graphics.GraphicsDevice.RenderState.DepthBufferEnable = true; Statics.SystemSettings.graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false; Statics.SystemSettings.graphics.GraphicsDevice.RenderState.AlphaTestEnable = false; // Set the Texture addressing mode Statics.SystemSettings.graphics.GraphicsDevice.SamplerStates[0].AddressU = Statics.SystemSettings.graphics.GraphicsDevice.SamplerStates[0].AddressV = Statics.SystemSettings.graphics.GraphicsDevice.SamplerStates[0].AddressW = TextureAddressMode.Wrap; Statics.SystemSettings.graphics.GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Anisotropic; Statics.SystemSettings.graphics.GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Anisotropic; Statics.SystemSettings.graphics.GraphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Anisotropic; Statics.SystemSettings.graphics.GraphicsDevice.Textures[0] = null; } #endregion } }