Пример #1
0
        public TSA_Image(
            Palette palettes,
            Tileset graphics,
            TSA_Array tsa)
        {
            if (palettes == null)
            {
                throw new Exception("Given palette data is null");
            }
            if (graphics == null)
            {
                throw new Exception("Given tileset data is null");
            }
            if (palettes.Count % GBA.Palette.MAX != 0)
            {
                throw new Exception("Given palette data has invalid length");
            }

            Width  = tsa.Width * 8;
            Height = tsa.Height * 8;

            Tiling   = tsa;
            Graphics = graphics;
            Palettes = Palette.Split(palettes, palettes.Count / Palette.MAX);
        }
Пример #2
0
        /// <summary>
        /// Automatically generates a TSA-compliant image from a 256(or fewer)-color image
        /// </summary>
        /// <param name="width">Width of the TSA (in tiles)</param>
        /// <param name="height">Height of the TSA (in tiles)</param>
        /// <param name="image">The bitmap to convert</param>
        /// <param name="paletteAmount">the maximum amount of 16-color palettes</param>
        /// <param name="checkRedundantTiles">whether or not to add all tiles found to the tileset</param>
        public TSA_Image(
            int width, int height,
            GBA.Bitmap image,
            int paletteAmount,
            bool checkRedundantTiles)
        {
            Width  = width * 8;
            Height = height * 8;

            if (image.Width != Width || image.Height != Height)
            {
                throw new Exception("Image given has invalid dimensions.\n" +
                                    "It must be " + Width + "x" + Height + " pixels.");
            }

            if (image.Colors.Count <= 16)
            {   // No need to run TSA-ifier code
                Palettes = Palette.Split(image.Colors, paletteAmount);

                Graphics = new Tileset(new Image(image));

                Tiling = TSA_Array.GetBasicTSA(width, height);
            }
            else
            {
                using (FormLoading loading = new FormLoading())
                { // Run the image TSA-ifier
                    loading.Show();

                    int    tileAmount  = width * height;
                    byte[] bytes       = image.ToBytes();
                    int[]  colorTotals = new int[image.Colors.Count];
                    int[,] colorAmounts = new int[image.Colors.Count, tileAmount];

                    loading.SetLoading("Checking colors...", 2);

                    int index;
                    int tile = 0;
                    for (int tileY = 0; tileY < height; tileY++)
                    {
                        for (int tileX = 0; tileX < width; tileX++)
                        {
                            index = tileX * 8 + tileY * 8 * Width;
                            for (int y = 0; y < 8; y++)
                            {
                                for (int x = 0; x < 8; x++)
                                {
                                    colorTotals[bytes[index]]++;
                                    colorAmounts[bytes[index], tile]++;
                                }
                                index += Width - 8;
                            }
                            tile++;
                        } // first we take a look at which colors are most present (in all, and per tile)
                    }
                    loading.SetPercent(7);

                    List <int> colors = new List <int>();
                    for (int i = 0; i < colorTotals.Length; i++)
                    {
                        index = 0;
                        while (index < colors.Count && colorTotals[i] > colors[index])
                        {
                            index++;
                        }

                        if (index < colors.Count)
                        {
                            colors.Insert(index, i);
                        }
                        else
                        {
                            colors.Add(i);
                        }

                        if (colors.Count > paletteAmount * 15)
                        {
                            colors.RemoveAt(0);
                        }
                    } // then we create a list of indices to colors with only the most used colors

                    loading.SetPercent(9);

                    Palettes = new Palette[paletteAmount];
                    for (int i = 0; i < paletteAmount; i++)
                    {
                        Palettes[i] = new GBA.Palette(16);
                        Palettes[i].Add(new GBA.Color(0x0000));
                    } // we create our palettes, forcing the 1st color to be black on each palette

                    loading.SetLoading("Asserting tile palettes...", 10);

                    byte[]    tilePalettes = new byte[tileAmount];
                    int[]     certainty    = new int[tileAmount];
                    GBA.Color color;
                    int       amount;
                    for (int i = colors.Count - 1; i >= 0; i--)
                    {
                        color = image.Colors[colors[i]];
                        tile  = 0;

                        while (tile < tilePalettes.Length)
                        {
                            amount = colorAmounts[colors[i], tile];

                            if (Palettes[tilePalettes[tile]].Contains(color))
                            {
                                certainty[tile] += amount;
                            }
                            else
                            {
                                if (Palettes[tilePalettes[tile]].IsFull)
                                {
                                    if (certainty[tile] < amount)
                                    {
                                        tilePalettes[tile]++;
                                        tilePalettes[tile] %= (byte)Palettes.Length;
                                        certainty[tile]     = 0;
                                        i++; break;
                                    }
                                    else
                                    {
                                        certainty[tile] -= amount;
                                    }
                                }
                                else if (amount != 0)
                                {
                                    Palettes[tilePalettes[tile]].Add(color);
                                    certainty[tile] += amount;
                                }
                            }
                            tile++;
                        }
                        loading.SetPercent(10 + (50 - 50 * ((float)i / (float)(colors.Count))));
                    } // and we do a loop going from  most used color to least used, setting tilePalettes and filling said palettes

                    amount = 0;
                    for (int p = 0; p < Palettes.Length; p++)
                    {
                        Palettes[p].Sort(delegate(GBA.Color first, GBA.Color second)
                        {
                            return((first.GetValueR() + first.GetValueG() + first.GetValueB())
                                   - (second.GetValueR() + second.GetValueG() + second.GetValueB()));
                        });
                        for (int i = Palettes[p].Count; i < 16; i++)
                        {
                            Palettes[p].Add(new Color(0x0000));
                        }
                    }

                    loading.SetMessage("Creating TSA information...");

                    Graphics = new Tileset(width * height);
                    Tiling   = new TSA_Array(width, height);
                    int pixel;
                    tile = 0;
                    byte HI_nibble;
                    byte LO_nibble;
                    Tile currentTile;
                    Tuple <int, bool, bool> current;
                    for (int tileY = 0; tileY < height; tileY++)
                    {
                        for (int tileX = 0; tileX < width; tileX++)
                        {
                            index = (Palettes[tilePalettes[tile]].IsFull) ? tilePalettes[tile] : 0;
                            bytes = new byte[GBA.Tile.LENGTH];

                            for (int y = 0; y < 8; y++)
                            {
                                for (int x = 0; x < 4; x++)
                                {
                                    color     = image.GetColor(tileX * 8 + x * 2, tileY * 8 + y);
                                    pixel     = GBA.Color.GetNearest(Palettes[index], color);
                                    LO_nibble = (pixel == -1) ? (byte)0x00 : (byte)(pixel);

                                    color     = image.GetColor(tileX * 8 + x * 2 + 1, tileY * 8 + y);
                                    pixel     = GBA.Color.GetNearest(Palettes[index], color);
                                    HI_nibble = (pixel == -1) ? (byte)0x00 : (byte)(pixel);

                                    bytes[x + y * 4] = (byte)((HI_nibble << 4) | LO_nibble);
                                }
                            }

                            currentTile = new Tile(bytes);

                            if (checkRedundantTiles)
                            {
                                if (currentTile.IsEmpty())
                                {
                                    current = Tuple.Create(0, false, false);
                                }
                                else
                                {
                                    current = Graphics.FindMatch(currentTile);

                                    if (current == null)
                                    {
                                        current = Tuple.Create(Graphics.Count, false, false);
                                        Graphics.Add(currentTile);
                                    }
                                }
                            }
                            else
                            {
                                current = Tuple.Create(Graphics.Count, false, false);
                                Graphics.Add(currentTile);
                            }
                            // try {
                            Tiling[tileX, tileY] = new TSA(
                                (UInt16)current.Item1,
                                tilePalettes[tile],
                                current.Item2,
                                current.Item3);
                            // } catch { }

                            loading.SetPercent(60 + 40 * ((float)tile / (float)tileAmount));
                            tile++;
                        }
                    }
                }
            }
        }