示例#1
0
        public void CalculateTerrainAutotiles(Loc rectStart, Loc rectSize)
        {
            //does not calculate floor tiles.
            //in all known use cases, there is no need to autotile floor tiles.
            //if a use case is brought up that does, this can be changed.
            HashSet <int> blocktilesets = new HashSet <int>();

            for (int ii = rectStart.X; ii < rectStart.X + rectSize.X; ii++)
            {
                for (int jj = rectStart.Y; jj < rectStart.Y + rectSize.Y; jj++)
                {
                    if (Collision.InBounds(Width, Height, new Loc(ii, jj)))
                    {
                        AutoTile outTile;
                        if (TextureMap.TryGetValue(Tiles[ii][jj].Data.ID, out outTile))
                        {
                            Tiles[ii][jj].Data.TileTex = outTile.Copy();
                        }

                        if (Tiles[ii][jj].Data.TileTex.AutoTileset > -1)
                        {
                            blocktilesets.Add(Tiles[ii][jj].Data.TileTex.AutoTileset);
                        }
                    }
                }
            }
            foreach (int tileset in blocktilesets)
            {
                AutoTileData entry = DataManager.Instance.GetAutoTile(tileset);
                entry.Tiles.AutoTileArea(Rand.FirstSeed, rectStart, rectSize, new Loc(Width, Height),
                                         (int x, int y, int neighborCode) =>
                {
                    Tiles[x][y].Data.TileTex.NeighborCode = neighborCode;
                },
                                         (int x, int y) =>
                {
                    if (!Collision.InBounds(Width, Height, new Loc(x, y)))
                    {
                        return(true);
                    }
                    return(Tiles[x][y].Data.TileTex.AutoTileset == tileset);
                },
                                         (int x, int y) =>
                {
                    if (!Collision.InBounds(Width, Height, new Loc(x, y)))
                    {
                        return(true);
                    }
                    return(Tiles[x][y].Data.TileTex.AutoTileset == tileset || Tiles[x][y].Data.TileTex.Associates.Contains(tileset));
                });
            }
        }
示例#2
0
        public override void Apply(T map)
        {
            AutoTileData entry = DataManager.Instance.GetAutoTile(BlockTileset);

            map.Map.BlankBG       = new AutoTile(entry.Tiles.Generic);
            map.Map.FloorBG       = new AutoTile(GroundTileset, IndependentGround ? -1 : BlockTileset);
            map.Map.TextureMap[1] = new AutoTile(BlockTileset, -1);
            map.Map.TextureMap[2] = new AutoTile(BlockTileset, -1);
            map.Map.TextureMap[3] = new AutoTile(WaterTileset, -1);
            map.Map.TextureMap[4] = new AutoTile(WaterTileset, -1);
            map.Map.TextureMap[5] = new AutoTile(WaterTileset, -1);
            map.Map.Element       = GroundElement;
        }
示例#3
0
        /// <summary>
        /// Transforms the intermediate AutoTile data into an output format that is optimized for
        /// efficient reading and updating operations.
        ///
        /// Requires the total number of output tiles, including generated ones, to be known.
        /// </summary>
        private void TransformAutoTileData(List <TilesetAutoTileInfo> outputData)
        {
            for (int autoTileIndex = 0; autoTileIndex < this.autoTiles.Count; autoTileIndex++)
            {
                AutoTileData data = this.autoTiles[autoTileIndex];

                TilesetAutoTileItem[] tileInfo = new TilesetAutoTileItem[this.outputTileCount];
                data.TileInfo.CopyTo(tileInfo, 0);

                outputData.Add(new TilesetAutoTileInfo(
                                   data.BaseTile,
                                   data.StateToTile,
                                   tileInfo));
            }
        }
