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