/// <summary>
        ///     Initializes a new instance of this control.
        /// </summary>
        /// <param name="file">Tileset file to display.</param>
        public TilesetWindow(string file)
        {
            InitializeComponent();

            _canvas = new GraphicsCanvas(canvasPanel, 0, Render);
            _tileset = new Tileset(file);

            TilesetWindow_ResizeEnd(null, new EventArgs());

            EventManager.AttachListener(_listener = new EventListener(EventCaptured));
        }
        /// <summary>
        ///		Loads this map from a given object or file path.
        /// </summary>
        /// <param name="url">Url of file to open map from.	</param>
        /// <param name="password">If a password is required to open this map, this will be used.</param>
        /// <param name="baseNode">The base node that all loading should be started from, this allows you to ignore this node and any nodes higher in the graph like the Root Camera.</param>
        /// <param name="keepPersistent">If set to true persistent ob jects will be kept.</param>
        /// <param name="keepCameras">If set to true all cameras will not be destroyed.</param>
        public void Load(object url, string password, SceneNode baseNode, bool keepPersistent, bool keepCameras)
        {
            // Keep track of the url.
            if (url is string)
                _url = url as string;

            // Try and open a stream to the file.
            Stream stream = StreamFactory.RequestStream(url, StreamMode.Open);
            if (stream == null) return;
            BinaryReader reader = new BinaryReader(stream);

            // Check the header of this file to make sure it really is a Fusion map file.
            if (reader.ReadChar() != 'F' || reader.ReadChar() != 'M' || reader.ReadChar() != 'P')
                throw new Exception("Fusion map file has invalid header, file may be corrupt.");

            // Read in the bit mask explaining the header.
            int headerBitMask = reader.ReadByte();
            if ((headerBitMask & 4) != 0) _mapProperties.Name = reader.ReadString();
            if ((headerBitMask & 8) != 0) _mapProperties.Author = reader.ReadString();
            if ((headerBitMask & 16) != 0) _mapProperties.Description = reader.ReadString();
            if ((headerBitMask & 32) != 0) _mapProperties.Version = reader.ReadSingle();

            // Read in the rest of the file into memory so we can decompress / decrypt it.
            byte[] fileData = reader.ReadBytes((int)(stream.Length - stream.Position));

            // Decrypt the data if required.
            if ((headerBitMask & 2) != 0)
                fileData = DataMethods.Decrypt(fileData, password);

            // Decompress the data if required.
            if ((headerBitMask & 1) != 0)
                fileData = DataMethods.Inflate(fileData);

            // Create a memory stream and a binary reader so we can minipulate the data better.
            MemoryStream memStream = new MemoryStream(fileData, 0, fileData.Length);
            BinaryReader memStreamReader = new BinaryReader(memStream);

            // Read in the encryption header to make sure everything went correctly.
            if ((headerBitMask & 2) != 0 || (headerBitMask & 1) != 0)
                if (memStreamReader.ReadChar() != 'C' || memStreamReader.ReadChar() != 'H' || memStreamReader.ReadChar() != 'K')
                    throw new Exception("Unable to open Fusion map file, password is invalid or fils is corrupted.");

            // Read in the tileset pool used to render tilemap segments.
            int tilesetCount = memStreamReader.ReadByte();
            Tileset.TilesetPool.Clear();
            for (int i = 0; i < tilesetCount; i++)
            {
                if (memStreamReader.ReadBoolean() == true)
                {
                    string newTilesetUrl = memStreamReader.ReadString();

                    if (newTilesetUrl.ToString().ToLower().StartsWith("pak@"))
                        newTilesetUrl = newTilesetUrl.ToString().Substring(4); // Legacy support.

                    if (Runtime.Resources.ResourceManager.ResourceIsCached(newTilesetUrl))
                        Tileset.AddToTilesetPool(Runtime.Resources.ResourceManager.RetrieveResource(newTilesetUrl) as Tileset);
                    else
                    {
                        Runtime.Debug.DebugLogger.WriteLog("Loading tileset from " + newTilesetUrl);
                        Tileset newTileset = new Tileset();
                        newTileset.Load(newTilesetUrl);
                        Tileset.AddToTilesetPool(newTileset);
                        Runtime.Resources.ResourceManager.CacheResource(newTilesetUrl, newTileset);
                    }

                }
            }

            // Tell the scene graph to load itself from this memory stream.
            _sceneGraph.Load(memStreamReader, keepPersistent, keepCameras, baseNode);

            // Free up the memory stream and reader.
            memStream.Close();
            memStream = null;

            // Free up the reader and stream.
            stream.Close();
            stream = null;

            // Reclaim memory used during loading.
            GC.Collect();
        }
 /// <summary>
 ///     Removes a given tileset to the tileset pool.
 /// </summary>
 /// <param name="tileset">Tileset to add.</param>
 public static void RemoveToTilesetPool(Tileset tileset)
 {
     // ArrayList removeList = new ArrayList();
        // foreach (Tileset t in _tilesetPool)
     //    if (t.Url.ToString().ToLower() == tileset.Url.ToString().ToLower())
     //        removeList.Add(t);
     //foreach (Tileset t in removeList)
      //   _tilesetPool.Remove(t);
     _tilesetPool.Remove(tileset);
 }
        /// <summary>
        ///     Adds a given tileset to the tileset pool.
        /// </summary>
        /// <param name="tileset">Tileset to add.</param>
        public static void AddToTilesetPool(Tileset tileset)
        {
            //foreach (Tileset t in _tilesetPool)
            //    if (t.Url.ToString().ToLower() == tileset.Url.ToString().ToLower())
             //       return;

            _tilesetPool.Add(tileset);
        }
        /// <summary>
        ///		Loads this tile node from a given binary reader.
        /// </summary>
        /// <param name="reader">Binary reader to load this tile node from.</param>
        public override void Load(BinaryReader reader)
        {
            // Load all the basic entity details.
            base.Load(reader);

            // Load all the tile node specific details.
            if (reader.ReadBoolean() == true)
            {
                int index = reader.ReadByte();
                _tileset = (Tileset)Tileset.TilesetPool[index % Tileset.TilesetPool.Count]; // Better to actually get a tileset, than get an error :P.
                _image = _tileset.Image;
            }
        }
 /// <summary>
 ///		Initializes a new instance of this class with the given 
 ///		rendering properties.
 /// </summary>
 /// <param name="tileset">Tileset used to render this tile.</param>
 /// <param name="frame">Frame of tilesets image to render this tile as.</param>
 /// <param name="blendMode">Blend mode to use when rendering this tile..</param>
 /// <param name="color">Color to use when rendering this tile.</param>
 public TileNode(Tileset tileset, int frame, BlendMode blendMode, int color)
 {
     _frame = frame;
     _tileset = tileset;
     if (_tileset != null) _image = tileset.Image;
     _blendMode = blendMode;
     _color = color;
     _name = "Tile";
     DeinitializeCollision(); // Tiles do not produce collision.
 }
        /// <summary>
        ///     Gets the currently selected tileset.
        /// </summary>
        /// <returns>Current selected tileset.</returns>
        public Tileset GetSelectedTileset()
        {
            if (_selectedTileset == null || _assetManagerWindow.SelectedTileset.ToLower() != _selectedTileset.Url.ToString().ToLower())
            {
                _selectedTileset = null;
                for (int i = 0; i < Tileset.TilesetPool.Count; i++)
                {
                    if ((Tileset.TilesetPool[i] as Tileset).Url.ToString().ToLower() == _assetManagerWindow.SelectedTileset.ToLower())
                        _selectedTileset = (Tileset.TilesetPool[i] as Tileset);
                }

                if (_selectedTileset == null)
                {
                    _selectedTileset = new Tileset(_assetManagerWindow.SelectedTileset.ToLower());
                    Tileset.AddToTilesetPool(_selectedTileset);
                }
            }
            return _selectedTileset;
        }
        /// <summary>
        ///		Preforms a flood fill operation of the given tilemap.
        /// </summary>
        /// <param name="tilemapNode">Tilemap to flood fill.</param>
        /// <param name="x">X position to start flood filling.</param>
        /// <param name="y">Y position to start flood filling.</param>
        /// <param name="fillTileset">Tileset to overwrite when flood filling.</param>
        /// <param name="fillFrame">Frame to overwrite when flood filling.</param>
        /// <param name="fillTracker">Array to keep track of tiles that have been flooded.</param>
        /// <param name="selectionX">X position of the tile being used to fill this flood fill step with.</param>
        /// <param name="selectionY">Y position of the tile being used to fill this flood fill step with.</param>
        private void FloodFill(TilemapSegmentNode tilemapNode, int x, int y, Tileset fillTileset, int fillFrame, ref bool[,] fillTracker, int selectionX, int selectionY)
        {
            // If the selection has gone beyond the width or height of the selection
            // then wrap it around.
            if (selectionX < _assetManagerWindow.TilesetSelection.X)
                selectionX = _assetManagerWindow.TilesetSelection.X + _assetManagerWindow.TilesetSelection.Width - 1;

            if (selectionX > _assetManagerWindow.TilesetSelection.X + _assetManagerWindow.TilesetSelection.Width - 1)
                selectionX = _assetManagerWindow.TilesetSelection.X;

            if (selectionY < _assetManagerWindow.TilesetSelection.Y)
                selectionY = _assetManagerWindow.TilesetSelection.Y + _assetManagerWindow.TilesetSelection.Height - 1;

            if (selectionY > _assetManagerWindow.TilesetSelection.Y + _assetManagerWindow.TilesetSelection.Height - 1)
                selectionY = _assetManagerWindow.TilesetSelection.Y;

            // Work out the frame of the selection we should be applying to this tile.
            int selectionFrame = GetSelectedTileset().Image.FrameIndexAtPosition(selectionX * GetSelectedTileset().Image.Width, selectionY * GetSelectedTileset().Image.Height);

            // If this tile should be set then set it.
            if (tilemapNode[x, y].Tileset == fillTileset && tilemapNode[x, y].Frame == fillFrame)
            {
                tilemapNode[x, y].Tileset = GetSelectedTileset();
                tilemapNode[x, y].Frame = selectionFrame;
                tilemapNode[x, y].Scale(_flipTilesX == true ? -1 : 1, _flipTilesY == true ? -1 : 1, 1);
                tilemapNode[x, y].Color = _assetManagerWindow.TilesetColor;
            }

            // Make this tile as filled.
            fillTracker[x, y] = true;

            int tilemapNodeWidth = tilemapNode.Width / tilemapNode.TileWidth;
            int tilemapNodeHeight = tilemapNode.Height / tilemapNode.TileHeight;

            // Check the tile to the left of this one, and see if it can be filled.
            if (x - 1 >= 0 && x - 1 < tilemapNodeWidth && fillTracker[x - 1, y] == false && tilemapNode[x - 1, y].Tileset == fillTileset && tilemapNode[x - 1, y].Frame == fillFrame)
                FloodFill(tilemapNode, x - 1, y, fillTileset, fillFrame, ref fillTracker, selectionX - 1, selectionY);

            // Check the tile to the right of this one, and see if it can be filled.
            if (x + 1 >= 0 && x + 1 < tilemapNodeWidth && fillTracker[x + 1, y] == false && tilemapNode[x + 1, y].Tileset == fillTileset && tilemapNode[x + 1, y].Frame == fillFrame)
                FloodFill(tilemapNode, x + 1, y, fillTileset, fillFrame, ref fillTracker, selectionX + 1, selectionY);

            // Check the tile at the top of this one, and see if it can be filled.
            if (y - 1 >= 0 && y - 1 < tilemapNodeHeight && fillTracker[x, y - 1] == false && tilemapNode[x, y - 1].Tileset == fillTileset && tilemapNode[x, y - 1].Frame == fillFrame)
                FloodFill(tilemapNode, x, y - 1, fillTileset, fillFrame, ref fillTracker, selectionX, selectionY - 1);

            // Check the tile at the bottom of this one, and see if it can be filled.
            if (y + 1 >= 0 && y + 1 < tilemapNodeHeight && fillTracker[x, y + 1] == false && tilemapNode[x, y + 1].Tileset == fillTileset && tilemapNode[x, y + 1].Frame == fillFrame)
                FloodFill(tilemapNode, x, y + 1, fillTileset, fillFrame, ref fillTracker, selectionX, selectionY + 1);
        }
 /// <summary>
 ///     Disposes of this tileset window.
 /// </summary>
 /// <param name="sender">Object that caused this event to be triggered.</param>
 /// <param name="e">Arguments explaining why this event occured.</param>
 private void TilesetWindow_FormClosed(object sender, FormClosedEventArgs e)
 {
     EventManager.DetachListener(_listener);
     _listener = null;
     _tileset = null;
     GC.Collect();
 }