//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DW Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DW.UI;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Diagnostics;
using System.Xml;
using DW.Data.GameObjects;
using DW.Globals;
using DW.Menus;
using DW.Data;
///
/// Scope of all Graphics related code, includes Renderer and Camera
///
namespace DW.Stream
{
///
/// Renderer is a sub-system static structure that drives all graphics-card related functions
/// This library is specifically split from the engine so it can be swapped out on alt. platforms (eg- DirectX, OpenGL, Mobile)
/// If designed correctly, a single game then only needs to "re-skin" with a different rendering system to port platforms.
/// In more advanced systems, this class holds draw-order dependency and shader-related information as well.
///
public class Renderer
{
public static MenuSystem menuSystem;
List cameras;
Texture2D horizontalBar, verticalBar; // Physical representation of the frame - game/HUD dividors
public List hudLocations;
///
/// Variables
///
public static SpriteBatch spriteBatch;
public static GraphicsDeviceManager graphics;
public static ContentManager content;
public static Viewport view;
///
/// Global Window Settings
///
public struct Dimensions
{
public static bool RESIZABLE = true;
public static Rectangle CLIENTBOUNDS = new Rectangle(0,0,800,600);
}
///
/// Global Font Struct
///
public struct SystemFonts
{
public static SpriteFont Arial;
public static SpriteFont ComicSans;
public static SpriteFont ComicSansSmall;
}
///
/// CTOR
///
public Renderer()
{
Renderer.view = graphics.GraphicsDevice.Viewport;
Renderer.spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
}
///
/// Gets the location of the Menu System (MS) and HUD xml files
/// Can run 4 completely seperate HUDs if so desired
///
/// How many players do we have
public void Load(int numPlayers)
{
SystemFonts.Arial = content.Load("_fonts/Arial");
cameras = new List();
string configFile = "_xml/GameConfiguration.xml";
horizontalBar = Renderer.content.Load("_textures/hud/horbar");
verticalBar = Renderer.content.Load("_textures/hud/vertbar");
hudLocations = new List();
try
{
XmlDocument reader = new XmlDocument();
reader.Load(configFile);
XmlNodeList allNodes = reader.ChildNodes;
foreach (XmlNode node in allNodes)
{
if (node.Name == "GameConfig")
{
foreach (XmlNode thisNode in node)
{
if (thisNode.Name == "MenuSystem")
{
menuSystem = new MenuSystem(thisNode.Attributes["location"].Value);
}
if (thisNode.Name == "HUD")
{
hudLocations.Add(thisNode.Attributes["location"].Value);
}
}
}
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("Error reading xml");
throw e;
}
Clear();
addPane(numPlayers);
}
///
/// Clear Number of Players and all Cameras
///
public void Clear()
{
Statics.PLAYERCOUNT = 0;
cameras.Clear();
}
///
/// Game Loop
///
/// Passed down from engine, controls the HUD timer
/// Provides a snapshot of timing values
public void Update(Stopwatch gameTimer, GameTime gametime)
{
if (Statics.engineState == Enums.EngineState.MENU_MODE)
{
menuSystem.Update();
}
if (Statics.engineState == Enums.EngineState.GAME_MODE)
{
for (int i = 0; i < cameras.Count; i++)
cameras[i].Update(gameTimer, gametime);
}
}
public void DrawMenus(GameTime gametime)
{
if (Statics.engineState == Enums.EngineState.MENU_MODE)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
Renderer.spriteBatch.Begin();
menuSystem.Draw(Renderer.spriteBatch);
Renderer.spriteBatch.End();
}
}
///
/// Main Draw portion of the game, all args should draw themselves,
/// Renderer just controls when it happens
///
/// Provides a snapshot of timing values
/// List of gameobjects to be drawn
public void DrawGame(GameTime gameTime, ObjectLibrary objLib)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
Renderer.spriteBatch.Begin();
// Draw Game
if (Statics.viewMode == Enums.ViewMode.SINGLE_SCREEN)
{
cameras[0].Draw(gameTime, objLib);
}
if (Statics.viewMode == Enums.ViewMode.SPLIT_SCREEN)
{
// Draw Window Panes
for (int x = 0; x < cameras.Count; x++)
cameras[x].Draw(gameTime, objLib);
// Draw (checks if required)
DrawCrossBars();
}
Renderer.spriteBatch.End();
}
private void DrawCrossBars()
{
// Draw Vertical Bar
if (Statics.PLAYERCOUNT > 1)
{
Renderer.spriteBatch.Draw(
verticalBar,
new Rectangle(
(view.Width / 2) - (verticalBar.Width / 2),
0,
verticalBar.Width,
verticalBar.Height),
Color.Green);
}
// Draw Horizontal Bar
if (Statics.PLAYERCOUNT > 2)
{
Renderer.spriteBatch.Draw(
horizontalBar,
new Rectangle(
0,
(view.Height / 2) - (horizontalBar.Height / 2),
horizontalBar.Width,
horizontalBar.Height),
Color.Pink);
}
}
///
/// Drop all content
///
public void Unload()
{
}
///
/// For each player, in split screen, add new pane
/// If not split screen, use a single pane
///
public void addPane(int count)
{
if (count < Statics.PLAYERCOUNTMAX)
{
// Incr. Active Players
Statics.PLAYERCOUNT = count;
//cameras.Clear();
//// Create new Player
List rects = Renderer.GetRectangles(Statics.PLAYERCOUNT);
for (int i = 0; i < rects.Count; i++)
{
cameras.Add(new Camera(hudLocations[i], rects[i]));
}
Resize();
}
else { Console.WriteLine("Too many players specified"); }
}
///
/// Remove a pane from the cameras list - in case a player drops
///
public void removePane()
{
if (cameras.Count > 0)
{
Statics.PLAYERCOUNT--;
cameras.RemoveAt(cameras.Count - 1);
Resize();
}
}
///
/// Keep same size window
///
///
public void Resize()
{
Resize(Renderer.Dimensions.CLIENTBOUNDS);
}
///
/// Handles Resize window and sub-components
/// Resize the windows and down into the cameras
///
/// Window/Game bounds
public void Resize(Rectangle clientBounds)
{
// Quad Ordering (aka - cameras.Count)
//------------------
// Quad 1 | Quad 2 |
// Quad 3 | Quad 4 |
// -----------------
if (cameras == null)
return;
// Get Sizes
List rects = Renderer.GetRectangles(Statics.PLAYERCOUNT);
for (int i = 0; i < Statics.PLAYERCOUNT; i++)
{
// Pass them along
cameras[i].Resize(rects[i]);
}
}
///
/// Mathematical formula for splitting the screen
///
/// Number of players
/// List of Rectangles holding the viewports for each pane
public static List GetRectangles(int frameCount)
{
List rects = new List();
switch (frameCount)
{
case 1:
rects.Add(new Rectangle(0, 0, view.Width, view.Height));
break;
case 2: // 2 players split vertically
rects.Add(new Rectangle(0, 0, view.Width / 2, view.Height));
rects.Add(new Rectangle(view.Width / 2, 0, view.Width / 2, view.Height));
break;
case 3: // 3 player split
rects.Add(new Rectangle(0, 0, view.Width / 2, view.Height / 2));
rects.Add(new Rectangle(view.Width / 2, 0, view.Width / 2, view.Height / 2));
rects.Add(new Rectangle(0, view.Height / 2, view.Width / 2, view.Height / 2));
break;
case 4: // 4 players
rects.Add(new Rectangle(0, 0, view.Width / 2, view.Height / 2));
rects.Add(new Rectangle(view.Width / 2, 0, view.Width / 2, view.Height / 2));
rects.Add(new Rectangle(0, view.Height / 2, view.Width / 2, view.Height / 2));
rects.Add(new Rectangle(view.Width / 2, view.Height / 2, view.Width / 2, view.Height / 2));
break;
default:
break;
}
return rects;
}
}
}