示例#4
0
        public void Draw(SpriteBatch spriteBatch, Loc pos)
        {
            List <TileLayer> layers;

            if (AutoTileset > -1)
            {
                AutoTileData entry = DataManager.Instance.GetAutoTile(AutoTileset);
                layers = entry.Tiles.GetLayers(NeighborCode);
            }
            else
            {
                layers = Layers;
            }
            foreach (TileLayer anim in layers)
            {
                anim.Draw(spriteBatch, pos, GraphicsManager.TotalFrameTick);
            }
        }
        public static void ImportAllDtefTiles(string sourceDir, string cachePattern)
        {
            var dirs = Directory.GetDirectories(sourceDir);

            foreach (var dir in dirs)
            {
                var fileName      = Path.GetFileName(dir);
                var outputFnTiles = string.Format(cachePattern, fileName);
                DiagManager.Instance.LoadMsg = "Importing " + fileName;

                // Read XML for layer mapping
                var document = new XmlDocument();
                document.Load(Path.Join(dir, XML_FN));
                var tileSize = int.Parse(document.DocumentElement.GetAttribute("dimensions"));

                // The tile index inside the tile sheet where the first frame of animation for this variation is.
                var variationStarts = new[] { 0, 0, 0 };

                // Outer dict: Layer num; inner dict: frame num; tuple: (file name, frame length)
                var frameSpecs = new[] {
                    new SortedDictionary <int, SortedDictionary <int, Tuple <string, int> > >(),
                    new SortedDictionary <int, SortedDictionary <int, Tuple <string, int> > >(),
                    new SortedDictionary <int, SortedDictionary <int, Tuple <string, int> > >()
                };

                try
                {
                    var tileList = new List <BaseSheet>();
                    foreach (var tileTitle in TileTitles)
                    {
                        for (var vi = 0; vi < VariantTitles.Length; vi++)
                        {
                            variationStarts[vi] = tileList.Count;
                            var variantFn = VariantTitles[vi];
                            var reg       = VariantTitlesFrames[vi];
                            var path      = Path.Join(dir, variantFn);
                            if (!File.Exists(path))
                            {
                                if (variantFn != VAR0_FN)
                                {
                                    throw new KeyNotFoundException($"Base variant missing for {fileName}.");
                                }
                                continue;
                            }

                            // Import main frame
                            var tileset = BaseSheet.Import(path);
                            tileList.Add(tileset);

                            // List additional layers and their frames - We do it this way in two steps to make sure it's sorted
                            foreach (var frameFn in Directory.GetFiles(dir, "*.png"))
                            {
                                if (!reg.IsMatch(frameFn))
                                {
                                    continue;
                                }
                                var match       = reg.Match(frameFn);
                                var layerIdx    = int.Parse(match.Groups[1].ToString());
                                var frameIdx    = int.Parse(match.Groups[2].ToString());
                                var durationIdx = int.Parse(match.Groups[3].ToString());
                                if (!frameSpecs[vi].ContainsKey(layerIdx))
                                {
                                    frameSpecs[vi].Add(layerIdx, new SortedDictionary <int, Tuple <string, int> >());
                                }
                                // GetFiles lists some files twice??
                                if (!frameSpecs[vi][layerIdx].ContainsKey(frameIdx))
                                {
                                    frameSpecs[vi][layerIdx].Add(frameIdx, new Tuple <string, int>(frameFn, durationIdx));
                                }
                            }

                            // Import additional frames
                            foreach (var layerFn in frameSpecs[vi].Values)
                            {
                                foreach (var frameFn in layerFn.Values)
                                {
                                    // Import frame
                                    tileset = BaseSheet.Import(frameFn.Item1);
                                    tileList.Add(tileset);
                                }
                            }
                        }

                        var node  = document.SelectSingleNode("//DungeonTileset/RogueEssence/" + tileTitle);
                        var index = -1;
                        if (node != null)
                        {
                            index = int.Parse(node.InnerText);
                        }

                        var autoTile = new AutoTileData();
                        var entry    = new AutoTileAdjacent();

                        var totalArray = new List <TileLayer> [48][];

                        for (var jj = 0; jj < FieldDtefMapping.Length; jj++)
                        {
                            totalArray[jj] = new List <TileLayer> [3];
                            for (var kk = 0; kk < MAX_VARIANTS; kk++)
                            {
                                totalArray[jj][kk] = new List <TileLayer>();
                            }
                        }

                        for (var jj = 0; jj < FieldDtefMapping.Length; jj++)
                        {
                            for (var kk = 0; kk < MAX_VARIANTS; kk++)
                            {
                                if (FieldDtefMapping[jj] == -1)
                                {
                                    continue; // Skip empty tile
                                }
                                var offIndex = tileTitle switch
                                {
                                    "Secondary" => 1,
                                    "Floor" => 2,
                                    _ => 0
                                };
                                var tileX = 6 * offIndex + jj % 6;
                                var tileY = (int)Math.Floor(jj / 6.0);

                                // Base Layer
                                var baseLayer = new TileLayer {
                                    FrameLength = 999
                                };
                                var idx     = variationStarts[kk];
                                var tileset = tileList[idx];
                                //keep adding more tiles to the anim until end of blank spot is found
                                if (!tileset.IsBlank(tileX * tileSize, tileY * tileSize, tileSize, tileSize))
                                {
                                    baseLayer.Frames.Add(new TileFrame(new Loc(tileX, tileY + idx * 8), fileName));
                                }
                                if (baseLayer.Frames.Count < 1)
                                {
                                    continue;
                                }
                                totalArray[jj][kk].Add(baseLayer);

                                // Additional layers
                                var processedLayerFrames = 1;
                                foreach (var layer in frameSpecs[kk].Values)
                                {
                                    if (layer.Count < 1)
                                    {
                                        continue;
                                    }
                                    var anim = new TileLayer {
                                        FrameLength = layer[0].Item2
                                    };

                                    for (var mm = 0; mm < layer.Count; mm++)
                                    {
                                        idx = variationStarts[kk] + processedLayerFrames;
                                        processedLayerFrames += 1;
                                        if (tileList.Count <= idx)
                                        {
                                            continue;
                                        }
                                        tileset = tileList[idx];
                                        //keep adding more tiles to the anim until end of blank spot is found
                                        if (!tileset.IsBlank(tileX * tileSize, tileY * tileSize, tileSize, tileSize))
                                        {
                                            anim.Frames.Add(new TileFrame(new Loc(tileX, tileY + idx * 8), fileName));
                                        }
                                    }

                                    if (anim.Frames.Count > 0)
                                    {
                                        totalArray[jj][kk].Add(anim);
                                    }
                                }
                            }
                        }

                        if (index == -1)
                        {
                            if (tileTitle == "Secondary")  // Secondary terrain is okay to be missing.
                            {
                                continue;
                            }
                            throw new KeyNotFoundException($"Layer index mapping for layer {tileTitle} for {fileName} missing.");
                        }

                        // Import auto tiles
                        for (var i = 0; i < FieldDtefMapping.Length; i++)
                        {
                            if (FieldDtefMapping[i] == -1)
                            {
                                continue;
                            }
                            List <List <TileLayer> > tileArray = typeof(AutoTileAdjacent)
                                                                 .GetField($"Tilex{FieldDtefMapping[i]:X2}")
                                                                 .GetValue(entry) as List <List <TileLayer> >;
                            ImportTileVariant(tileArray, totalArray[i]);
                        }

                        autoTile.Tiles = entry;

                        autoTile.Name = new LocalText(fileName + tileTitle);

                        DataManager.SaveData(index, DataManager.DataType.AutoTile.ToString(), autoTile);
                        Debug.WriteLine($"{index:D3}: {autoTile.Name}");
                    }
                    ImportHelper.SaveTileSheet(tileList, outputFnTiles, tileSize);
                    foreach (var tex in tileList)
                    {
                        tex.Dispose();
                    }
                }
                catch (Exception ex)
                {
                    DiagManager.Instance.LogError(new Exception("Error importing " + fileName + "\n", ex));
                }
            }
        }
