World Builder – MainForm.cs

 

#region Using Statements
using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using System.Drawing;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
using ParadigmEngine;
using ParadigmEngine.TileEngine;
using ParadigmEngine.ParticleSystem;
using ParadigmEngine.DeferredRenderer;
using ParadigmCommon;
#endregion

namespace Paradigm
{
    /// <summary>
    /// Main editor form.  Handles tile selection as well as XNA pane for map editing.
    /// </summary>
    public partial class MainForm : Form, IXnaGraphicsForm
    {
        #region Fields
        //XNA
        private SpriteBatch spriteBatch;
        private MouseState prevMouseState;
        private static WinFormsContentManager contentManager;
        private DeferredRenderer deferredRenderer;

        private RenderTarget2D colorTarget;
        private RenderTarget2D normalTarget;
        private RenderTarget2D depthTarget;

        /// <summary>
        /// The resolution we had prior to a resize
        /// </summary>
        private Vector2 prevRenderResolution;

        /// <summary>
        /// Has the XNA pane been initialized?
        /// </summary>
        private bool xnaInitialized = false;

        // GDI
        private Image tilesImage;
        private Pen gridPen = new Pen(System.Drawing.Color.Black, 1);
        private Pen selectedPen = new Pen(System.Drawing.Color.Purple, 3.5f);

        // Plugin management
        private List<string> pluginAssemblies = new List<string>();
        private List<ParadigmPlugin> loadedPlugins = new List<ParadigmPlugin>();

        // Map Engine
        private Map map;
        private Texture2D mapTiles;
        private string tileSet;
        private const string defaultMapAssetType = "ParadigmEngine.TileEngine.Map";
        private string mapAssetType = "ParadigmEngine.TileEngine.Map";
        private string mapID;
        private Microsoft.Xna.Framework.Graphics.Color mapBgColor = Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue;
        private int mapTileSize = 32;
        private int mapTileWidth = 50;
        private int mapTileHeight = 50;
        private int mapPixelWidth = 0;
        private int mapPixelHeight = 0;
        private List<bool> mapForegroundLayers = new List<bool>();
        private List<PortalInfo> mapPortalInfoList;
        private List<ShaderRegionInfo> mapShaderRegionInfoList;
        private List<MapEventInfo> mapEventInfoList;
        private List<TerrainInfo> mapTerrainInfoList;

        // Map Editor
        private const int minLayerCount = 3;
        private int layerCount = 3;
        bool[] defaultForegroundData = { false, false, true };
        private bool loadedTexture = false;
        private MapEntity selectedEntity;
        private AnimatedTile selectedAnimatedTile;

        private MouseSelectionHandler mouseSelectionHandler;
        private LightLayerInputHandler lightLayerInputHandler;

        private int tilesetXCount;
        private int tilesetYCount;
        private CollisionLayer collisionLayer;
        private HazardLayer hazardLayer;
        private EntityLayer entityLayer;
        private ParticleLayer particleLayer;
        private PortalLayer portalLayer;
        private ShaderEffectLayer shaderEffectLayer;
        private TerrainLayer terrainLayer;
        private EventLayer eventLayer;
        private TileCoordLayer tileCoordLayer;
        private LightLayer lightLayer;

        // Editor Support
        private SpriteFont spriteFont;
        private SelectionReticle selectionReticle;
        private Microsoft.Xna.Framework.Rectangle prevSelectionRectBounds;
        private const int bufferTiles = 5;

        // Particle system
        private ParticleEmitter selectedEmitter;
        private Texture2D particleTexture;
        private ParticleManager particleManager;

        // initialize brush to a null brush
        private EditorBrush currentBrush = EditorBrush.None;

        // initialize layer to 0
        private int currentLayer = 0;

        // tile selector
        private SelectedTile selectedTile;
        private bool selectedMultipleTiles;
        private Vector2 selectedStartTile;
        private Vector2 selectedEndTile;
        private Vector2 selectedTileRange;

        // matrix scale
        private int prevWheelValue;
        private float mapScale = 1.0f;

        // game timer
        private System.Diagnostics.Stopwatch timer;
        private TimeSpan lastUpdate;

         #endregion

        #region Attributes
        /// <summary>
        /// GraphicsDevice
        /// </summary>
        public GraphicsDevice GraphicsDevice
        {
            get { return xnaDisplay.GraphicsDevice; }
        }

        /// <summary>
        /// Public content manager
        /// </summary>
        public static WinFormsContentManager ContentManager
        {
            get { return contentManager; }
        }

        /// <summary>
        /// Currently Loaded Map
        /// </summary>
        public Map Map
        {
            get { return map; }
        }

        /// <summary>
        /// The actual XNA asset type this map will be exported as
        /// </summary>
        public string MapAssetType
        {
            get { return mapAssetType; }
            set { mapAssetType = value; }
        }

        /// <summary>
        /// Map ID
        /// </summary>
        public string MapID
        {
            get { return mapID; }
            set { mapID = value; }
        }

        /// <summary>
        /// Background color of map
        /// </summary>
        public Microsoft.Xna.Framework.Graphics.Color MapBgColor
        {
            get { return mapBgColor; }
            set { mapBgColor = value; }
        }

        /// <summary>
        /// Tile size
        /// </summary>
        public int MapTileSize
        {
            get { return mapTileSize; }
            set { mapTileSize = value; }
        }

        /// <summary>
        /// Map width in tiles
        /// </summary>
        public int MapTileWidth
        {
            get { return mapTileWidth; }
            set { mapTileWidth = value; }
        }

        /// <summary>
        /// Map height in tiles
        /// </summary>
        public int MapTileHeight
        {
            get { return mapTileHeight; }
            set { mapTileHeight = value; }
        }

        /// <summary>
        /// Map width in pixels
        /// </summary>
        public int MapPixelWidth
        {
            get { return mapPixelWidth; }
            set { mapPixelWidth = value; }
        }

        /// <summary>
        /// Map height in pixels
        /// </summary>
        public int MapPixelHeight
        {
            get { return mapPixelHeight; }
            set { mapPixelHeight = value; }
        }

        /// <summary>
        /// List defining layers tagged as foreground
        /// </summary>
        public List<bool> MapForegroundLayers
        {
            get { return mapForegroundLayers; }
            set { mapForegroundLayers = value; }
        }

        /// <summary>
        /// List of PortalInfo objects from map
        /// </summary>
        public List<PortalInfo> PortalInfoList
        {
            get { return mapPortalInfoList; }
            set { mapPortalInfoList = value; }
        }

        /// <summary>
        /// List of ShaderRegionInfo objects from map
        /// </summary>
        public List<ShaderRegionInfo> ShaderRegionInfoList
        {
            get { return mapShaderRegionInfoList; }
            set { mapShaderRegionInfoList = value; }
        }

        /// <summary>
        /// List of TerrainInfo objects from map
        /// </summary>
        public List<TerrainInfo> TerrainInfoList
        {
            get { return mapTerrainInfoList; }
            set { mapTerrainInfoList = value; }
        }

        /// <summary>
        /// List of MapEventInfo objects from map
        /// </summary>
        public List<MapEventInfo> EventInfoList
        {
            get { return mapEventInfoList; }
            set { mapEventInfoList = value; }
        }

        /// <summary>
        /// The dimensions of the XNA pane
        /// </summary>
        public Vector2 TileDisplayDimensions
        {
            get { return new Vector2((float)xnaDisplay.Width, (float)xnaDisplay.Height); }
        }

        /// <summary>
        /// is the map texture loaded?
        /// </summary>
        public bool LoadedTexture
        {
            get { return loadedTexture; }
        }

        /// <summary>
        /// Selected map entitiy
        /// </summary>
        public MapEntity SelectedEntity
        {
            get { return selectedEntity; }
            set { selectedEntity = value; }
        }

        /// <summary>
        /// Selected animated tile
        /// </summary>
        public AnimatedTile SelectedAnimatedTile
        {
            get { return selectedAnimatedTile; }
            set { selectedAnimatedTile = value; }
        }

        /// <summary>
        /// Selected particle emitter
        /// </summary>
        public ParticleEmitter SelectedEmitter
        {
            get { return selectedEmitter; }
            set { selectedEmitter = value; }
        }

        /// <summary>
        /// Particle manager
        /// </summary>
        public ParticleManager ParticleManager
        {
            get { return particleManager; }
        }

        /// <summary>
        /// Number of map layers
        /// </summary>
        public int LayerCount
        {
            get { return layerCount; }
            set { layerCount = value; }
        }

        /// <summary>
        /// Minimum layers a map can have
        /// </summary>
        public int MinLayerCount
        {
            get { return minLayerCount; }
        }

        /// <summary>
        /// Selection reticle
        /// </summary>
        public SelectionReticle SelectionReticle
        {
            get { return selectionReticle; }
            set { selectionReticle = value; }
        }

        /// <summary>
        /// Paradigm particle texture
        /// </summary>
        public Texture2D ParticleTexture
        {
            get { return particleTexture; }
        }

        /// <summary>
        /// The current map scale value
        /// </summary>
        public float MapScale
        {
            get {return mapScale;}
        }
        #endregion

        #region Form Control Event Methods
        public MainForm()
        {
            InitializeComponent();

            // form event handlers
            xnaDisplay.OnInitialize += new EventHandler(xnaDisplay_OnInitialize);
            xnaDisplay.OnDraw += new EventHandler(xnaDisplay_OnDraw);
            xnaDisplay.MouseEnter += new EventHandler(xnaDisplay_MouseEnter);
            xnaDisplay.MouseLeave += new EventHandler(xnaDisplay_MouseLeave);
            xnaDisplay.MouseDown += new MouseEventHandler(xnaDisplay_MouseDown);
            xnaDisplay.MouseUp += new MouseEventHandler(xnaDisplay_MouseUp);
            xnaDisplay.Layout += new LayoutEventHandler(xnaDisplay_SizeChanged);
            currentBrushBox.SelectedIndexChanged += new EventHandler(currentBrushBox_SelectedIndexChanged);
            currentLayerBox.SelectedIndexChanged += new EventHandler(currentLayerBox_SelectedIndexChanged);
            tileSelectionBox.Paint += new PaintEventHandler(tileSelectionBox_Paint);
            tileSelectionBox.MouseEnter += new EventHandler(tileSelectionBox_MouseEnter);
            tileSelectionBox.MouseLeave += new EventHandler(tileSelectionBox_MouseLeave);
            tileSelectionBox.MouseDown += new MouseEventHandler(tileSelectionBox_MouseDown);
            tileSelectionBox.MouseUp += new MouseEventHandler(tileSelectionBox_MouseUp);
            toolStrip1.MouseEnter += new EventHandler(toolStrip1_MouseEnter);
            hScrollBar1.Scroll += delegate { xnaDisplay.Invalidate(); };
            vScrollBar1.Scroll += delegate { xnaDisplay.Invalidate(); };

            // redraw the tile display when application is idle
            Application.Idle += delegate { xnaDisplay.Invalidate(); };
            Application.Idle += delegate { tileSelectionBox.Invalidate(); };

            // load available plugins
            LoadPlugins();

            InitializeContentBuilder(FileHelper.GetAssemblyDirectory());

            LoadDefaultSettings();

            mapPixelWidth = mapTileWidth * mapTileSize;
            mapPixelHeight = mapTileHeight * mapTileSize;

            // set default foreground data
            mapForegroundLayers.AddRange(defaultForegroundData);

            // start timer
            timer = new System.Diagnostics.Stopwatch();
            lastUpdate = new TimeSpan();

            ParadigmEngine.Rand.random = new Random();
            ParadigmCommon.Rand.random = new Random();

            // initialize static map selections class to hold data for supporting selection form
            MapSelections.Initialize(this);

            timer.Start();

       }

        /// <summary>
        /// Load default editor options
        /// </summary>
        private void LoadDefaultSettings()
        {
            string fileName = FileHelper.GetAssemblyDirectory() + "/options.xml";

            // if the options file exists, load the options
            if (File.Exists(fileName))
            {
                DefaultSettings settings = new DefaultSettings();

                FileHelper.DeserializeXMLObject<DefaultSettings>(fileName, out settings);

                mapAssetType = settings.MapAssetType;
                mapBgColor = settings.MapBgColor;
                mapTileWidth = settings.MapTileWidth;
                mapTileHeight = settings.MapTileHeight;
                mapTileSize = settings.MapTileSize;
            }
            else // if not, create the options file from those saved in the form
            {
                SaveDefaultSettings();
            }

        }

        /// <summary>
        /// Saves the default editor settings
        /// </summary>
        /// <param name="assemblyLocation"></param>
        private void SaveDefaultSettings()
        {
            string fileName = FileHelper.GetAssemblyDirectory() + "/options.xml";

            DefaultSettings settings = new DefaultSettings(mapAssetType, mapBgColor, mapTileSize, mapTileWidth, mapTileHeight);

            FileHelper.SerializeXMLObject<DefaultSettings>(settings, fileName);
        }

