/*
* Util.GameScreen.cs
* Authors: Adam Nabinger
* Copyright (c) 2007-2008 Cornell University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Util
{
///
/// The root class for each minigame. A Screen is a DrawableGameComponent intended to be layed one on top of another generically.
///
public abstract class GameScreen : DrawableGameComponent
{
#region Fields
// The global directory for the loading content and file saving/loading
private static readonly string globalRootDirectory;
// The global directory for loading content from
private static readonly string globalRootContentDirectory;
// The global directory for storing any saved files
private static readonly string globalRootStorageDirectory;
// Directory to store any saved files within
private const string storageDirectory = @"\Autism Collaborative\";
// The current content manager
private VariableContentManager mContent;
// The current root directory for content loading and file saving/loading
private string mRootDirectory;
// The input handler used for processing any input on the game screen
private InputHandler mInputHandler;
// The logger used for recording event codes
private Logger mLogger;
// List of drawable game components
private List mComponents;
// The frame rate display object
private FrameRateDisplayComponent frameRateDisplay;
// Whether or not the mouse cursor is trapped within the gamescreen
private bool trap;
///
/// Reference to the main game screen
///
internal MainGame mGame;
#endregion
#region Properties
///
/// Gets/Sets the frame rate display component.
///
protected FrameRateDisplayComponent FrameRateDisplay
{
get { return frameRateDisplay; }
private set { frameRateDisplay = value; }
}
///
/// The fully qualified path of the directory from which the game is being run.
///
public static string GlobalRootDirectory { get { return globalRootDirectory; } }
///
/// The fully qualified path of the main content directory.
///
public static string GlobalRootContentDirectory { get { return globalRootContentDirectory; } }
///
/// The fully qualifed path of the primary storage directory.
/// Currently a subdirectory under My Documents.
///
public static string GlobalRootStorageDirectory { get { return globalRootStorageDirectory; } }
///
/// Expose access to the components associated with this game screen.
///
public ICollection Components { get { return mComponents; } }
///
/// The root, main game, hosting this screen. This reference should be used sparingly, only when necessary (which isn't often).
///
[Obsolete("This Game reference should be used sparingly, when absolutely necessary, and absolutely not for things like 'Game.Components.Contains(x)' or 'foreach(thing in Game.Components)'. That's bad coding practice and will kill your performance.")]
public new MainGame Game { get { return mGame; } }
///
/// The bounds of the window the game is inside.
///
public Rectangle WindowBounds { get { return mGame.Window.ClientBounds; } }
///
/// Gets the Current Content.ContentManager
///
public VariableContentManager Content
{
get { return mContent; }
internal set { mContent = value; }
}
///
/// Gets the Current GraphicsDeviceManager
///
public GraphicsDeviceManager GraphicsDeviceManager { get { return mGame.gdm; } }
///
/// The directory from which the assembly containing this GameScreen was loaded.
///
public string RootDirectory
{
get { return mRootDirectory; }
internal set
{
mRootDirectory = value;
if (Content != null)
{
Content.RootDirectory = mRootDirectory + MainGame.ContentSubdirectory;
}
}
}
///
/// Gets/Sets whether the mouse pointer is visible or not
///
public bool IsMouseVisible {
get { return mGame.IsMouseVisible; }
set { mGame.IsMouseVisible = value; }
}
#endregion
#region Creation
protected GameScreen()
: base(MainGame.TheGame)
{ }
static GameScreen()
{
string RootLoc = Assembly.GetEntryAssembly().Location;
if (RootLoc != null) {
int val = RootLoc.LastIndexOf('\\');
globalRootDirectory = RootLoc.Substring(0, val);
}
globalRootContentDirectory = globalRootDirectory + MainGame.ContentSubdirectory;
globalRootStorageDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + storageDirectory;
if (!Directory.Exists(globalRootStorageDirectory))
{
Directory.CreateDirectory(globalRootStorageDirectory);
}
}
#endregion
#region Initialization
///
/// Base initialize call.
///
public override void Initialize()
{
// Set the texture size allowed for the game based on this computer's hardware
VariableContentManager.SetMaxResolutionToHardwareCapabilities(mGame.gdm.GraphicsDevice);
// Initialization
base.Initialize();
}
///
/// Reinitialize will be called on the screen after a screen which was raised above it is done.
///
public virtual void Reinitialize() { }
#endregion
#region Input Handler
///
/// Get a new Input Handler.
///
/// A new instance of Util.InputHandler
protected InputHandler GetInputHandler()
{
if (mInputHandler == null)
{
mInputHandler = new InputHandler(mGame, UserProfileUtility.CurrentLogger);
}
return mInputHandler;
}
#endregion
#region Logger
///
/// Get a new Logger.
///
/// The new logger
protected Logger GetLogger()
{
if (mLogger == null)
{
mLogger = new Logger(UserProfileUtility.CurrentLogger);
}
return mLogger;
}
#endregion
#region FPS
///
/// Show the FPS of this screen with an overlay component.
///
protected void ShowFPS()
{
if (FrameRateDisplay != null)
{
return;
}
FrameRateDisplay = new FrameRateDisplayComponent();
AddComponent(FrameRateDisplay);
}
///
/// Show the FPS of this screen with an overlay component.
///
/// Path name for the font to use
protected void ShowFPS(string fontName)
{
if (FrameRateDisplay != null)
{
return;
}
FrameRateDisplay = new FrameRateDisplayComponent(fontName);
AddComponent(FrameRateDisplay);
}
#endregion
#region Auto Clear
///
/// Adds a clear object that renders the default color over the entire screen at the given draw order position
///
/// The draw order position for when to render
protected void AutoClear(int drawPosition)
{
Clear mClear = new Clear();
mClear.DrawOrder = drawPosition;
AddComponent(mClear);
}
///
/// Adds a clear object that renders the choosen color over the entire screen at the given draw order position
///
/// The draw order position for when to render
/// The color to render
protected void AutoClear(int drawPosition, Color color)
{
Clear mClear = new Clear(color);
mClear.DrawOrder = drawPosition;
AddComponent(mClear);
}
#endregion
#region Management
///
/// Dispose of this screen and all components it was using.
///
/// Whether or not this is currently being disposed
[DebuggerHidden]
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (trap)
{
MouseUtility.ReleaseTrap();
}
if (mInputHandler != null)
{
mInputHandler.Dispose();
}
if (mLogger != null)
{
mLogger.Dispose();
}
if (mComponents != null)
{
while (mComponents.Count > 0)
{
mComponents[0].Dispose();
}
}
mContent.Unload();
mContent.Dispose();
}
base.Dispose(disposing);
}
[Obsolete("This should never be used.")]
public void PublicAddComponent(DrawableGameScreenComponent newComponent)
{
#if DEBUG
Console.WriteLine("This should never be used.");
#endif
AddComponent(newComponent);
}
///
/// Add a drawable game screen component to the components list managed by this game screen.
/// This component will automatically be initialized and loaded, and will be disposed when this screen is disposed.
///
/// The new component to be added
protected void AddComponent(DrawableGameScreenComponent newComponent)
{
if (newComponent.parent != null)
{
throw new ArgumentException("Component has already been added to a screen.");
}
newComponent.parent = this;
if (mComponents == null)
{
mComponents = new List();
}
mComponents.Add(newComponent);
mGame.Components.Add(newComponent);
//newComponent.Disposed += Components_ComponentRemoved;
}
internal void RemoveComponent(DrawableGameScreenComponent oldComponent)
{
if (mComponents != null)
{
mComponents.Remove(oldComponent);
// mGame's component list is already handled by XNA
}
}
#endregion
#region Activation
///
/// Activates and reveals this gamescreen and all of its components
///
public virtual void Enable()
{
// Disable this
Enabled = true;
Visible = true;
mInputHandler.Enable();
// Do the same for all of our components
if (mComponents == null)
{
return;
}
// Go through and get them all
foreach (DrawableGameScreenComponent component in mComponents)
{
// Disable them
component.Enabled = true;
component.Visible = true;
}
}
///
/// Deactivates and hides this gamescreen and all of its components
///
public virtual void Disable()
{
// Disable this
Enabled = false;
Visible = false;
mInputHandler.Disable();
// Do the same for all of our components
if (mComponents == null)
{
return;
}
// Go through and get them all
foreach (DrawableGameScreenComponent component in mComponents)
{
// Disable them
component.Enabled = false;
component.Visible = false;
}
}
#endregion
#region Screen State
///
/// Remove the screen that is on the top of the stack.
/// Dispose, and UnloadContent are called.
/// Then, the screen below, which is now on top again, gets Reinitialized.
///
protected void Done()
{
mGame.PopScreen();
}
///
/// Ask the game to exit, removing all screens and closing the program.
///
protected void Exit()
{
mGame.Exit();
}
#endregion
#region Modifiers
///
/// Add a new screen to the stack, on top of the current one.
/// Sets the DrawOrder and UpdateOrder of the new Screen to place it on top of the stack.
/// Then, Initialize and LoadContent will be called on the newScreen.
/// Finally, the new Screen will enter into the common Update+Draw loop.
///
/// The new game screen added to the top of the stack
protected void Raise(GameScreen newScreen)
{
if (newScreen.RootDirectory == null)
{
newScreen.RootDirectory = RootDirectory;
}
mGame.PushScreen(newScreen);
}
///
/// Swap the current top screen, with the given one.
///
/// The game screen to replace the current one
protected void Swap(GameScreen newScreen)
{
if (newScreen.RootDirectory == null)
{
newScreen.RootDirectory = RootDirectory;
}
mGame.SwapScreen(newScreen);
}
#endregion
#region Mouse
///
/// Sets the mouse cursor to be unable to leave the game screen
///
protected void TrapMouse()
{
trap = true;
MouseUtility.AutoTrap(mGame);
}
///
/// Gets the mouse cursor's location in the given viewpot
///
/// The location of the mouse cursor
/// The viewport to check
/// The mouse cursor's location in the given viewport
public static Point MouseViewportLocation(Point mouseLoc, Viewport view)
{
Point ret = Point.Zero;
ret.X = mouseLoc.X - view.X;
ret.Y = mouseLoc.Y - view.Y;
return ret;
}
#endregion
}
}