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