        /// <summary>
        /// Initialize the content builder
        /// </summary>
        private void InitializeContentBuilder(string assemblyLocation)
        {
            List<string> buildAssemblies = new List<string>();

            // determine relative locations for map engine libraries
            string dataDllPath = assemblyLocation + "\\ParadigmData.dll";
            string engineDllPath = assemblyLocation + "\\ParadigmEngine.dll";
            string commonDllPath = assemblyLocation + "\\ParadigmCommon.dll";

            buildAssemblies.Add(Path.GetFullPath(dataDllPath));
            buildAssemblies.Add(Path.GetFullPath(engineDllPath));
            buildAssemblies.Add(Path.GetFullPath(commonDllPath));

            // create new content builder with new reference libraries
            //ContentBuilder contentBuilder = new ContentBuilder(
            //    new string[] { Path.GetFullPath(engineDllPath), Path.GetFullPath(extensionDllPath) }
            //    );

            foreach (string assembly in pluginAssemblies)
                buildAssemblies.Add(assembly);

            ContentBuilder builder = new ContentBuilder(buildAssemblies);

            // create content manager
            ContentManager manager = new ContentManager(xnaDisplay.Services,
                                    builder.OutputDirectory);

            /* Not using HDD based cache
             *
            // we no longer want to use the builders output directory as it is
            // constantly cleared.  since we want to dynamically load content,
            // we are going to switch to the new cache system.
            ContentManager manager = new ContentManager(xnaDisplay.Services,
                                    builder.CacheDirectory);
            */

            contentManager = new WinFormsContentManager(builder, manager);
        }

        private void InitializeDeferredRenderer()
        {
            string buildError;
            string currentDirectory = FileHelper.GetAssemblyDirectory();

            deferredRenderer = new DeferredRenderer(GraphicsDevice, true);

            Effect normalEffect = contentManager.LoadContent<Effect>
                (currentDirectory + "/Content/Shaders/DeferredLighting.fx", null, "EffectProcessor", out buildError, false, false);

            Effect combineLightMapsEffect = contentManager.LoadContent<Effect>
                (currentDirectory + "/Content/Shaders/CombineLightMaps.fx", null, "EffectProcessor", out buildError, false, false);

            Effect finalLightingEffect = contentManager.LoadContent<Effect>
                (currentDirectory + "/Content/Shaders/CombineLighting.fx", null, "EffectProcessor", out buildError, false, false);

            deferredRenderer.Initialize(normalEffect, combineLightMapsEffect, finalLightingEffect);

        }

        /// <summary>
        /// Change Current Brush
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void currentBrushBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (Convert.ToString(currentBrushBox.SelectedItem))
            {
                case "None":
                    currentBrush = EditorBrush.None;
                    break;
                case "Tile Draw":
                    currentBrush = EditorBrush.Tile_Draw;
                    break;
                case "Tile Layer Fill":
                    currentBrush = EditorBrush.Tile_Layer_Fill;
                    break;
                case "Animated Tile Draw":
                    currentBrush = EditorBrush.Animated_Tile_Draw;
                    break;
                case "Animated Tile Layer Fill":
                    currentBrush = EditorBrush.Animated_Tile_Layer_Fill;
                    break;
                case "Erase Tiles":
                    currentBrush = EditorBrush.Tile_Erase;
                    break;
                case "Collision - None":
                    currentBrush = EditorBrush.Collision_Passable;
                    break;
                case "Collision - Impassible":
                    currentBrush = EditorBrush.Collision_Impassable;
                    break;
                case "Collision - Slope Down":
                    currentBrush = EditorBrush.Collision_SlopeDown;
                    break;
                case "Collision - Slope Up":
                    currentBrush = EditorBrush.Collision_SlopeUp;
                    break;
                case "Collision - Platform":
                    currentBrush = EditorBrush.Collision_Platform;
                    break;
                case "Collision - Abnormal":
                    currentBrush = EditorBrush.Collision_Abnormal;
                    break;
                case "Collision - NPC":
                    currentBrush = EditorBrush.Collision_NPC;
                    break;
                case "Entity Draw":
                    currentBrush = EditorBrush.Entity_Draw;
                    break;
                case "Entity Erase":
                    currentBrush = EditorBrush.Entity_Erase;
                    break;
                case "Mass Entity Erase":
                    currentBrush = EditorBrush.Mass_Entity_Erase;
                    break;
                case "Particle Emitter Draw":
                    currentBrush = EditorBrush.Particle_Emitter_Draw;
                    break;
                case "Particle Emitter Erase":
                    currentBrush = EditorBrush.Particle_Emitter_Erase;
                    break;
                case "Portal Draw":
                    currentBrush = EditorBrush.Portal_Draw;
                    break;
                case "Event Region Draw":
                    currentBrush = EditorBrush.Event_Region_Draw;
                    break;
                case "Shader Region Draw":
                    currentBrush = EditorBrush.Shader_Region_Draw;
                    break;
                case "Terrain Draw":
                    currentBrush = EditorBrush.Terrain_Draw;
                    break;
                case "Terrain Erase":
                    currentBrush = EditorBrush.Terrain_Erase;
                    break;
                case "Hazard - None":
                    currentBrush = EditorBrush.Hazard_None;
                    break;
                case "Lighting":
                    currentBrush = EditorBrush.Lighting;
                    break;

                default:
                    break;
            }
        }