示例#6
0
        /// <summary>
        /// Gathers and processes AutoTile input data into an easily modifyable intermediate format,
        /// while also collecting information on generated tiles and connectivity state mappings.
        /// </summary>
        /// <param name="autoTileConfig"></param>
        private void GatherAutoTileData(IReadOnlyList <TilesetAutoTileInput> autoTileConfig)
        {
            for (int autoTileIndex = 0; autoTileIndex < autoTileConfig.Count; autoTileIndex++)
            {
                TilesetAutoTileInput autoTileInput = autoTileConfig[autoTileIndex];
                AutoTileData         autoTile      = new AutoTileData
                {
                    BaseTile         = MathF.Clamp(autoTileInput.BaseTileIndex, 0, this.inputTileCount - 1),
                    TileInfo         = this.autoTileItemPool.Rent(this.inputTileCount),
                    StateToTile      = new int[(int)TileConnection.All + 1],
                    IsStateAvailable = new bool[(int)TileConnection.All + 1]
                };
                autoTile.TileInfo.Count = this.inputTileCount;

                // Initialize the tile mapping for all potential connection states with the base tile
                for (int conIndex = 0; conIndex < autoTile.StateToTile.Length; conIndex++)
                {
                    autoTile.StateToTile[conIndex] = autoTile.BaseTile;
                }

                // Use the directly applicable tile mapping as-is
                int autoTileSourceTileCount = MathF.Min(autoTileInput.TileInput.Count, this.inputTileCount);
                for (int tileIndex = autoTileSourceTileCount - 1; tileIndex >= 0; tileIndex--)
                {
                    TilesetAutoTileItem tileInput = autoTileInput.TileInput[tileIndex];
                    autoTile.TileInfo[tileIndex] = tileInput;

                    if (tileInput.IsAutoTile)
                    {
                        autoTile.IsStateAvailable[(int)tileInput.Neighbours] = true;
                        autoTile.StateToTile[(int)tileInput.Neighbours]      = tileIndex;
                        autoTile.TileInfo.Data[tileIndex].ConnectsToAutoTile = true;

                        // Apply base tile information to the main tile dataset
                        this.tiles.Data[tileIndex].AutoTileLayer = autoTileIndex + 1;
                    }
                }

                // Attempt to construct missing tiles of the minimum required base set from existing tiles
                // by using their sub-tile quadrants individually. Use a buffer for availability checks, so
                // we don't base generated tiles on previously generated tiles.
                autoTile.IsStateAvailable.CopyTo(this.autoTileStateBuffer, 0);
                for (int i = 0; i < AutoTileFallbackMap.BaseConnectivityTiles.Count; i++)
                {
                    TileConnection connectivity = AutoTileFallbackMap.BaseConnectivityTiles[i];
                    if (this.autoTileStateBuffer[(int)connectivity])
                    {
                        continue;
                    }

                    TileConnection topLeft     = FindGeneratedAutoTileBase(TileQuadrant.TopLeft, connectivity, this.autoTileStateBuffer);
                    TileConnection topRight    = FindGeneratedAutoTileBase(TileQuadrant.TopRight, connectivity, this.autoTileStateBuffer);
                    TileConnection bottomRight = FindGeneratedAutoTileBase(TileQuadrant.BottomRight, connectivity, this.autoTileStateBuffer);
                    TileConnection bottomLeft  = FindGeneratedAutoTileBase(TileQuadrant.BottomLeft, connectivity, this.autoTileStateBuffer);

                    // Skip cases where we can't construct a full tile
                    if (topLeft == TileConnection.None)
                    {
                        continue;
                    }
                    if (topRight == TileConnection.None)
                    {
                        continue;
                    }
                    if (bottomRight == TileConnection.None)
                    {
                        continue;
                    }
                    if (bottomLeft == TileConnection.None)
                    {
                        continue;
                    }

                    int generatedIndex = this.ScheduleGenerateTile(
                        autoTile.BaseTile,
                        autoTile.StateToTile[(int)topLeft],
                        autoTile.StateToTile[(int)topRight],
                        autoTile.StateToTile[(int)bottomRight],
                        autoTile.StateToTile[(int)bottomLeft]);

                    autoTile.IsStateAvailable[(int)connectivity] = true;
                    autoTile.StateToTile[(int)connectivity]      = generatedIndex;
                    autoTile.TileInfo.Count = MathF.Max(autoTile.TileInfo.Count, generatedIndex + 1);
                    autoTile.TileInfo.Data[generatedIndex] = autoTileInput.TileInput[autoTile.BaseTile];
                    autoTile.TileInfo[generatedIndex]      = new TilesetAutoTileItem
                    {
                        IsAutoTile         = true,
                        ConnectsToAutoTile = true,
                        Neighbours         = connectivity
                    };
                }

                // Fill up unavailable state mappings with the closest available match
                for (int stateIndex = 0; stateIndex < autoTile.IsStateAvailable.Length; stateIndex++)
                {
                    if (autoTile.IsStateAvailable[stateIndex])
                    {
                        continue;
                    }

                    IReadOnlyList <TileConnection> fallbacks = AutoTileFallbackMap.GetFallback((TileConnection)stateIndex);
                    for (int i = 0; i < fallbacks.Count; i++)
                    {
                        int fallbackStateIndex = (int)fallbacks[i];
                        if (autoTile.IsStateAvailable[fallbackStateIndex])
                        {
                            autoTile.StateToTile[stateIndex] = autoTile.StateToTile[fallbackStateIndex];
                            break;
                        }
                    }
                }

                // Add the gathered info to our local working data
                this.autoTiles.Add(autoTile);
            }
        }
