//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// 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);}
}
}
}