//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynter.Stream
{
#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
///
/// Handles all render operations
///
public class Renderer
{
///
/// Used in Menu System
///
public SpriteBatch spriteBatch;
private static RenderTarget2D renderTarget; // Primary Render target
private VertexBuffer vertexBuffer; // Buffer to store vertices
private VertexPositionTexture[] vertices; // Array to store vertex Position, Normal and Texture information
private VertexDeclaration vertexDeclaration; // Vertex Declaration
private int totalPlayers;
///
/// Delegate function to draw all world objects.
///
/// Camera number
public delegate List DrawObjectLibrary(int cameraNumber);
///
/// Delegate function to draw all screen objects.
///
/// Player index
public delegate List DrawSprites(int playerIndex);
///
/// Draw HUD delegate type
///
///
///
public delegate void DrawHUD(int playerIndex, SpriteBatch spriteBatch);
///
/// Draw Object Library delegate
///
public DrawObjectLibrary drawObjectLibrary;
///
/// Draw Sprites delegate
///
public DrawSprites drawSprites;
///
/// Draw HUD delegate
///
public DrawHUD drawHUD;
///
/// Constructor
///
public Renderer(ContentManager content)
{
GraphicsDevice graphicsDevice = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
// Set up the menu system components
spriteBatch = new SpriteBatch(Statics_Stream.RenderSettings.graphics.GraphicsDevice);
// Create Vertex Declaration, Buffer, and Array
vertexDeclaration = new VertexDeclaration(graphicsDevice, VertexPositionTexture.VertexElements);
vertexBuffer = new VertexBuffer(graphicsDevice,
VertexPositionTexture.SizeInBytes * 4,
BufferUsage.WriteOnly);
vertices = new VertexPositionTexture[4];
// Create quad with width and height = 1
vertices[0] = new VertexPositionTexture(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f));
vertices[1] = new VertexPositionTexture(new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f));
vertices[2] = new VertexPositionTexture(new Vector3(1.0f, 1.0f, 0.0f), new Vector2(1.0f, 0.0f));
vertices[3] = new VertexPositionTexture(new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 0.0f));
// Set the data
vertexBuffer.SetData(vertices);
}
#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
///
/// Total number of humans in the game
public void Draw(int totplayers)
{
totalPlayers = totplayers;
// Set up state
GraphicsDevice graphicsDevice = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
graphicsDevice.Clear(Color.Black);
graphicsDevice.RenderState.DepthBufferEnable = true;
try
{
// Enable Render To Texture
graphicsDevice.SetRenderTarget(0, renderTarget);
}
catch {
AutoDetectResolution();
}
// Draw GameObjects to the framebuffer
Draw_ObjectLibrary(graphicsDevice);
// Draw Post Process Sprites and HUD
Draw_Sprites(graphicsDevice);
// Disable Render To Texture
graphicsDevice.SetRenderTarget(0, null);
// Store rendered image in modelTexture1
ShaderParameters.DrawFX.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);
// Draw Borders around the screen
Draw_Borders(graphicsDevice, spriteBatch);
}
private void Draw_ObjectLibrary(GraphicsDevice graphicsDevice)
{
// Draw all objects for each player's viewport
for (int cameraNumber = 0; cameraNumber < Statics_Stream.RenderSettings.cameraList.Count; cameraNumber++)
{
Statics_Stream.RenderSettings.cameraList[cameraNumber].viewport.Width = Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH;
Statics_Stream.RenderSettings.cameraList[cameraNumber].viewport.Height = Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT;
graphicsDevice.Viewport = Statics_Stream.RenderSettings.cameraList[cameraNumber].viewport;
graphicsDevice.Clear(new Color(15, 25, 20));
//===\ Game Object Draw / ===
//objectLibrary.Draw(cameraNumber);
List drawList = drawObjectLibrary(cameraNumber);
foreach (Draw drawObject in drawList)
{
if (drawObject != null)
{
drawObject.DoDraw();
}
}
}
}
private void Draw_Sprites(GraphicsDevice graphicsDevice)
{
// Draw all objects for each player's viewport
for (int playerIndex = 0; playerIndex < Statics_Stream.RenderSettings.cameraList.Count; playerIndex++)
{
Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport = Statics_Stream.RenderSettings.cameraList[playerIndex].viewport;
// ObjectLibrary PostDraw_Sprites
//objectLibrary.Draw_Billboards(playerIndex);
List drawList = drawSprites(playerIndex);
foreach (Draw drawObject in drawList)
{
if (drawObject != null)
{
drawObject.DoDraw();
}
}
}
}
private void Draw_HUD(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch)
{
// Draw each player's HUD on top of everything
for (int playerIndex = 0; playerIndex < totalPlayers; playerIndex++)
{
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
graphicsDevice.Viewport = Statics_Stream.RenderSettings.cameraList[playerIndex].viewport;
// Post Draw for Humans
//objectLibrary.PostDraw_HUD(i, spriteBatch);
drawHUD(playerIndex, spriteBatch);
spriteBatch.End();
}
}
private void Draw_PostProcessEffects(GraphicsDevice graphicsDevice)
{
graphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionTexture.SizeInBytes);
graphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0f, 0);
// Setup view and projection matrixes
Statics_Stream.RenderSettings.matrixView = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up);
// Set all the different shader parameter for Anti-Aliasing
ShaderParameters.DrawFX.ViewProj.SetValue(Statics_Stream.RenderSettings.matrixView * Statics_Stream.RenderSettings.matrixProjection);
ShaderParameters.DrawFX.World.SetValue(Statics_Stream.RenderSettings.matrixPosition);
ShaderParameters.DrawFX.effect.CurrentTechnique = ShaderParameters.DrawFX.effect.Techniques["DrawQuad"];
// Render our quad
ShaderParameters.DrawFX.effect.Begin();
foreach (EffectPass pass in ShaderParameters.DrawFX.effect.CurrentTechnique.Passes)
{
pass.Begin();
graphicsDevice.VertexDeclaration = vertexDeclaration;
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
pass.End();
}
ShaderParameters.DrawFX.effect.End();
}
private void Draw_Borders(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch)
{
// Draw the borders on the screen
graphicsDevice.Viewport = Statics_Stream.RenderSettings.defaultViewport;
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.End();
}
#endregion
#region Utilities
private void SetZoomLevel(GraphicsDevice graphicsDevice)
{
// If Zoom enables - HACKED !
if (Statics_Stream.RenderSettings.zoomEnabled)
{
Statics_Stream.RenderSettings.matrixProjection = Matrix.CreateOrthographic(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, 10000);
Statics_Stream.RenderSettings.matrixPosition = Matrix.CreateScale(graphicsDevice.Viewport.Width * Statics_Stream.RenderSettings.zoomFactor,
graphicsDevice.Viewport.Height * Statics_Stream.RenderSettings.zoomFactor,
1) *
Matrix.CreateTranslation(-graphicsDevice.Viewport.Width, -graphicsDevice.Viewport.Height, 0.0f);
}
else
{
Statics_Stream.RenderSettings.matrixProjection = Matrix.CreateOrthographic(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 1, 10000);
Statics_Stream.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);
}
}
///
/// Set up for 1280 or 1024 Resolution.
/// Supports both 4:3 and Widescreen format
///
public static void AutoDetectResolution()
{
// Check the display mode to see how big the resolution
int displayWidth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.Width;
int displayHeight = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.Height;
// Primary render target. Everything drawn in the player viewport's will be rendered to this target
renderTarget = new RenderTarget2D(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.Width,
Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.Height,
1,
SurfaceFormat.Color);
/*
#if XBOX360
Statics.RenderSettings.GAME_WINDOW_WIDTH = displayWidth;
Statics.RenderSettings.GAME_WINDOW_HEIGHT = displayHeight;
#else
//Auto detect best resolution
if (displayWidth >= 1280)
{
// 720p
Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH = 1280;
if (displayHeight >= 1024)
{
// 4:3 resolution
Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT = 1024;
}
else
{
// Widescreen
Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT = 720;
}
}
else if (displayWidth >= 1024)
{
// something in between
Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH = 1024;
Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT = 768;
}
else
{
// Default to 480p
if (displayWidth > 700)
{
Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH = 800;
}
else
{
Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH = 640;
}
if (displayHeight >= 600)
{
Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT = 600;
}
else
{
Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT = 480;
}
}
#endif
*/
Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH = displayWidth;
Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT = displayHeight;
Statics_Stream.RenderSettings.graphics.PreferredBackBufferWidth = Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH;
Statics_Stream.RenderSettings.graphics.PreferredBackBufferHeight = Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT;
Statics_Stream.RenderSettings.graphics.ApplyChanges();
}
///
/// Set up the best settings for Window and ViewPort
///
public static void AutoDetectWindowAndDefaultViewport(/*GameWindow Window*/)
{
// Set up window
Statics_Stream.RenderSettings.clientWidth = Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH;
Statics_Stream.RenderSettings.clientHeight = Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT; // Window.ClientBounds.Height;
Statics_Stream.RenderSettings.clientMinDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MinDepth;
Statics_Stream.RenderSettings.clientMaxDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MaxDepth;
// Set the default viewport
Statics_Stream.RenderSettings.defaultViewport.X = 0;
Statics_Stream.RenderSettings.defaultViewport.Y = 0;
Statics_Stream.RenderSettings.defaultViewport.Width = Statics_Stream.RenderSettings.clientWidth;
Statics_Stream.RenderSettings.defaultViewport.Height = Statics_Stream.RenderSettings.clientHeight;
Statics_Stream.RenderSettings.defaultViewport.MinDepth = Statics_Stream.RenderSettings.clientMinDepth;
Statics_Stream.RenderSettings.defaultViewport.MaxDepth = Statics_Stream.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)
{
Renderer.AutoDetectResolution();
Renderer.AutoDetectWindowAndDefaultViewport(/*Window*/);
Statics_Stream.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_Stream.RenderSettings.clientWidth / 2;
}
else
{
viewportWidth = Statics_Stream.RenderSettings.clientWidth;
}
if (numPlayers > 1)
{
// Divide height
viewportHeight = Statics_Stream.RenderSettings.clientHeight / 2;
}
else
{
viewportHeight = Statics_Stream.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_Stream.RenderSettings.clientMinDepth;
blankCamera.viewport.MaxDepth = Statics_Stream.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_Stream.RenderSettings.cameraList.Add(blankCamera);
}
}
///
/// Reset rendering options to support 3D drawing.
///
public void DisableSpriteBatches()
{
// Make sure culling is off
Statics_Stream.RenderSettings.graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
// Fix the render state post drawing sprite batch
Statics_Stream.RenderSettings.graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
Statics_Stream.RenderSettings.graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
Statics_Stream.RenderSettings.graphics.GraphicsDevice.RenderState.AlphaTestEnable = false;
// Set the Texture addressing mode
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SamplerStates[0].AddressU =
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SamplerStates[0].AddressV =
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SamplerStates[0].AddressW =
TextureAddressMode.Wrap;
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Anisotropic;
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Anisotropic;
Statics_Stream.RenderSettings.graphics.GraphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Anisotropic;
// Release resources locked by XNA
for (int n = 0; n < 16; n++)
{
Statics_Stream.RenderSettings.graphics.GraphicsDevice.Textures[n] = null;
}
}
#endregion
}
}