示例#7
0
        /// <summary>
        /// Reads all tileset folders from the input directory, and creates autotiles from them.
        /// </summary>
        /// <param name="sourceDir"></param>
        /// <param name="cacheDir"></param>
        public static void ImportAllAutoTiles(string sourceDir, string cacheDir)
        {
            //TODO: create a version for one tile import
            int index = 0;

            string[] sizeDirs = Directory.GetDirectories(sourceDir);
            foreach (string sizeDir in sizeDirs)
            {
                int tileSize = GetDirSize(sizeDir);
                if (tileSize == 0)
                {
                    continue;
                }


                string[] dirs = Directory.GetDirectories(sizeDir);
                for (int ii = 0; ii < dirs.Length; ii++)
                {
                    string fileName = Path.GetFileName(dirs[ii]);
                    //string[] info = fileName.Split('.');
                    string outputName = fileName;


                    DiagManager.Instance.LoadMsg = "Importing " + outputName;

                    int TOTAL_TILES = 47;

                    try
                    {
                        int currentTier = 0;
                        foreach (string tileTitle in TILE_TITLES)
                        {
                            AutoTileData     autoTile = new AutoTileData();
                            AutoTileAdjacent entry    = new AutoTileAdjacent();

                            List <TileLayer>[][] totalArray = new List <TileLayer> [48][];

                            for (int jj = 0; jj < TOTAL_TILES; jj++)
                            {
                                totalArray[jj] = new List <TileLayer> [3];
                                for (int kk = 0; kk < 3; kk++)
                                {
                                    totalArray[jj][kk] = new List <TileLayer>();
                                }
                            }

                            int layerIndex = 0;
                            while (true)
                            {
                                string[] layers = Directory.GetFiles(dirs[ii] + "/", tileTitle + "." + String.Format("{0:D2}", layerIndex) + ".*");
                                if (layers.Length == 1)
                                {
                                    string   layerName = Path.GetFileNameWithoutExtension(layers[0]);
                                    string[] layerInfo = layerName.Split('.');

                                    using (BaseSheet tileset = BaseSheet.Import(layers[0]))
                                    {
                                        int frameLength = Convert.ToInt32(layerInfo[2]);
                                        if (frameLength == 0)
                                        {
                                            frameLength = 60;
                                        }
                                        int maxVariants = Convert.ToInt32(layerInfo[3]);


                                        int maxFrames = tileset.Width / tileSize / maxVariants;

                                        for (int jj = 0; jj < TOTAL_TILES; jj++)
                                        {
                                            for (int kk = 0; kk < maxVariants; kk++)
                                            {
                                                //go through each layer
                                                TileLayer anim = new TileLayer();
                                                anim.FrameLength = frameLength;

                                                for (int mm = 0; mm < maxFrames; mm++)
                                                {
                                                    //keep adding more tiles to the anim until end of blank spot is found
                                                    if (!tileset.IsBlank((kk * maxFrames + mm) * tileSize, jj * tileSize, tileSize, tileSize))
                                                    {
                                                        anim.Frames.Add(new TileFrame(new Loc(kk * maxFrames + mm, jj + currentTier * 47), outputName));
                                                    }
                                                }

                                                if (anim.Frames.Count > 0)
                                                {
                                                    totalArray[jj][kk].Add(anim);
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (layers.Length > 1)
                                {
                                    throw new Exception("More files than expected");
                                }
                                else
                                {
                                    break;
                                }
                                layerIndex++;
                                currentTier++;
                            }

                            if (layerIndex > 0)
                            {
                                ImportTileVariant(entry.Tilex00, totalArray[0]);
                                ImportTileVariant(entry.Tilex01, totalArray[1]);
                                ImportTileVariant(entry.Tilex02, totalArray[2]);
                                ImportTileVariant(entry.Tilex03, totalArray[3]);
                                ImportTileVariant(entry.Tilex13, totalArray[4]);
                                ImportTileVariant(entry.Tilex04, totalArray[5]);
                                ImportTileVariant(entry.Tilex05, totalArray[6]);
                                ImportTileVariant(entry.Tilex06, totalArray[7]);
                                ImportTileVariant(entry.Tilex26, totalArray[8]);
                                ImportTileVariant(entry.Tilex07, totalArray[9]);
                                ImportTileVariant(entry.Tilex17, totalArray[10]);
                                ImportTileVariant(entry.Tilex27, totalArray[11]);
                                ImportTileVariant(entry.Tilex37, totalArray[12]);
                                ImportTileVariant(entry.Tilex08, totalArray[13]);
                                ImportTileVariant(entry.Tilex09, totalArray[14]);
                                ImportTileVariant(entry.Tilex89, totalArray[15]);
                                ImportTileVariant(entry.Tilex0A, totalArray[16]);
                                ImportTileVariant(entry.Tilex0B, totalArray[17]);
                                ImportTileVariant(entry.Tilex1B, totalArray[18]);
                                ImportTileVariant(entry.Tilex8B, totalArray[19]);
                                ImportTileVariant(entry.Tilex9B, totalArray[20]);
                                ImportTileVariant(entry.Tilex0C, totalArray[21]);
                                ImportTileVariant(entry.Tilex4C, totalArray[22]);
                                ImportTileVariant(entry.Tilex0D, totalArray[23]);
                                ImportTileVariant(entry.Tilex4D, totalArray[24]);
                                ImportTileVariant(entry.Tilex8D, totalArray[25]);
                                ImportTileVariant(entry.TilexCD, totalArray[26]);
                                ImportTileVariant(entry.Tilex0E, totalArray[27]);
                                ImportTileVariant(entry.Tilex2E, totalArray[28]);
                                ImportTileVariant(entry.Tilex4E, totalArray[29]);
                                ImportTileVariant(entry.Tilex6E, totalArray[30]);
                                ImportTileVariant(entry.Tilex0F, totalArray[31]);
                                ImportTileVariant(entry.Tilex1F, totalArray[32]);
                                ImportTileVariant(entry.Tilex2F, totalArray[33]);
                                ImportTileVariant(entry.Tilex3F, totalArray[34]);
                                ImportTileVariant(entry.Tilex4F, totalArray[35]);
                                ImportTileVariant(entry.Tilex5F, totalArray[36]);
                                ImportTileVariant(entry.Tilex6F, totalArray[37]);
                                ImportTileVariant(entry.Tilex7F, totalArray[38]);
                                ImportTileVariant(entry.Tilex8F, totalArray[39]);
                                ImportTileVariant(entry.Tilex9F, totalArray[40]);
                                ImportTileVariant(entry.TilexAF, totalArray[41]);
                                ImportTileVariant(entry.TilexBF, totalArray[42]);
                                ImportTileVariant(entry.TilexCF, totalArray[43]);
                                ImportTileVariant(entry.TilexDF, totalArray[44]);
                                ImportTileVariant(entry.TilexEF, totalArray[45]);
                                ImportTileVariant(entry.TilexFF, totalArray[46]);

                                autoTile.Tiles = entry;

                                autoTile.Name = new LocalText(outputName + tileTitle);

                                DataManager.SaveData(index, DataManager.DataType.AutoTile.ToString(), autoTile);
                                Debug.WriteLine(String.Format("{0:D3}: {1}", index, autoTile.Name));
                                index++;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        DiagManager.Instance.LogError(new Exception("Error importing " + outputName + "\n", ex));
                    }
                }
            }
        }
        private Image AutoTileTexture(Sides sides, Corners corners, MTexture[,] edges, MTexture[,] innerCorners, out AutoTileData data)
        {
            if (sides == Sides.All)
            {
                data = corners switch {
                    Corners.All ^ Corners.UpLeft => new AutoTileData(0, 0, TileType.InnerCorner),
                    Corners.All ^ Corners.UpRight => new AutoTileData(1, 0, TileType.InnerCorner),
                    Corners.All ^ Corners.DownLeft => new AutoTileData(0, 1, TileType.InnerCorner),
                    Corners.All ^ Corners.DownRight => new AutoTileData(1, 1, TileType.InnerCorner),
                    _ => new AutoTileData(1, 1, TileType.Filler)
                };
            }
            else
            {
                data = sides switch {
                    Sides.All ^ Sides.Up => new AutoTileData(1, 0, TileType.Edge),
                    Sides.All ^ Sides.Down => new AutoTileData(1, 2, TileType.Edge),
                    Sides.All ^ Sides.Left => new AutoTileData(0, 1, TileType.Edge),
                    Sides.All ^ Sides.Right => new AutoTileData(2, 1, TileType.Edge),
                    Sides.Down | Sides.Right => new AutoTileData(0, 0, TileType.Corner),
                    Sides.Down | Sides.Left => new AutoTileData(2, 0, TileType.Corner),
                    Sides.Up | Sides.Right => new AutoTileData(0, 2, TileType.Corner),
                    Sides.Up | Sides.Left => new AutoTileData(2, 2, TileType.Corner),
                    _ => new AutoTileData(1, 1, TileType.Filler)
                };
            }

            return(new Image(
                       data.Type == TileType.InnerCorner ?
                       innerCorners[data.X, data.Y] :
                       edges[data.X, data.Y]));
        }