#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
}
}