        private void currentLayerBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            currentLayer = currentLayerBox.SelectedIndex;
        }

        private void toolStrip1_MouseEnter(object sender, EventArgs e)
        {
            if (ActiveForm == this)
                Mouse.WindowHandle = toolStrip1.Handle;
        }

        private void xnaDisplay_MouseLeave(object sender, EventArgs e)
        {   if (ActiveForm == this)
                Mouse.WindowHandle = this.Handle;
        }

        private void xnaDisplay_MouseEnter(object sender, EventArgs e)
        {
            if (ActiveForm == this)
            {
                xnaDisplay.Focus();
                Mouse.WindowHandle = xnaDisplay.Handle;
            }
        }

        /// <summary>
        /// Mouse down.  Ensures mouse handle is set to XNA Display
        /// </summary>
        private void xnaDisplay_MouseDown(object sender, MouseEventArgs e)
        {
            Mouse.WindowHandle = xnaDisplay.Handle;
        }

        /// <summary>
        /// Mouse Up.  Displays context menu depending on brush
        /// </summary>
        private void xnaDisplay_MouseUp(object sender, MouseEventArgs e)
        {
            // show context menu if right mouse button is clicked
            if (e.Button == MouseButtons.Right)
            {
                // get mouse loc
                System.Drawing.Point p = new System.Drawing.Point(e.X, e.Y);

                // determine context menu by tag
                switch (currentBrush)
                {
                    // Iterate through all map entities from back to front.  If we
                    // find a collision, that will be the entity we are editing.
                    case EditorBrush.Entity_Draw:
                        MapEntity entity = null;

                        for (int i = entityLayer.EntityList.Count - 1; i >= 0; i--)
                        {
                            if (entityLayer.EntityList[i].BoundingRectangle.Intersects(selectionReticle.BoundingRectangle))
                            {
                                entity = entityLayer.EntityList[i];
                                break;
                            }
                        }

                        if (entity != null)
                        {
                            prevSelectionRectBounds = selectionReticle.BoundingRectangle;
                            entityIDCM.Show(xnaDisplay, p);
                        }

                        break;
                }
            }
        }

        void xnaDisplay_SizeChanged(object sender, EventArgs e)
        {
            if (!xnaInitialized)
                return;

            int width = GraphicsDevice.DisplayMode.Width;
            int height = GraphicsDevice.DisplayMode.Height;

            // get new resolution
            Vector2 newResolution = new Vector2((float)width,(float)height);

            // only progress if we ACTUALLY changed resoltuion
            if (newResolution == prevRenderResolution)
                return;

            colorTarget.Dispose();
            normalTarget.Dispose();
            depthTarget.Dispose();

            // recreate render targets on size change
            colorTarget = new RenderTarget2D(GraphicsDevice,
                width,
                height,
                1,
                GraphicsDevice.PresentationParameters.BackBufferFormat);

            normalTarget = new RenderTarget2D(GraphicsDevice,
                width,
                height,
                1,
                GraphicsDevice.PresentationParameters.BackBufferFormat);

            depthTarget = new RenderTarget2D(GraphicsDevice,
                width,
                height,
                1,
                GraphicsDevice.PresentationParameters.BackBufferFormat);

            if (deferredRenderer.IsInitialized)
                deferredRenderer.UpdateResolution(GraphicsDevice);

            prevRenderResolution = newResolution;

        }

        /// <summary>
        /// Form load
        /// </summary>
        private void MainForm_Load(object sender, EventArgs e)
        {
            GenerateNewMap();
            UpdateLayers();

            // create dummy selected tile
            selectedTile = new SelectedTile(-1, Vector2.Zero, Microsoft.Xna.Framework.Rectangle.Empty);
        }

        private void editEntityIDCMItem_Click(object sender, EventArgs e)
        {
            MapEntity entity = null;

            for (int i = entityLayer.EntityList.Count - 1; i >= 0; i--)
            {
                if (entityLayer.EntityList[i].BoundingRectangle.Intersects(prevSelectionRectBounds))
                {
                    entity = entityLayer.EntityList[i];
                    break;
                }
            }

            if (entity != null)
            {
                EntityIDForm dialog = new EntityIDForm(entity.ID);
                dialog.TopMost = true;
                dialog.ShowDialog();

                if (dialog.DialogResult == DialogResult.OK)
                {
                    try
                    {
                        entity.ID = dialog.EntityID;
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
        }
        #endregion

        #region XNA
        /// <summary>
        /// Initialize Tile Display
        /// </summary>
        private void xnaDisplay_OnInitialize(object sender, EventArgs e)
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            collisionLayer = new CollisionLayer(this, GraphicsDevice);
            hazardLayer = new HazardLayer(this, GraphicsDevice);
            entityLayer = new EntityLayer(this, GraphicsDevice);
            particleLayer = new ParticleLayer(this, GraphicsDevice);
            portalLayer = new PortalLayer(this, GraphicsDevice);
            shaderEffectLayer = new ShaderEffectLayer(this, GraphicsDevice);
            terrainLayer = new TerrainLayer(this, GraphicsDevice);
            eventLayer = new EventLayer(this, GraphicsDevice);
            tileCoordLayer = new TileCoordLayer(this, GraphicsDevice);
            lightLayer = new LightLayer(this, GraphicsDevice);

            mouseSelectionHandler = new MouseSelectionHandler(this, GraphicsDevice);
            lightLayerInputHandler = new LightLayerInputHandler(this, lightLayer);

            string currentDirectory = FileHelper.GetAssemblyDirectory();
            string buildError;

            // load sprite font
            spriteFont = contentManager.LoadContent<SpriteFont>
                (currentDirectory + "/Content/font.spritefont", null,
                "FontDescriptionProcessor", out buildError, false, false);

            // load selection reticle texture
            Texture2D selectionReticleTex = contentManager.LoadContent<Texture2D>
                (currentDirectory + "/Content/reticle.png", null, null, out buildError, false, false);
            selectionReticle = new SelectionReticle(selectionReticleTex, mapTileSize);

            // load particle texture and manager
            particleTexture = contentManager.LoadContent<Texture2D>
                (currentDirectory + "/Content/paradigm_particles.png", null, null, out buildError, false, false);

            particleManager = new ParticleManager(spriteBatch);

            EntityRenderer.Initialize();

            //int width = xnaDisplay.Width;
            //int height = xnaDisplay.Height;

            int width = GraphicsDevice.DisplayMode.Width;
            int height = GraphicsDevice.DisplayMode.Height;

            // save resolution
            prevRenderResolution = new Vector2((float)width, (float)height);

            // set up render targets on size change
            colorTarget = new RenderTarget2D(GraphicsDevice,
                width,
                height,
                1,
                GraphicsDevice.PresentationParameters.BackBufferFormat);

            normalTarget = new RenderTarget2D(GraphicsDevice,
                width,
                height,
                1,
                GraphicsDevice.PresentationParameters.BackBufferFormat);

            depthTarget = new RenderTarget2D(GraphicsDevice,
                width,
                height,
                1,
                GraphicsDevice.PresentationParameters.BackBufferFormat);

            InitializeDeferredRenderer();

            xnaInitialized = true;
        }

        /// <summary>
        /// Method called before every frame draw.  Similar to the XNA Update() method.
        /// </summary>
        private void xnaDisplay_OnDraw(object sender, EventArgs e)
        {
            // total game time
            TimeSpan total = timer.Elapsed;

            // time elapsed since the last update
            TimeSpan elapsed = total - lastUpdate;

            // create the game time using those values
            GameTime gameTime = new GameTime(total, elapsed, total, elapsed);

            // clear the display
            xnaDisplay.GraphicsDevice.Clear(mapBgColor);

            if ((map != null) && (map.IsInitialized) && (mapTiles != null))
            {
                Logic(gameTime);
                Render(gameTime);
            }

            lastUpdate = total;
        }

        /// <summary>
        /// Perform rendering logic for XNA
        /// TODO:  Clean up input handling
        /// </summary>
        private void Logic(GameTime gameTime)
        {
            // TODO
            // Figure out why there is not a scroll bar buffer anymore

            // update scroll bars
            hScrollBar1.Minimum = (xnaDisplay.Width / 2) - (int)(map.Tile_Size * bufferTiles);
            vScrollBar1.Minimum = (xnaDisplay.Height / 2) - (int)(map.Tile_Size * bufferTiles);
            hScrollBar1.Maximum = (int)(map.Width * map.Tile_Size * mapScale) - hScrollBar1.Minimum + (int)(map.Tile_Size * bufferTiles);
            vScrollBar1.Maximum = (int)(map.Height * map.Tile_Size * mapScale) - vScrollBar1.Minimum + (int)(map.Tile_Size * bufferTiles);

            MouseState mouseState = Mouse.GetState();

            // adjust scale
            CalculateZoom();

            // The mouse x and y positions are returned relative to the
            // upper-left corner of the game window.

            // only edit the map if the mouse is within bounds, the mouse button is down,
            // and the mouse handle is set to this xna control

            Microsoft.Xna.Framework.Rectangle viewportRect;
            viewportRect.X = 0;
            viewportRect.Y = 0;
            viewportRect.Width = mapTileSize * mapTileWidth;
            viewportRect.Height = mapTileSize * mapTileHeight;

            // get tile location of mouse cursor
            Vector2 mouseTileLocation = XnaMouseTileLocation(mouseState);

            Microsoft.Xna.Framework.Point mouseLoc;
            mouseLoc.X = (int)(mouseTileLocation.X * mapTileSize);
            mouseLoc.Y = (int)(mouseTileLocation.Y * mapTileSize);

            tileCoordLabel.Text = "Tile Coordinates: " + mouseTileLocation.X + ", " + mouseTileLocation.Y;
            mouseCoordLabel.Text = "Mouse Coordinates: " + mouseLoc.X + ", " + mouseLoc.Y;

            Vector2 worldPosition = new Vector2(mouseTileLocation.X * mapTileSize, mouseTileLocation.Y * mapTileSize);

            // update selection reticle
            selectionReticle.UpdatePosition(new Vector2(mouseTileLocation.X * mapTileSize, mouseTileLocation.Y * mapTileSize));

            // selected entity - calculate position based on mouse coords
            if (selectedEntity != null)
            {
                selectedEntity.WorldPosition = new Vector2(worldPosition.X + selectedEntity.Sprite.Origin.X, worldPosition.Y);
            }

            // selected animated tile - calculate position based on mouse coords
            if (selectedAnimatedTile != null)
                selectedAnimatedTile.WorldPosition = worldPosition;

            // selected animated tile - calculate position based on mouse coords
            if (selectedEmitter != null)
            {
                selectedEmitter.WorldPosition = new Vector2(worldPosition.X + mapTileSize / 2, worldPosition.Y + mapTileSize / 2);
            }

            // create selected emitter particles if we are drawing them
            if (currentBrush == EditorBrush.Particle_Emitter_Draw)
            {
                if (selectedEmitter != null)
                    selectedEmitter.CreateParticles();
            }

            if (currentBrush == EditorBrush.Entity_Draw) // spawn draw
            {
                if (selectedEntity != null)
                {

                    if ((selectedEntity.BoundingRectangle.Intersects(viewportRect)) &&
                        (mouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed) &&
                        (Mouse.WindowHandle == xnaDisplay.Handle))
                    {
                        EditMap(mouseState, viewportRect);
                    }
                }
            }
            else if (currentBrush == EditorBrush.Entity_Erase) // spawn erase
            {
                if ((mouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed) &&
                    (Mouse.WindowHandle == xnaDisplay.Handle))
                {
                    EditMap(mouseState, viewportRect);
                }
            }
            else // otherwise
            {
                if ((viewportRect.Contains(mouseLoc)) &&
                    (mouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed) &&
                    (Mouse.WindowHandle == xnaDisplay.Handle))
                {
                    EditMap(mouseState, viewportRect);
                }
            }

            // only update the input handler if we are using brushes that utilize it,
            // and the mouse handle is the xna display
            if (((currentBrush == EditorBrush.Portal_Draw) || (currentBrush == EditorBrush.Shader_Region_Draw) || (currentBrush == EditorBrush.Event_Region_Draw)) &&
               (Mouse.WindowHandle == xnaDisplay.Handle))
                mouseSelectionHandler.Update(mouseState);

            if (((currentBrush == EditorBrush.Lighting)) &&
                (Mouse.WindowHandle == xnaDisplay.Handle))
                lightLayerInputHandler.Update(mouseState);

            prevMouseState = Mouse.GetState();

            float frameTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            particleManager.UpdateParticles(frameTime);

            UpdateEntityRenderer();

            map.Update(gameTime);
        }

        /// <summary>
        /// Updates entity render with current map entities and particles
        /// </summary>
        private void UpdateEntityRenderer()
        {
            EntityRenderer.ClearEntities();

            List<DrawableWorldEntity> tempEntityList = new List<DrawableWorldEntity>();

            // Map entities
            if (showSpawnLayerToolStripMenuItem.Checked)
            {
                for (int i = 0; i < entityLayer.EntityList.Count; i++)
                {
                    DrawableWorldEntity entity = entityLayer.EntityList[i] as DrawableWorldEntity;
                    tempEntityList.Add(entity);
                }
            }

            // Particle Emitters
            if (showParticleEmittersToolStripMenuItem.Checked)
            {
                particleLayer.CreateParticles();

                for (int i = 0; i < particleManager.ParticleCount; i++)
                {
                    if (particleManager.Particle[i] != null)
                    {
                        DrawableWorldEntity particle = particleManager.Particle[i] as DrawableWorldEntity;
                        tempEntityList.Add(particle);
                    }
                }
            }

            EntityRenderer.UseZOrdering = zOrderEntitiesToolStripMenuItem.Checked;
            EntityRenderer.AddEntities(tempEntityList);
        }

        /// <summary>
        /// Perform Edits to Map
        /// TODO:  Create MapEditor class and delegate all of this code into functions as this is a bit messy atm
        /// </summary>
        /// <param name="mouseState"></param>
        private void EditMap(MouseState mouseState, Microsoft.Xna.Framework.Rectangle viewportRect)
        {

            Vector2 mouseTileLocation = XnaMouseTileLocation(mouseState);

            if (map != null)
            {
                switch (currentBrush)
                {
                    case EditorBrush.None:
                        break;

                    // TODO:  Find a better way to group these collision brushes, this is messy and
                    // unnecessary

                    case EditorBrush.Collision_Passable:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Collision_Impassable:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Collision_Platform:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Collision_SlopeDown:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Collision_SlopeUp:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Collision_Abnormal:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Collision_NPC:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.SetCollision(map, mouseTileLocation, currentBrush);
                        break;

                    case EditorBrush.Tile_Draw:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.TileDraw(map, mouseTileLocation, currentLayerBox.SelectedIndex, selectedTile, selectedMultipleTiles, selectedStartTile, selectedTileRange);
                        break;

                    case EditorBrush.Animated_Tile_Draw:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.AnimatedTileDraw(map, currentLayer, selectedAnimatedTile, mouseTileLocation);
                        break;

                    case EditorBrush.Animated_Tile_Layer_Fill:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.AnimatedTileLayerFill(map, currentLayer, selectedAnimatedTile, mapTileWidth, mapTileHeight);
                        break;

                    case EditorBrush.Tile_Layer_Fill:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.TileLayerFill(map, currentLayerBox.SelectedIndex, selectedTile);
                        break;

                    case EditorBrush.Tile_Erase:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.TileErase(map, mouseTileLocation, currentLayerBox.SelectedIndex);
                        break;

                    case EditorBrush.Entity_Draw:
                        if (selectedEntity.BoundingRectangle.Intersects(viewportRect))
                        {
                            MapEditor.EntityDraw(map, entityLayer, selectedEntity, mouseTileLocation);
                        }
                        break;

                    case EditorBrush.Entity_Erase:
                        if (prevMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Released)
                        {
                            MapEditor.EntityErase(entityLayer, selectionReticle);
                        }
                        break;

                    case EditorBrush.Mass_Entity_Erase:
                        MapEditor.EntityErase(entityLayer, selectionReticle);
                        break;

                    case EditorBrush.Particle_Emitter_Draw:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.ParticleEmitterDraw(map, particleLayer, selectedEmitter, mouseTileLocation);
                        break;

                    case EditorBrush.Particle_Emitter_Erase:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.ParticleEmitterErase(map, particleLayer, mouseTileLocation);
                        break;

                    case EditorBrush.Portal_Draw:
                        if (MapSelections.PortalSelection > -1)
                        {
                            if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                                MapEditor.PortalDraw(map, mouseSelectionHandler, mapPortalInfoList, MapSelections.PortalSelection);
                        }
                        else
                        {
                            MessageBox.Show("Please select a portal from the portals dropdown within the selection window before attempting to draw.", "No portal selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                        break;

                    case EditorBrush.Event_Region_Draw:
                        if (MapSelections.EventSelection > -1)
                        {
                            if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                                MapEditor.EventRegionDraw(map, mouseSelectionHandler, mapEventInfoList, MapSelections.EventSelection);
                        }
                        else
                        {
                            MessageBox.Show("Please select an event from the shader dropdown within the selection window before attempting to draw.", "No event selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                        break;

                    case EditorBrush.Shader_Region_Draw:
                        if (MapSelections.ShaderSelection > -1)
                        {
                            if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                                MapEditor.ShaderRegionDraw(map, mouseSelectionHandler, mapShaderRegionInfoList, MapSelections.ShaderSelection);
                        }
                        else
                        {
                            MessageBox.Show("Please select a shader from the shader dropdown within the selection window before attempting to draw.", "No shader selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                        break;

                    case EditorBrush.Terrain_Draw:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            if (MapSelections.TerrainSelection > -1)
                                MapEditor.TerrainSet(map, mouseTileLocation, MapSelections.TerrainSelection);
                        break;

                    case EditorBrush.Terrain_Erase:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.TerrainNone(map, mouseTileLocation);
                        break;

                    case EditorBrush.Hazard_Damage:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.HazardDamage(map, mouseTileLocation);
                        break;

                    case EditorBrush.Hazard_None:
                        if ((mouseTileLocation.X < mapTileWidth) && (mouseTileLocation.Y < mapTileHeight))
                            MapEditor.HazardNone(map, mouseTileLocation);
                        break;

                    default:
                        break;
                }
            }
        }

        /// <summary>
        /// Render XNA graphic content to tile display
        /// </summary>
        private void Render(GameTime gameTime)
        {
            // declare transform matrix
            Matrix transformMatrix;

            // create a map display translation matrix and multiply by a scale matrix
            transformMatrix = CreateDisplayTranslation();
            transformMatrix = Matrix.Multiply(transformMatrix, Matrix.CreateScale(mapScale));

            GraphicsDevice.SetRenderTarget(0, null);
            GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.Black);

            Texture2D colorMap = GetColorMap(gameTime, transformMatrix);

            //if (map.TilesetTextures.ColorMap != null)
            //    colorMap.Save("color.png", ImageFileFormat.Png);

            // if we are using the deferred renderer, use it
            if (useDeferredRendererToolStripMenuItem.Checked)
            {
                Texture2D normalMap = GetNormalMap(gameTime, transformMatrix);
                Texture2D depthMap = GetDepthMap(gameTime, transformMatrix);

                //if (map.TilesetTextures.NormalMap != null)
                //    normalMap.Save("normal.png", ImageFileFormat.Png);

                //if (map.TilesetTextures.DepthMap != null)
                //    depthMap.Save("depth.png", ImageFileFormat.Png);

                // TODO:
                // Move this coordinate transformation block into the DeferredRenderer class

                List<PointLight> lights = new List<PointLight>();
                foreach (MapLight light in lightLayer.LightList)
                {
                    // create a copy of the original light
                    PointLight l = new PointLight(light.Light);

                    // modify values
                    Vector3 lPos = l.Position;
                    lPos.X += TranslationVector().X;
                    lPos.Y += TranslationVector().Y;
                    lPos.X *= mapScale;
                    lPos.Y *= mapScale;
                    lPos.Z *= mapScale;
                    l.Position = lPos;

                    l.Brightness *= mapScale;
                    l.Flicker *= mapScale;

                    lights.Add(l);
                }

                Texture2D litScene = deferredRenderer.Draw(spriteBatch, colorMap, normalMap, depthMap, lights, map.LightParams, transformMatrix);

                spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
                spriteBatch.Draw(litScene, Vector2.Zero, Microsoft.Xna.Framework.Graphics.Color.White);
                spriteBatch.End();
            }
            else
            {
                spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
                spriteBatch.Draw(colorMap, Vector2.Zero, Microsoft.Xna.Framework.Graphics.Color.White);
                spriteBatch.End();
            }

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
            {
                if (showCollisionLayerToolStripMenuItem.Checked)
                    collisionLayer.Draw(spriteBatch);

                if (showHazardLayerToolStripMenuItem.Checked)
                    hazardLayer.Draw(spriteBatch);

                if (showTerrainLayerToolStripMenuItem.Checked)
                    terrainLayer.Draw(spriteBatch);

                if (showTerrainLabelsToolStripMenuItem.Checked)
                    terrainLayer.DrawLabels(gameTime, spriteBatch, spriteFont);

                if (showEntityLabelsToolStripMenuItem.Checked)
                    entityLayer.DrawLabels(gameTime, spriteBatch, spriteFont);

                if (showParticleLabelsToolStripMenuItem.Checked)
                    particleLayer.DrawLabels(gameTime, spriteBatch, spriteFont);

                if (showPortalLayerToolStripMenuItem.Checked)
                    portalLayer.Draw(mapPortalInfoList, spriteBatch, spriteFont);

                if (showEventRegionsToolStripMenuItem.Checked)
                    eventLayer.Draw(mapEventInfoList, spriteBatch, spriteFont);

                if (showShaderLayerToolStripMenuItem.Checked)
                    shaderEffectLayer.Draw(mapShaderRegionInfoList, spriteBatch, spriteFont);

                if (showTileCoordinatesToolStripMenuItem.Checked)
                    tileCoordLayer.DrawLabels(spriteBatch, spriteFont);

                if (showTileGridToolStripMenuItem.Checked)
                    tileCoordLayer.DrawGrid(spriteBatch);

                if (showLightLayerToolStripMenuItem.Checked)
                    lightLayer.Draw(spriteBatch);

                if (showLightLabelsToolStripMenuItem.Checked)
                    lightLayer.DrawLabels(spriteBatch, spriteFont);

                if (Mouse.WindowHandle == xnaDisplay.Handle)
                {
                    // get tile location from mouse
                    Vector2 mouseTileLocation = XnaMouseTileLocation(Mouse.GetState());

                    // if we are drawing multiple tiles, hover the selected tiles with alpha
                    if ((currentBrush == EditorBrush.Tile_Draw) && (selectedMultipleTiles == true))
                    {
                        spriteBatch.Draw(
                            map.TilesetTextures.ColorMap,
                            new Vector2(mouseTileLocation.X * mapTileSize, mouseTileLocation.Y * mapTileSize),
                            selectedTile.SourceRect,
                            new Microsoft.Xna.Framework.Graphics.Color(255, 255, 255, 100)
                            );
                    }
                    // if we are working with spawns
                    else if ((selectedEntity != null) && (currentBrush == EditorBrush.Entity_Draw))
                    {
                        // draw entity with transparency
                        selectedEntity.Draw(gameTime, spriteBatch, true);
                    }
                    // if we are working with animated tiles
                    else if ((selectedAnimatedTile != null) && ((currentBrush == EditorBrush.Animated_Tile_Draw) || (currentBrush == EditorBrush.Animated_Tile_Layer_Fill)))
                    {
                        // draw entity with transparency
                        selectedAnimatedTile.Draw(gameTime, spriteBatch, true);
                    }
                    else
                    {
                        // if we are drawing portals, effect regions, or event regions use the input handler
                        if ((currentBrush == EditorBrush.Portal_Draw) || (currentBrush == EditorBrush.Shader_Region_Draw) || (currentBrush == EditorBrush.Event_Region_Draw))
                        {
                            HighlightSelectedTiles(spriteBatch);
                            mouseSelectionHandler.Draw(spriteBatch);
                        }
                        else if (currentBrush == EditorBrush.Lighting)
                        {
                            // lighting drawing here
                        }
                        else
                        {
                            // if we are drawing anything else draw a reticle around the tile we are hovering over
                            selectionReticle.Draw(spriteBatch);
                        }
                    }
                }
            }
            spriteBatch.End();

        }

        /// <summary>
        /// Render the entire scene and return the color map
        /// </summary>
        private Texture2D GetColorMap(GameTime gameTime, Matrix transformMatrix)
        {
            GraphicsDevice.SetRenderTarget(0, colorTarget);

            // attempt to clear the buffer.  this may fail due to not
            // having a correctly formatted Depth Stencil buffer.  If
            // that happens, we need to create a new one
            try
            {
                GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, map.BgColor, 1, 0);
            }
            catch (InvalidOperationException)
            {
                // Set our custom depth buffer
                GraphicsDevice.DepthStencilBuffer = RenderHelper.CreateDepthStencil(colorTarget);

                // try to clear again
                GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, map.BgColor, 1, 0);
            }

            if (showLayerShadingToolStripMenuItem.Checked) // draw with layer shading
            {

                // draw normal map layer
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                {
                    map.Draw(gameTime, spriteBatch, MapDraw.Normal, MapTexture.Color, false, currentLayer);
                }

                // draw particle markers
                if (showParticleMarkersToolStripMenuItem.Checked)
                    particleLayer.DrawMarkers(spriteBatch);

                spriteBatch.End();

                // draw entities
                EntityRenderer.Draw(gameTime, spriteBatch, particleTexture, transformMatrix, true);

                // draw foreground
                if (showForegroundHighlightToolStripMenuItem.Checked)
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Color, true, currentLayer);
                    }
                    spriteBatch.End();
                }
                else
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Color, false, currentLayer);
                    }
                    spriteBatch.End();
                }
            }
            else // draw without shading
            {
                // draw normal map layer
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                {
                    map.Draw(gameTime, spriteBatch, MapDraw.Normal, MapTexture.Color, false, -1);
                }

                // draw particle markers
                if (showParticleMarkersToolStripMenuItem.Checked)
                    particleLayer.DrawMarkers(spriteBatch);

                spriteBatch.End();

                // draw entities
                EntityRenderer.Draw(gameTime, spriteBatch, particleTexture, transformMatrix, true);

                // draw foreground
                if (showForegroundHighlightToolStripMenuItem.Checked)
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Color, true, -1);
                    }
                    spriteBatch.End();
                }
                else
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Color, false, -1);
                    }
                    spriteBatch.End();
                }
            }

            GraphicsDevice.SetRenderTarget(0, null);

            return colorTarget.GetTexture();
        }

        /// <summary>
        /// Render the entire scene and return the color map
        /// </summary>
        private Texture2D GetNormalMap(GameTime gameTime, Matrix transformMatrix)
        {
            GraphicsDevice.SetRenderTarget(0, normalTarget);
            GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer,
                Microsoft.Xna.Framework.Graphics.Color.TransparentWhite,
                1, 0);

            if (showLayerShadingToolStripMenuItem.Checked) // draw with layer shading
            {

                // draw normal map layer
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                {
                    map.Draw(gameTime, spriteBatch, MapDraw.Normal, MapTexture.Normals, false, currentLayer);
                }

                // draw particle markers
                if (showParticleMarkersToolStripMenuItem.Checked)
                    particleLayer.DrawMarkers(spriteBatch);

                spriteBatch.End();

                // draw entities
                EntityRenderer.DrawNormals(gameTime, spriteBatch, particleTexture, transformMatrix, true);

                // draw foreground
                if (showForegroundHighlightToolStripMenuItem.Checked)
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Normals, true, currentLayer);
                    }
                    spriteBatch.End();
                }
                else
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Normals, false, currentLayer);
                    }
                    spriteBatch.End();
                }
            }
            else // draw without shading
            {
                // draw normal map layer
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                {
                    map.Draw(gameTime, spriteBatch, MapDraw.Normal, MapTexture.Normals, false, -1);
                }

                // draw particle markers
                if (showParticleMarkersToolStripMenuItem.Checked)
                    particleLayer.DrawMarkers(spriteBatch);

                spriteBatch.End();

                // draw entities
                EntityRenderer.DrawNormals(gameTime, spriteBatch, particleTexture, transformMatrix, true);

                // draw foreground
                if (showForegroundHighlightToolStripMenuItem.Checked)
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Normals, true, -1);
                    }
                    spriteBatch.End();
                }
                else
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Normals, false, -1);
                    }
                    spriteBatch.End();
                }
            }

            GraphicsDevice.SetRenderTarget(0, null);

            return normalTarget.GetTexture();
        }

        /// <summary>
        /// Render the entire scene and return the color map
        /// </summary>
        private Texture2D GetDepthMap(GameTime gameTime, Matrix transformMatrix)
        {
            GraphicsDevice.SetRenderTarget(0, depthTarget);
            GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer,
                Microsoft.Xna.Framework.Graphics.Color.Black,
                1, 0);

            if (showLayerShadingToolStripMenuItem.Checked) // draw with layer shading
            {

                // draw normal map layer
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                {
                    map.Draw(gameTime, spriteBatch, MapDraw.Normal, MapTexture.Depth, false, currentLayer);
                }

                // draw particle markers
                if (showParticleMarkersToolStripMenuItem.Checked)
                    particleLayer.DrawMarkers(spriteBatch);

                spriteBatch.End();

                // draw entities
                //EntityRenderer.DrawNormals(gameTime, spriteBatch, particleTexture, transformMatrix, true);

                // draw foreground
                if (showForegroundHighlightToolStripMenuItem.Checked)
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Depth, true, currentLayer);
                    }
                    spriteBatch.End();
                }
                else
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Depth, false, currentLayer);
                    }
                    spriteBatch.End();
                }
            }
            else // draw without shading
            {
                // draw normal map layer
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                {
                    map.Draw(gameTime, spriteBatch, MapDraw.Normal, MapTexture.Depth, false, -1);
                }

                // draw particle markers
                if (showParticleMarkersToolStripMenuItem.Checked)
                    particleLayer.DrawMarkers(spriteBatch);

                spriteBatch.End();

                // draw entities
                //EntityRenderer.DrawNormals(gameTime, spriteBatch, particleTexture, transformMatrix, true);

                // draw foreground
                if (showForegroundHighlightToolStripMenuItem.Checked)
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Depth, true, -1);
                    }
                    spriteBatch.End();
                }
                else
                {
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, transformMatrix);
                    {
                        map.Draw(gameTime, spriteBatch, MapDraw.Foreground, MapTexture.Depth, false, -1);
                    }
                    spriteBatch.End();
                }
            }

            GraphicsDevice.SetRenderTarget(0, null);

            return depthTarget.GetTexture();
        }
        /// <summary>
        /// Highlight tiles selected by the input handler
        /// </summary>
        /// <param name="spriteBatch">SpriteBatch</param>
        private void HighlightSelectedTiles(SpriteBatch spriteBatch)
        {
            // create transparent orange texture for selected tiles
            Texture2D selectedTex =
                RuntimeTexture.CreateRectangle(
                    GraphicsDevice,
                    mapTileSize,
                    mapTileSize,
                    new Microsoft.Xna.Framework.Graphics.Color(0,169,235,100));

            for (int y = 0; y < mapTileHeight; y++)
            {
                for (int x = 0; x < mapTileWidth; x++)
                {
                    Tile tempTile = map.GetTile(x, y);

                    if (mouseSelectionHandler.MouseRec.Contains(tempTile.MapRectangle.Center))
                    {
                        spriteBatch.Draw(selectedTex, tempTile.Location, Microsoft.Xna.Framework.Graphics.Color.White);
                    }
                }
            }
        }

        #endregion

 

        #region Loading, Saving, Resizing, and Generating Methods

        /// <summary>
        /// Load XML Map File
        /// </summary>
        /// <param name="fileName">Full path to XML map</param>
        private void LoadMap(string fileName)
        {
            // get the initial time to measure load time
            DateTime startTime = DateTime.Now;

            Cursor = Cursors.WaitCursor;

            string buildError, tempFileName;

            // correct asset type in xml and dump to a temp file for loading
            //XmlAssetCorrector.CorrectInputAssetType(fileName, defaultMapAssetType ,out tempFileName);

            // load the temp file
            map = contentManager.LoadContent<Map>(fileName, null, null, out buildError, true, false);

            // delete the temp file
            //File.Delete(tempFileName);

            if (map.ID != null)
                mapID = map.ID;
            else
                mapID = "";

            mapAssetType = map.AssetType;
            mapBgColor = map.BgColor;
            tileSet = map.TileSet;
            mapForegroundLayers.Clear();
            mapForegroundLayers.AddRange(map.ForegroundLayers);
            mapTileSize = map.Tile_Size;
            mapTileWidth = map.Width;
            mapTileHeight = map.Height;
            mapPixelWidth = map.WidthInPixels;
            mapPixelHeight = map.HeightInPixels;

            lightLayer.AddList(map.LightList);

            mapPortalInfoList.Clear();
            mapPortalInfoList.AddRange(map.PortalList);
            mapShaderRegionInfoList.Clear();
            mapShaderRegionInfoList.AddRange(map.ShaderRegionList);
            mapTerrainInfoList.Clear();
            mapTerrainInfoList.AddRange(map.TerrainList);
            mapEventInfoList.Clear();
            mapEventInfoList.AddRange(map.EventList);

            layerCount = map.Layers.Count;

            // clear spawn layer
            entityLayer.Clear();

            // clear particle layer
            particleLayer.Clear();

            // process entities
            MapEntityDesc entityInfo = new MapEntityDesc();

            string entityResource, prevEntityResource;
            prevEntityResource = "";

            for (int i = 0; i < map.SpawnList.Count; i++)
            {
                MapEntity entity = new MapEntity();

                // get entity directory and filename
                entityResource = FileHelper.GetAssemblyDirectory() + "/Entities/" + map.SpawnList[i].EntityResource + ".xml";

                // if we are using the same resource, no need to load a new one.  otherwise, load the new one.
                if (entityResource != prevEntityResource)
                {
                    if (File.Exists(entityResource))
                    {
                        // load entity info from resource
                        entityInfo = contentManager.LoadContent<MapEntityDesc>
                            (entityResource, null, null, out buildError, false, true);

                        // create new entity and initialize
                        entity = new MapEntity(entityInfo);
                        entity.ResourcePath = map.SpawnList[i].EntityResource;
                        entity.Initialize(this, mapTileSize);
                    }
                }
                else // use a copy of the last entity if we can
                {
                    if ((entityLayer.EntityList[i - 1] != null) && (entityLayer.EntityList[i - 1].Animation != null))
                        entity = entityLayer.EntityList[i - 1];
                }

                if ((entity != null) && (entity.Animation != null))
                {
                    // add entity to map
                    entityLayer.Add(entity, map.SpawnList[i].SpawnPoint, map.SpawnList[i].SpawnTile, map.SpawnList[i].ID);

                    // save the last entity loaded
                    prevEntityResource = entityResource;
                }
            }
            entityLayer.Sort();

            // process particles
            MapParticleDesc particleDesc = new MapParticleDesc();

            string particleResource, prevParticleResource;
            prevParticleResource = "";

            for (int i = 0; i < map.ParticleEmitterList.Count; i++)
            {
                ParticleEmitter particleEmitter = new ParticleEmitter();

                // get entity directory and filename
                particleResource = FileHelper.GetAssemblyDirectory() + "/Particles/" + map.ParticleEmitterList[i].EmitterResource + ".xml";

                // if we are using the same resource, no need to load a new one.  otherwise, load the new one.
                if (particleResource != prevParticleResource)
                {
                    if (File.Exists(particleResource))
                    {
                        // load entity info from resource
                        particleDesc = contentManager.LoadContent<MapParticleDesc>
                            (particleResource, null, null, out buildError, false, true);

                        // create new entity and initialize
                        particleEmitter = new ParticleEmitter(particleManager, map.ParticleEmitterList[i].SpawnPoint, particleDesc);
                        particleEmitter.ResourcePath = map.ParticleEmitterList[i].EmitterResource;
                    }
                }
                else // use a copy of the last entity if we can
                {
                    if (particleLayer.EmitterList[i - 1] != null)
                        particleEmitter = particleLayer.EmitterList[i - 1].Clone();
                }

                if (particleEmitter != null)
                {
                    // add entity to map
                    particleLayer.Add(particleEmitter, map.ParticleEmitterList[i].SpawnPoint, map.ParticleEmitterList[i].SpawnTile);

                    // save the last entity loaded
                    prevParticleResource = particleResource;
                }
            }

            MapSelections.UpdateAll();
            UpdateLayers();

            Cursor = Cursors.Arrow;

            // get the stop time and duration
            DateTime stopTime = DateTime.Now;
            TimeSpan duration = stopTime - startTime;

            // display load time
            MessageBox.Show("Loading took " + duration, "Map Load Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);

            // update reticle
            selectionReticle.SetSize(mapTileSize);
        }

        /// <summary>
        /// Loads all animated tiles for the map post initialization
        /// </summary>
        private void LoadAnimatedTiles()
        {
            List<AnimatedTile> animatedTiles = new List<AnimatedTile>();
            AnimatedTileDesc tileDesc;
            Texture2D animationTex;
            string animationTexPath, buildError;

            string tileResource = "";
            string prevTileResource = "";

            for (int i = 0; i < map.AnimatedTileList.Count; i++)
            {
                AnimatedTile animatedTile = new AnimatedTile();
                animatedTile.ID = -1;

                // get tile directory and filename
                tileResource = map.AnimatedTileList[i].TileResource;

                // if we are using the same resource, no need to load a new one.  otherwise, load the new one.
                if (tileResource != prevTileResource)
                {
                    // load tile info from resource
                    string fullResourcePath = FileHelper.GetAssemblyDirectory() + "/Animated Tiles/" + tileResource + ".xml";

                    if (File.Exists(fullResourcePath))
                    {
                        tileDesc = contentManager.LoadContent<AnimatedTileDesc>
                            (fullResourcePath, null, null, out buildError, false, true);

                        // load texture from desc
                        animationTexPath = FileHelper.GetAssemblyDirectory() + tileDesc.Texture;

                        if (File.Exists(animationTexPath))
                        {
                            animationTex = contentManager.LoadContent<Texture2D>
                                (animationTexPath, null, null, out buildError, false, true);

                            // create new tile and initialize
                            animatedTile = new AnimatedTile();
                            animatedTile.ResourcePath = tileResource;
                            animatedTile.WorldPosition = map.AnimatedTileList[i].SpawnPoint;
                            animatedTile.TilePosition = map.AnimatedTileList[i].SpawnTile;
                            animatedTile.ID = map.AnimatedTileList[i].ID;
                            animatedTile.Layer = map.AnimatedTileList[i].Layer;

                            animatedTile.Initialize(animationTex, tileDesc);
                        }
                    }

                }
                else // use a copy of the last tile if we can
                {
                    if (animatedTiles[i - 1] != null)
                    {
                        animatedTile = animatedTiles[i - 1].Clone();
                        animatedTile.ResourcePath = tileResource;
                        animatedTile.WorldPosition = map.AnimatedTileList[i].SpawnPoint;
                        animatedTile.TilePosition = map.AnimatedTileList[i].SpawnTile;
                        animatedTile.ID = map.AnimatedTileList[i].ID;
                        animatedTile.Layer = map.AnimatedTileList[i].Layer;
                    }
                }

                if (animatedTile.ID != -1)
                {
                    // add tile to temporary list
                    animatedTiles.Add(animatedTile);

                    // add to map
                    map.AddAnimatedTile(animatedTile);

                    // save the last tile loaded
                    prevTileResource = tileResource;
                }
            }
        }

        /// <summary>
        /// Load tile texture
        /// </summary>
        /// <param name="fileName">Full path to texture file</param>
        private void LoadTexture(string fileName)
        {
            Cursor = Cursors.WaitCursor;
            string buildError;

            string path = System.IO.Path.GetDirectoryName(fileName);
            string file = System.IO.Path.GetFileNameWithoutExtension(fileName);
            string fileExt = System.IO.Path.GetExtension(fileName);
            string normalsFile = path + "//" + file + "_Normal" + fileExt;
            string depthFile = path + "//" + file + "_Depth" + fileExt;

            tileSet = "Tiles/" + file;

            tilesImage = Image.FromFile(fileName);
            tileSelectionBox.Image = tilesImage;

            mapTiles = contentManager.LoadContent<Texture2D>(fileName, null, null, out buildError, true, true);
            map.SetColorTexture(mapTiles);

            map.TilesetWidth = map.TilesetTextures.Width;
            map.TilesetHeight = map.TilesetTextures.Height;

            buildError = null;

            Texture2D mapNormals;
            mapNormals = contentManager.LoadContent<Texture2D>(normalsFile, null, null, out buildError, true, true);

            // this build error would indicate an issue loading normals
            // we will circumvent this by creating a dummy texture
            if (buildError != null)
            {
                mapNormals = RuntimeTexture.CreateRectangle(GraphicsDevice,
                    map.TilesetTextures.Width,
                    map.TilesetTextures.Height,
                    new Microsoft.Xna.Framework.Graphics.Color(0, 0, 0, 0));
            }
            map.SetNormalTexture(mapNormals);

            Texture2D mapDepth;
            mapDepth = contentManager.LoadContent<Texture2D>
                (depthFile, null, null, out buildError, true, true);

            // this build error would indicate an issue loading normals
            // we will circumvent this by creating a dummy texture
            if (buildError != null)
            {
                mapDepth = RuntimeTexture.CreateRectangle(GraphicsDevice,
                    map.TilesetTextures.Width,
                    map.TilesetTextures.Height,
                    new Microsoft.Xna.Framework.Graphics.Color(0, 0, 0, 0));
            }
            map.SetDepthTexture(mapDepth);

            map.Initialize();

            tilesetXCount = (int)(tilesImage.Width / mapTileSize);
            tilesetYCount = (int)(tilesImage.Height / mapTileSize);

            Cursor = Cursors.Arrow;

            loadedTexture = true;
        }

        /// <summary>
        /// Exports new tile map to an XML file
        /// </summary>
        /// <param name="fileName">File Name</param>
        private void ExportMap(string fileName)
        {
            // declare temp rows
            List<string> layerRows = new List<string>();

            // create new map
            Map newMap = new Map();

            // create spawn list
            List<MapEntityInfo> spawnList = new List<MapEntityInfo>();

            // create animated tile list
            List<AnimatedTileInfo> animatedTileList = new List<AnimatedTileInfo>();

            // create particle emitter list
            List<ParticleEmitterInfo> particleEmitterList = new List<ParticleEmitterInfo>();

            // process spawn list
            for (int i = 0; i < entityLayer.EntityList.Count; i++)
            {
                // create and fill out spawn info
                MapEntityInfo spawnInfo = new MapEntityInfo();
                spawnInfo.ID = entityLayer.EntityList[i].ID;
                spawnInfo.EntityResource = entityLayer.EntityList[i].ResourcePath;
                spawnInfo.SpawnPoint = entityLayer.EntityList[i].WorldPosition;
                spawnInfo.SpawnTile = entityLayer.EntityList[i].TilePosition;

                // add to list
                spawnList.Add(spawnInfo);
            }

            // sort spawn list by resource
            spawnList.Sort(delegate(MapEntityInfo spawn1, MapEntityInfo spawn2)
            {
                return spawn1.EntityResource.CompareTo(spawn2.EntityResource);
            });

            // process particle emitters
            for (int i = 0; i < particleLayer.EmitterList.Count; i++)
            {
                // create and fill out spawn info
                ParticleEmitterInfo particleInfo = new ParticleEmitterInfo();
                particleInfo.EmitterResource = particleLayer.EmitterList[i].ResourcePath;
                particleInfo.SpawnPoint = particleLayer.EmitterList[i].WorldPosition;
                particleInfo.SpawnTile = particleLayer.EmitterList[i].TilePosition;
                particleInfo.IsForeground = false;

                // add to list
                particleEmitterList.Add(particleInfo);
            }

            // sort spawn list by resource
            particleEmitterList.Sort(delegate(ParticleEmitterInfo emitter1, ParticleEmitterInfo emitter2)
            {
                return emitter1.EmitterResource.CompareTo(emitter2.EmitterResource);
            });

            // save data to map
            newMap.AssetType = mapAssetType;
            newMap.ID = mapID;
            newMap.BgColor = mapBgColor;
            newMap.TileSet = tileSet;
            newMap.TilesetXCount = tilesetXCount;
            newMap.TilesetYCount = tilesetYCount;
            newMap.Tile_Size = mapTileSize;
            newMap.Width = mapTileWidth;
            newMap.Height = mapTileHeight;
            newMap.TilesetWidth = tilesImage.Width;
            newMap.TilesetHeight = tilesImage.Height;

            // process lists
            newMap.SpawnList = new List<MapEntityInfo>();
            newMap.SpawnList.AddRange(spawnList);

            newMap.ParticleEmitterList = new List<ParticleEmitterInfo>();
            newMap.ParticleEmitterList.AddRange(particleEmitterList);

            newMap.PortalList = new List<PortalInfo>();
            newMap.PortalList.AddRange(mapPortalInfoList);

            newMap.ShaderRegionList = new List<ShaderRegionInfo>();
            newMap.ShaderRegionList.AddRange(mapShaderRegionInfoList);

            newMap.TerrainList = new List<TerrainInfo>();
            newMap.TerrainList.AddRange(mapTerrainInfoList);

            newMap.EventList = new List<MapEventInfo>();
            newMap.EventList.AddRange(mapEventInfoList);

            newMap.ForegroundLayers.Clear();
            newMap.ForegroundLayers.AddRange(mapForegroundLayers);

            // save light data
            newMap.LightParams = new LightParams(map.LightParams);
            newMap.LightList = new List<PointLight>();

            foreach (MapLight mapLight in lightLayer.LightList)
                newMap.LightList.Add(mapLight.Light);

            AnimatedTileInfo tempAnimatedTileInfo = new AnimatedTileInfo();

            // generate layer lists and get all animated tiles
            for (int i = 0; i < layerCount; i++)
            {
                // add new layer
                newMap.Layers.Add(new List<string>());

                for (int y = 0; y < mapTileHeight; y++)
                {
                    // add new row in the layer
                    newMap.Layers[i].Add(null);

                    for (int x = 0; x < mapTileWidth; x++)
                    {
                        Tile currentTile = map.GetTile(x, y);

                        newMap.Layers[i][y] += currentTile.Layers[i] + ",";

                        // create info objects for each animated tile and add to list
                        for (int j = 0; j < currentTile.AnimatedTiles.Count; j++)
                        {
                            tempAnimatedTileInfo = new AnimatedTileInfo();
                            tempAnimatedTileInfo.ID = currentTile.ID;
                            tempAnimatedTileInfo.Layer = currentTile.AnimatedTiles[j].Layer;
                            tempAnimatedTileInfo.SpawnPoint = currentTile.AnimatedTiles[j].WorldPosition;
                            tempAnimatedTileInfo.SpawnTile = currentTile.AnimatedTiles[j].TilePosition;
                            tempAnimatedTileInfo.TileResource = currentTile.AnimatedTiles[j].ResourcePath;

                            animatedTileList.Add(tempAnimatedTileInfo);
                        }
                    }

                    // remove trailing comma
                    newMap.Layers[i][y] = newMap.Layers[i][y].TrimEnd(new Char[] { ',' });
                }
            }

            // sort animated tiles by resource
            animatedTileList.Sort(delegate(AnimatedTileInfo tile1, AnimatedTileInfo tile2)
            {
                return tile1.TileResource.CompareTo(tile2.TileResource);
            });

            // save animated tiles to map
            newMap.AnimatedTileList = animatedTileList;

            string hazardLayerRow;
            string collisionLayerRow;
            string terrainLayerRow;

            // iterate through tiles once more to get collision and hazard data
            for (int y = 0; y < map.Height; y++)
            {
                // clear all temp layers
                collisionLayerRow = null;
                hazardLayerRow = null;
                terrainLayerRow = null;

                for (int x = 0; x < map.Width; x++)
                {
                    Tile currentTile = map.GetTile(x, y);

                    // the third to last layer in the tile layers contains hazard data
                    hazardLayerRow += currentTile.Layers[currentTile.Layers.Count - 3] + ",";

                    // the second to last layer in the tile layers contains collision data
                    collisionLayerRow += currentTile.Layers[currentTile.Layers.Count - 2] + ",";

                    // the last layer in the tile layers contains terrain data
                    terrainLayerRow += currentTile.Layers[currentTile.Layers.Count - 1] + ",";
                }

                // trim trailing commas
                hazardLayerRow = hazardLayerRow.TrimEnd(new Char[] { ',' });
                collisionLayerRow = collisionLayerRow.TrimEnd(new Char[] { ',' });
                terrainLayerRow = terrainLayerRow.TrimEnd(new Char[] { ',' });

                // add the new rows to the map layers
                newMap.HazardLayer.Add(hazardLayerRow);
                newMap.CollisionLayer.Add(collisionLayerRow);
                newMap.TerrainLayer.Add(terrainLayerRow);
            }

            /*
             * Now using intermediate serialzier, leaving this code for educational value
             *
             * // Open the file, creating it if necessary
             * // FileStream stream = File.Open(fileName, FileMode.OpenOrCreate);
             * // Convert the object to XML data and put it in the stream
             * // XmlSerializer serializer = new XmlSerializer(typeof(Map));
             * // serializer.Serialize(stream, map);
             * // Close the file
             * // stream.Close();
             *
             */

            XmlWriterSettings xmlSettings = new XmlWriterSettings();

            xmlSettings.Indent = true;

            using (XmlWriter xmlWriter = XmlWriter.Create(fileName, xmlSettings))
            {
                IntermediateSerializer.Serialize(xmlWriter, newMap, null);
            }

            // correct asset type
            //XmlAssetCorrector.CorrectOutputAssetType(fileName, defaultMapAssetType, mapAssetType);

            // update cached copy
            //contentManager.UpdateCache<Map>(fileName, newMap);

            // set textures
            newMap.SetColorTexture(map.TilesetTextures.ColorMap);
            newMap.SetNormalTexture(map.TilesetTextures.NormalMap);
            newMap.SetDepthTexture(map.TilesetTextures.DepthMap);

            // set current map to new map
            map = newMap;

            map.Initialize();

            LoadAnimatedTiles();
        }

        /// <summary>
        /// Generate new map
        /// </summary>
        private void GenerateNewMap()
        {
            // load default settings for use with new map
            LoadDefaultSettings();

            map = new Map();

            // temporary rows used to create empty layers
            string tempRow;

            for (int i = 0; i < minLayerCount; i++)
            {
                // add a new layer
                map.Layers.Add(new List<string>());

                for (int y = 0; y < mapTileHeight; y++)
                {
                    // add a new layer row
                    map.Layers[i].Add(null);

                    for (int x = 0; x < mapTileWidth; x++)
                    {
                        map.Layers[i][y] += "-1,";
                    }

                    // trim trailing comma
                    map.Layers[i][y] = map.Layers[i][y].TrimEnd(new Char[] { ',' });
                }
            }

            // process hazard layer
            for (int y = 0; y < mapTileHeight; y++)
            {
                tempRow = null;

                for (int x = 0; x < mapTileWidth; x++)
                {
                    tempRow += "-1,";
                }

                tempRow = tempRow.TrimEnd(new Char[] { ',' });

                // fill all layers with "null" data
                map.HazardLayer.Add(tempRow);
            }

            // process terrain layer
            for (int y = 0; y < mapTileHeight; y++)
            {
                tempRow = null;

                for (int x = 0; x < mapTileWidth; x++)
                {
                    tempRow += "-1,";
                }

                tempRow = tempRow.TrimEnd(new Char[] { ',' });

                // fill all layers with "null" data
                map.TerrainLayer.Add(tempRow);
            }

            // things are a bit different for the collision map, default is passable so we will write that instead of -1
            for (int y = 0; y < mapTileHeight; y++)
            {
                tempRow = null;

                for (int x = 0; x < mapTileWidth; x++)
                {
                    tempRow += (int)TileCollision.Passable + ",";
                }

                tempRow = tempRow.TrimEnd(new Char[] { ',' });

                map.CollisionLayer.Add(tempRow);
            }

            /*
            // create new lists for the map
            map.AnimatedTileList = new List<AnimatedTileInfo>();
            map.SpawnList = new List<MapEntityInfo>();
            map.ParticleEmitterList = new List<ParticleEmitterInfo>();
            map.PortalList = new List<PortalInfo>();
            map.ShaderRegionList = new List<ShaderRegionInfo>();
            map.TerrainList = new List<TerrainInfo>();
            map.EventList = new List<MapEventInfo>();
            */

            // create new lists for the editor
            mapPortalInfoList = new List<PortalInfo>();
            mapShaderRegionInfoList = new List<ShaderRegionInfo>();
            mapTerrainInfoList = new List<TerrainInfo>();
            mapEventInfoList = new List<MapEventInfo>();

            // set tile data and bg color
            map.BgColor = mapBgColor;
            map.Tile_Size = mapTileSize;
            map.Width = mapTileWidth;
            map.Height = mapTileHeight;

            /*
            map.LightParams = new LightParams();
            map.LightList = new List<PointLight>();
            */

            // clear all light data and reset
            lightLayer.ClearLights();

            layerCount = minLayerCount;

            // set default foreground data
            mapForegroundLayers.Clear();
            mapForegroundLayers.AddRange(defaultForegroundData);
            map.ForegroundLayers.Clear();
            map.ForegroundLayers.AddRange(defaultForegroundData);

            // clear spawn layer
            entityLayer.Clear();

            // clear particle layer
            particleLayer.Clear();

            // clear tiles image
            tileSelectionBox.Image = null;

            MapSelections.UpdateAll();
            UpdateLayers();
        }

        /// <summary>
        /// Resize the map
        /// </summary>
        /// <param name="width">New map width</param>
        /// <param name="height">New map height</param>
        public void ResizeMap(int width, int height)
        {
            // create a new map object
            Map newMap = new Map();

            // temporary rows used to create empty layers
            string tempRow;
            string tempColRow;

            Tile currentTile;

            int oldWidth = mapTileWidth;
            int oldHeight = mapTileHeight;

            #region Tile Layers
            // process tile layers
            for (int i = 0; i < layerCount; i++)
            {
                // add new layer
                newMap.Layers.Add(new List<string>());

                for (int y = 0; y < height; y++)
                {
                    // add null row
                    newMap.Layers[i].Add(null);

                    tempRow = null;

                    // modify rows if they already existed in old map
                    if (y < oldHeight)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            // if the tile exists already, copy its data to the layers
                            if (x < oldWidth)
                            {
                                currentTile = map.GetTile(x, y);
                                newMap.Layers[i][y] += currentTile.Layers[i] + ",";
                            }
                            else // if the tile doesnt exist, add null data
                            {
                                newMap.Layers[i][y] += "-1,";
                            }
                        }

                        // trim trailing commas
                        newMap.Layers[i][y] = newMap.Layers[i][y].TrimEnd(new Char[] { ',' });
                    }

                    // if these are new rows use "null" data
                    if ((height > oldHeight) && (y >= oldHeight))
                    {
                        // create temp data for new rows
                        for (int x = 0; x < width; x++)
                        {
                            tempRow += "-1,";
                        }

                        // trim trailing commas
                        tempRow = tempRow.TrimEnd(new Char[] { ',' });

                        // replace null rows with data
                        newMap.Layers[i][y] = tempRow;
                    }
                }
            }
            #endregion

            #region Collision, Hazard, and Terrain Layers
            for (int y = 0; y < height; y++)
            {
                tempRow = null;
                tempColRow = null;

                // add rows
                newMap.HazardLayer.Add(tempRow);
                newMap.CollisionLayer.Add(tempColRow);
                newMap.TerrainLayer.Add(tempRow);

                // modify rows if they already existed in old map
                if (y < oldHeight)
                {
                    for (int x = 0; x < width; x++)
                    {
                        // if the tile exists already, copy its data to the layers
                        if (x < oldWidth)
                        {
                            currentTile = map.GetTile(x, y);
                            newMap.HazardLayer[y] += currentTile.Layers[currentTile.Layers.Count - 3] + ",";
                            newMap.CollisionLayer[y] += currentTile.Layers[currentTile.Layers.Count - 2] + ",";
                            newMap.TerrainLayer[y] += currentTile.Layers[currentTile.Layers.Count - 1] + ",";
                        }
                        else // if the tile doesn't exist, add null data
                        {
                            newMap.HazardLayer[y] += "-1,";
                            newMap.CollisionLayer[y] += (int)TileCollision.Passable + ",";
                            newMap.TerrainLayer[y] += "-1,";
                        }
                    }

                    // trim trailing commas
                    newMap.HazardLayer[y] = newMap.HazardLayer[y].TrimEnd(new Char[] { ',' });
                    newMap.CollisionLayer[y] = newMap.CollisionLayer[y].TrimEnd(new Char[] { ',' });
                    newMap.TerrainLayer[y] = newMap.TerrainLayer[y].TrimEnd(new Char[] { ',' });
                }

                // if these are new rows use "null" data
                if ((height > oldHeight) && (y >= oldHeight))
                {
                    // create temp data for new rows
                    for (int x = 0; x < width; x++)
                    {
                        tempRow += "-1,";
                        tempColRow += (int)TileCollision.Passable + ",";
                    }

                    // trim trailing commas
                    tempRow = tempRow.TrimEnd(new Char[] { ',' });
                    tempColRow = tempColRow.TrimEnd(new Char[] { ',' });

                    // replace null rows with data
                    newMap.HazardLayer[y] = tempRow;
                    newMap.CollisionLayer[y] = tempColRow;
                    newMap.TerrainLayer[y] = tempRow;
                }
            }
            #endregion

            // copy remaining map attributes
            newMap.BgColor = map.BgColor;
            newMap.ForegroundLayers.Clear();
            newMap.ForegroundLayers.AddRange(map.ForegroundLayers);
            newMap.LightParams = new LightParams(map.LightParams);

            newMap.TerrainList = new List<TerrainInfo>();
            newMap.TerrainList.AddRange(map.TerrainList);

            newMap.Tile_Size = map.Tile_Size;
            newMap.TilesetHeight = map.TilesetHeight;
            newMap.TilesetWidth = map.TilesetWidth;

            newMap.SetColorTexture(map.TilesetTextures.ColorMap);
            newMap.SetNormalTexture(map.TilesetTextures.NormalMap);
            newMap.SetDepthTexture(map.TilesetTextures.DepthMap);

            // set new width and height attributes
            newMap.Width = width;
            newMap.Height = height;

            // make sure editor matches
            mapTileWidth = newMap.Width;
            mapTileHeight = newMap.Height;
            mapTileSize = newMap.Tile_Size;

            #region Entities
            // remove any entities that are no longer within map bounds

            // get viewport rect
            Microsoft.Xna.Framework.Rectangle viewportRect;
            viewportRect.X = 0;
            viewportRect.Y = 0;
            viewportRect.Width = mapTileSize * mapTileWidth;
            viewportRect.Height = mapTileSize * mapTileHeight;

            // create a new list of entities
            List<MapEntity> entitiesInBounds = new List<MapEntity>();

            for (int i = 0; i < entityLayer.EntityList.Count; i++)
            {
                // if the entity intersects our viewport, add it to our new list of entities
                if (entityLayer.EntityList[i].BoundingRectangle.Intersects(viewportRect))
                    entitiesInBounds.Add(entityLayer.EntityList[i]);
            }

            // replace the old entity list with the new one
            entityLayer.Replace(entitiesInBounds);

            newMap.SpawnList.Clear();
            newMap.SpawnList.AddRange(map.SpawnList);
            #endregion

            #region Portals
            // create a new list of portals
            List<PortalInfo> portalsInBounds = new List<PortalInfo>();

            for (int i = 0; i < mapPortalInfoList.Count; i++)
            {
                PortalInfo pInfo = mapPortalInfoList[i];

                // if the portal is not contained in our viewport
                // reset its bounding box
                if (!viewportRect.Contains(pInfo.boundingBox))
                    pInfo.boundingBox = Microsoft.Xna.Framework.Rectangle.Empty;

                portalsInBounds.Add(pInfo);
            }

            mapPortalInfoList.Clear();
            mapPortalInfoList.AddRange(portalsInBounds);

            newMap.PortalList.Clear();
            newMap.PortalList.AddRange(portalsInBounds);
            #endregion

            #region Lights
            newMap.LightList.Clear();
            newMap.LightList.AddRange(map.LightList);
            #endregion

            #region Animated Tiles
            // create a new list of lights
            List<AnimatedTileInfo> animTilesInBounds = new List<AnimatedTileInfo>();

            Microsoft.Xna.Framework.Rectangle mapDimensions =
                    new Microsoft.Xna.Framework.Rectangle(0,0,width,height);

            for (int i = 0; i < map.AnimatedTileList.Count; i++)
            {
                AnimatedTileInfo aTile = map.AnimatedTileList[i];

                // check to make sure the tile position of our animated tile
                // falls within the tile based map dimensions

                Microsoft.Xna.Framework.Point tPos =
                    new Microsoft.Xna.Framework.Point(
                        (int)aTile.SpawnTile.X, (int)aTile.SpawnTile.X);

                if (mapDimensions.Contains(tPos))
                    animTilesInBounds.Add(aTile);
            }

            newMap.AnimatedTileList = new List<AnimatedTileInfo>();
            newMap.AnimatedTileList.AddRange(animTilesInBounds);
            #endregion

            #region Particle Emitters
            // create a new list of lights
            List<ParticleEmitter> emittersInBounds = new List<ParticleEmitter>();

            for (int i = 0; i < particleLayer.EmitterList.Count; i++)
            {
                ParticleEmitter pEmitter = particleLayer.EmitterList[i];

                // if the viewport contains our emitter, add it to our list
                // of acceptable emitters
                Microsoft.Xna.Framework.Point lPos =
                    new Microsoft.Xna.Framework.Point(
                        (int)pEmitter.WorldPosition.X, (int)pEmitter.WorldPosition.Y);

                if (viewportRect.Contains(lPos))
                    emittersInBounds.Add(pEmitter);
            }

            particleLayer.Replace(emittersInBounds);

            newMap.ParticleEmitterList.Clear();
            newMap.ParticleEmitterList.AddRange(map.ParticleEmitterList);
            #endregion

            #region Shader Regions
            // create a new list of portals
            List<ShaderRegionInfo> shadersInBounds = new List<ShaderRegionInfo>();

            for (int i = 0; i < mapShaderRegionInfoList.Count; i++)
            {
                ShaderRegionInfo sInfo = mapShaderRegionInfoList[i];

                // if the portal is not contained in our viewport
                // reset its bounding box
                if (!viewportRect.Contains(sInfo.boundingBox))
                    sInfo.boundingBox = Microsoft.Xna.Framework.Rectangle.Empty;

                shadersInBounds.Add(sInfo);
            }

            mapShaderRegionInfoList.Clear();
            mapShaderRegionInfoList.AddRange(shadersInBounds);

            newMap.ShaderRegionList.Clear();
            newMap.ShaderRegionList.AddRange(shadersInBounds);
            #endregion

            #region Event Regions
            // create a new list of portals
            List<MapEventInfo> eventsInBounds = new List<MapEventInfo>();

            for (int i = 0; i < mapEventInfoList.Count; i++)
            {
                MapEventInfo eInfo = mapEventInfoList[i];

                // if the portal is not contained in our viewport
                // reset its bounding box
                if (!viewportRect.Contains(eInfo.boundingBox))
                    eInfo.boundingBox = Microsoft.Xna.Framework.Rectangle.Empty;

                eventsInBounds.Add(eInfo);
            }

            mapEventInfoList.Clear();
            mapEventInfoList.AddRange(eventsInBounds);

            newMap.EventList.Clear();
            newMap.EventList.AddRange(eventsInBounds);
            #endregion

            // initialize new map
            newMap.Initialize();

            // copy new map to our map object
            map = newMap;
        }
        #endregion

        #region Menu Methods
        /// <summary>
        /// Generate a new map
        /// </summary>
        private void newMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenerateNewMap();
        }

        /// <summary>
        /// Load a XML map
        /// </summary>
        private void loadXMLMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();

            // Default to the directory which contains our content files.
            string assemblyLocation = Assembly.GetExecutingAssembly().Location;
            string relativePath = Path.Combine(assemblyLocation, "../Maps");
            string contentPath = Path.GetFullPath(relativePath);

            // setup dial dialog
            fileDialog.InitialDirectory = contentPath;

            fileDialog.Title = "Load XML Map";

            fileDialog.Filter = "XML (*.xml)|*.xml|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                LoadMap(fileDialog.FileName);

                // if there is a predefined tileset...
                if (map.TileSet != null)
                {
                    string tileSetFile = FileHelper.GetAssemblyDirectory() + "/" + map.TileSet + ".png";

                    // if the file exists, load it
                    if (File.Exists(tileSetFile))
                    {
                        LoadTexture(tileSetFile);
                    }
                    else // if not, select a new one
                    {
                        loadTileTextureToolStripMenuItem_Click(null, null);
                    }
                }

                // once map is initialized, load all animated tiles
                if (map.IsInitialized)
                    LoadAnimatedTiles();
            }
        }

        /// <summary>
        /// Load a tile texture
        /// </summary>
        private void loadTileTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();

            // Default to the directory which contains our content files.
            string assemblyLocation = Assembly.GetExecutingAssembly().Location;
            string relativePath = Path.Combine(assemblyLocation, "../Tiles");
            string contentPath = Path.GetFullPath(relativePath);

            // setup file dialog
            fileDialog.InitialDirectory = contentPath;

            fileDialog.Title = "Load Tile Set";

            fileDialog.Filter = "PNG (*.png)|*.png|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                LoadTexture(fileDialog.FileName);
            }
        }

        /// <summary>
        /// Save Map
        /// </summary>
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog fileDialog = new SaveFileDialog();

            // Default to the directory which contains our content files.
            string assemblyLocation = Assembly.GetExecutingAssembly().Location;
            string relativePath = Path.Combine(assemblyLocation, "../Maps");
            string contentPath = Path.GetFullPath(relativePath);

            // setup file dialog
            fileDialog.InitialDirectory = contentPath;

            fileDialog.Title = "Export Map";

            fileDialog.Filter = "XML (*.xml)|*.xml|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                ExportMap(fileDialog.FileName);
            }
        }

        /// <summary>
        /// Exit program
        /// </summary>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Show manage layers form
        /// </summary>
        private void manageLayersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageLayersForm manageLayersForm = ManageLayersForm.CreateInstance(this);
            if (manageLayersForm != null)
            {
                manageLayersForm.Show();
                manageLayersForm.TopMost = true;
                manageLayersForm.Activate();
            }
        }

        /// <summary>
        /// Show manage animated tiles form
        /// </summary>
        private void manageAnimatedTilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageAnimatedTilesForm manageAnimatedTilesForm = ManageAnimatedTilesForm.CreateInstance(this);
            if (manageAnimatedTilesForm != null)
            {
                {
                    manageAnimatedTilesForm.Show();
                    manageAnimatedTilesForm.TopMost = true;
                    manageAnimatedTilesForm.Activate();
                }
            }
        }

        /// <summary>
        /// Show manage portals form
        /// </summary>
        private void managePortalsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManagePortalsForm managePortalsForm = ManagePortalsForm.CreateInstance(this);
            if (managePortalsForm != null)
            {
                managePortalsForm.Show();
                managePortalsForm.TopMost = true;
                managePortalsForm.Activate();
            }
        }

        /// <summary>
        /// Show configure map settings form
        /// </summary>
        private void configureMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MapSettingsForm mapSettingsForm = MapSettingsForm.CreateInstance(this);
            if (mapSettingsForm != null)
            {
                mapSettingsForm.SaveDefaultSettings += delegate { SaveDefaultSettings(); };
                mapSettingsForm.ShowDialog();
                mapSettingsForm.TopMost = true;
                mapSettingsForm.Activate();
            }
        }

        /// <summary>
        /// Show manage shader effects form
        /// </summary>
        private void manageShadersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageShadersForm manageShadersForm = ManageShadersForm.CreateInstance(this);
            if (manageShadersForm != null)
            {
                manageShadersForm.Show();
                manageShadersForm.TopMost = true;
                manageShadersForm.Activate();
            }
        }

        /// <summary>
        /// Show manage entities form
        /// </summary>
        private void manageEntitiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageEntitiesForm manageEntitiesForm = ManageEntitiesForm.CreateInstance(this);
            if (manageEntitiesForm != null)
            {
                manageEntitiesForm.Show();
                manageEntitiesForm.TopMost = true;
                manageEntitiesForm.Activate();
            }
        }

        /// <summary>
        /// Show manage particle emitters form
        /// </summary>
        private void manageParticleEmittersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageParticlesForm manageParticlesForm = ManageParticlesForm.CreateInstance(this);
            if (manageParticlesForm != null)
            {
                manageParticlesForm.Show();
                manageParticlesForm.TopMost = true;
                manageParticlesForm.Activate();
            }
        }

        /// <summary>
        /// Show manage terrain types form
        /// </summary>
        private void manageTerrainTypesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageTerrainForm manageTerrainForm = ManageTerrainForm.CreateInstance(this);
            if (manageTerrainForm != null)
            {
                manageTerrainForm.Show();
                manageTerrainForm.TopMost = true;
                manageTerrainForm.Activate();
            }
        }

        /// <summary>
        /// Show map selections form
        /// </summary>
        private void showMapSelectionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MapSelectionsForm mapSelectionsForm = MapSelectionsForm.CreateInstance(this);
            if (mapSelectionsForm != null)
            {
                mapSelectionsForm.Show();
                mapSelectionsForm.TopMost = true;
                mapSelectionsForm.Activate();
            }
        }

        /// <summary>
        /// Show map event form
        /// </summary>
        private void manageEventsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageEventsForm manageEventsForm = ManageEventsForm.CreateInstance(this);
            if (manageEventsForm != null)
            {
                manageEventsForm.Show();
                manageEventsForm.TopMost = true;
                manageEventsForm.Activate();
            }
        }

        /// <summary>
        /// Show manage world lighting form
        /// </summary>
        private void manageWorldLightingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageWorldLightForm manageWorldLightForm = ManageWorldLightForm.CreateInstance(this, map.LightParams);
            if (manageWorldLightForm != null)
            {
                manageWorldLightForm.Show();
                manageWorldLightForm.TopMost = true;
                manageWorldLightForm.Activate();
            }
        }

        /// <summary>
        /// Show manage lights form
        /// </summary>
        private void manageLightsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ManageLightsForm manageLightsForm = ManageLightsForm.CreateInstance(this, lightLayer);
            if (manageLightsForm != null)
            {
                manageLightsForm.Show();
                manageLightsForm.TopMost = true;
                manageLightsForm.Activate();
            }
        }

        #endregion

        #region Misc Helper Methods
        /// <summary>
        /// Loads available plugins using reflection
        /// </summary>
        private void LoadPlugins()
        {
            // search plugin directory for dlls
            string[] files = Directory.GetFiles("Plugins", "*.dll");

            // check each file in plugin direction
            foreach (string file in files)
            {
                try
                {
                    // load the assembly and get types
                    Assembly assembly = Assembly.LoadFrom(file);
                    System.Type[] types = assembly.GetTypes();

                    // look for our interface in the assembly
                    foreach (System.Type type in types)
                    {
                        // if we found our interface, verify attributes
                        if (type.GetInterface("IParadigmPlugin") != null)
                        {

                            if (type.GetCustomAttributes(typeof(ParadigmPluginDisplayNameAttribute), false).Length != 1)
                                throw new PluginNotValidException(type, "Plugin display name is not supported!");

                            if (type.GetCustomAttributes(typeof(ParadigmPluginDescriptionAttribute), false).Length != 1)
                                throw new PluginNotValidException(type, "Plugin description is not supported");

                            string name = type.GetCustomAttributes(typeof(ParadigmPluginDisplayNameAttribute), false)[0].ToString();
                            string description = type.GetCustomAttributes(typeof(ParadigmPluginDescriptionAttribute), false)[0].ToString();

                            // create the plugin using reflection
                            Object o = Activator.CreateInstance(type);

                            ParadigmPlugin plugin = new ParadigmPlugin(o as IParadigmPlugin, name, description);

                            pluginAssemblies.Add(Path.GetFullPath(FileHelper.GetAssemblyDirectory() + "\\" + file));
                            loadedPlugins.Add(plugin);
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message, "Plugin Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            // iterate through list and add them to our form control
            for (int i = 0; i < loadedPlugins.Count; i++)
            {
                ParadigmPlugin plugin = loadedPlugins[i];

                pluginsToolStripMenuItem.DropDownItems.Add(plugin.Name);
                pluginsToolStripMenuItem.DropDownItems[i].Click += delegate { plugin.Activate(contentManager); };
                pluginsToolStripMenuItem.DropDownItems[i].Text = plugin.Name;
                pluginsToolStripMenuItem.DropDownItems[i].ToolTipText = plugin.Description;

            }
        }

        /// <summary>
        /// Update layers box with the current amount of layers
        /// </summary>
        public void UpdateLayers()
        {
            currentLayerBox.Items.Clear();

            for (int i = 0; i < layerCount; i++)
            {
                currentLayerBox.Items.Add(Convert.ToString(i));

                if (mapForegroundLayers[i] == true)
                    currentLayerBox.Items[i] = currentLayerBox.Items[i] + " [Fore]";
            }

            map.ForegroundLayers.Clear();
            map.ForegroundLayers.AddRange(mapForegroundLayers);

            currentLayerBox.SelectedIndex = 0;
            currentLayer = 0;
        }

        /// <summary>
        /// Returns a matrix to be used with SpriteBatch.Begin
        /// </summary>
        public Matrix CreateDisplayTranslation()
        {
            // variables needed for upcoming matrix translations and decompose
            Vector3 scale, translation;
            Quaternion rotation;
            float X, Y;

            // create translation matrix initially based upon player being centered
            Matrix transformMatrix = Matrix.CreateTranslation((float)(-hScrollBar1.Value + xnaDisplay.Width / 2),
                                                              (float)(-vScrollBar1.Value + xnaDisplay.Height / 2), 1);

            transformMatrix.Decompose(out scale, out rotation, out translation);

            X = translation.X;
            Y = translation.Y;

            /* Unlock boundaries

            // check left boundary
            if (X > 0)
                X = 0;

            // check right boundary
            if (mapPixelWidth >= tileDisplay1.Width)
                if (mapPixelWidth + X + (map.Tile_Size / 2) < tileDisplay1.Width)
                    X = (float)(-(mapPixelWidth - tileDisplay1.Width + (mapTileSize / 2)));

            // check top boundary
            if (Y > 0)
                Y = 0;

            // check bottom boundary
            if (mapPixelHeight >= tileDisplay1.Height)
                if (mapPixelHeight + Y + (map.Tile_Size / 2) < tileDisplay1.Height)
                    Y = (float)(-(mapPixelHeight - tileDisplay1.Height + (mapTileSize /2)));
            */

            transformMatrix = Matrix.CreateTranslation(new Vector3(X, Y, 1));

            return transformMatrix;
        }

        /// <summary>
        /// Retrieve a vector indicating the current camera offset
        /// </summary>
        /// <returns></returns>
        public Vector2 TranslationVector()
        {
            Vector3 scale, translation;
            Quaternion rotation;

            Matrix translationMatrix = CreateDisplayTranslation();
            translationMatrix.Decompose(out scale, out rotation, out translation);

            Vector2 translationVector2D = new Vector2(translation.X, translation.Y);

            return translationVector2D;
        }

        /// <summary>
        /// Calculate Map Zoom
        /// </summary>
        private void CalculateZoom()
        {
            // get the current scroll wheel value
            int currentWheelValue = Mouse.GetState().ScrollWheelValue;

            // get the amount of "notches" turned
            int zoomNotches = (currentWheelValue - prevWheelValue) / 120;

            // update the map scale by a percentage
            mapScale += (float)(zoomNotches * .25f);

            // clamp scale to 1 decimal
            mapScale = (float)Math.Round((double)mapScale, 2);

            // clamp the zoom
            mapScale = MathHelper.Clamp(mapScale, 0.25f, 1f);

            // update old wheel value
            prevWheelValue = currentWheelValue;
        }

        /// <summary>
        /// Return a vector containing the x,y coords of the mouse in terms of tiles
        /// </summary>
        private Vector2 FormMouseTileLocation()
        {
            int mx = Mouse.GetState().X;
            int my = Mouse.GetState().Y;

            Vector2 mouseTileLocation = new Vector2((float)(mx / mapTileSize), (float)(my / mapTileSize));

            return mouseTileLocation;
        }

        /// <summary>
        /// Return a vector containing the x,y coords of the mouse in terms of tiles
        /// </summary>
        private Vector2 XnaMouseTileLocation(MouseState mouseState)
        {

            // clamp mouse to confines of display
            int mx = (int)MathHelper.Clamp(mouseState.X, 0, (float)xnaDisplay.Width);
            int my = (int)MathHelper.Clamp(mouseState.Y, 0, (float)xnaDisplay.Height);

            mx += (int)(-TranslationVector().X * mapScale);
            my += (int)(-TranslationVector().Y * mapScale);

            int mouseTileX = (int)(mx / (mapTileSize * mapScale));
            int mouseTileY = (int)(my / (mapTileSize * mapScale));

            Vector2 mouseTileLocation = new Vector2((float)mouseTileX, (float)mouseTileY);
            return mouseTileLocation;
        }

        /// <summary>
        /// Update the spawn layer
        /// </summary>
        public void UpdateSpawnLayer(MapEntityDesc entityDesc)
        {
            entityLayer.Update(entityDesc);
        }

        /// <summary>
        /// Update the particle layer
        /// </summary>
        /// <param name="particleDesc"></param>
        public void UpdateParticleLayer(MapParticleDesc particleDesc)
        {
            particleLayer.Update(particleDesc);
        }
        #endregion

        #region Tiles Selector
        /// <summary>
        /// Paint method for tile selector box.
        /// </summary>
        private void tileSelectionBox_Paint(object sender, PaintEventArgs e)
        {
            DrawGrid(e.Graphics);
            DrawSelection(e.Graphics);
        }

        /// <summary>
        /// On mouse enter, set mouse handle to tile selector handle
        /// </summary>
        private void tileSelectionBox_MouseEnter(object sender, EventArgs e)
        {
            Mouse.WindowHandle = tileSelectionBox.Handle;
        }

        /// <summary>
        /// On mouse leave, set mouse handle to XNA window handle
        /// </summary>
        private void tileSelectionBox_MouseLeave(object sender, EventArgs e)
        {
            // For now we aren't doing this as the tildDisplay is taking input
            // when it shouldn't have focus.

            //Mouse.WindowHandle = tileDisplay1.Handle;
        }

        /// <summary>
        /// On mouse down within tile selector
        /// </summary>
        private void tileSelectionBox_MouseDown(object sender, MouseEventArgs e)
        {
            int mx = Mouse.GetState().X;
            int my = Mouse.GetState().Y;

            Vector2 mouseTileLocation = FormMouseTileLocation();

            selectedStartTile = mouseTileLocation;
            prevMouseState = Mouse.GetState();
        }

        /// <summary>
        /// On mouse up within tile selector
        /// </summary>
        private void tileSelectionBox_MouseUp(object sender, MouseEventArgs e)
        {
            if (prevMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
            {
                int mx = Mouse.GetState().X;
                int my = Mouse.GetState().Y;

                Vector2 mouseTileLocation = FormMouseTileLocation();

                selectedEndTile = mouseTileLocation;

                if (selectedStartTile == selectedEndTile)
                {
                    selectedMultipleTiles = false;

                    // set selected tile
                    selectedTile.Position = mouseTileLocation;
                    selectedTile.SourceRect = new Microsoft.Xna.Framework.Rectangle(
                        (int)mouseTileLocation.X * mapTileSize,
                        (int)mouseTileLocation.Y * mapTileSize,
                        mapTileSize,
                        mapTileSize
                        );
                    selectedTile.ID = (int)((mouseTileLocation.Y * tilesetXCount) + mouseTileLocation.X);
                }
                else
                {
                    int xRange = (int)(selectedEndTile.X - selectedStartTile.X);
                    int yRange = (int)(selectedEndTile.Y - selectedStartTile.Y);

                    selectedTileRange = new Vector2(xRange, yRange);
                    selectedMultipleTiles = true;

                    // set selected tile
                    selectedTile.Position = selectedStartTile;
                    selectedTile.SourceRect = new Microsoft.Xna.Framework.Rectangle(
                        (int)selectedStartTile.X * mapTileSize,
                        (int)selectedStartTile.Y * mapTileSize,
                        (xRange * mapTileSize) + mapTileSize,
                        (yRange * mapTileSize) + mapTileSize
                        );
                    selectedTile.ID = (int)((mouseTileLocation.Y * tilesetXCount) + mouseTileLocation.X);
                }
            }
            prevMouseState = Mouse.GetState();
        }

        /// <summary>
        /// Draw box around selected tile(s)
        /// </summary>
        /// <param name="g"></param>
        private void DrawSelection(Graphics g)
        {
            Graphics graphics = g;

            if ((tileSelectionBox.Image != null))
            {
                // as we cannot convert from an XNA rect to a GDI rect, use the
                // values directly

                graphics.DrawRectangle(selectedPen,
                    selectedTile.SourceRect.X,
                    selectedTile.SourceRect.Y,
                    selectedTile.SourceRect.Width,
                    selectedTile.SourceRect.Height);
            }
        }

        /// <summary>
        /// Draw a grid over the tile texture
        /// </summary>
        private void DrawGrid(Graphics g)
        {
            if (tileSelectionBox.Image != null)
            {
                Graphics graphics = g;

                for (int y = 0; y < tileSelectionBox.Image.Height / mapTileSize; y++)
                {
                    for (int x = 0; x < tileSelectionBox.Image.Width / mapTileSize; x++)
                    {
                        graphics.DrawLine(gridPen, x * mapTileSize, 0, x * mapTileSize, tileSelectionBox.Image.Height);
                    }
                    graphics.DrawLine(gridPen, 0, y * mapTileSize, tileSelectionBox.Image.Width, y * mapTileSize);
                }
            }
        }
        #endregion
    }
}