Example #1
0
        /// <summary>
        /// Exports a palette to a file
        /// </summary>
        /// <param name="outputPath">The path to export to</param>
        /// <param name="palette">The palette</param>
        public static void ExportPalette(string outputPath, IList <ARGBColor> palette, int scale = 16, int offset = 0, int?optionalLength = null, int?optionalWrap = null)
        {
            int length = optionalLength ?? palette.Count;
            int wrap   = optionalWrap ?? length;
            var tex    = TextureHelpers.CreateTexture2D(Mathf.Min(length, wrap) * scale, Mathf.CeilToInt(length / (float)wrap) * scale, clear: true);

            for (int i = 0; i < length; i++)
            {
                int mainY = (tex.height / scale) - 1 - (i / wrap);
                int mainX = i % wrap;

                Color col = palette[offset + i].GetColor();

                // Remove transparency
                col = new Color(col.r, col.g, col.b);

                for (int y = 0; y < scale; y++)
                {
                    for (int x = 0; x < scale; x++)
                    {
                        tex.SetPixel(mainX * scale + x, tex.height - (mainY * scale + y) - 1, col);
                    }
                }
            }

            tex.Apply();

            Util.ByteArrayToFile(outputPath, tex.EncodeToPNG());
        }
Example #2
0
        private void CreateTilemapFull()
        {
            var lvl       = LevelEditorData.Level;
            int mapWidth  = 16;
            int mapHeight = Mathf.CeilToInt(lvl.Maps[LevelEditorData.CurrentMap].TileSet[0].Tiles.Length / (float)mapWidth);

            int       cellSize = LevelEditorData.Level.CellSize;
            Texture2D tex      = TextureHelpers.CreateTexture2D(mapWidth * cellSize, mapHeight * cellSize);

            // Refresh the full tilemap template for current map
            int xx = 0;
            int yy = 0;

            foreach (Unity_TileTexture t in lvl.Maps[LevelEditorData.CurrentMap].TileSet[0].Tiles)
            {
                FillInTilePixels(tex, t, null, xx, yy, cellSize);
                xx++;
                if (xx == mapWidth)
                {
                    xx = 0;
                    yy++;
                }
            }

            templateMaxY = yy + 1;


            tex.filterMode = FilterMode.Point;
            tex.Apply();
            tilemapFull.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0, 0), LevelEditorData.Level.PixelsPerUnit, 0, SpriteMeshType.FullRect);
        }
Example #3
0
        /// <summary>
        /// Creates a tile set from a tile map
        /// </summary>
        /// <param name="tileMapColors">The tile map colors</param>
        /// <param name="tileMapWidth">The tile map width, in tiles</param>
        /// <param name="cellSize">The tile size</param>
        public Unity_TileSet(IList <BaseColor> tileMapColors, int tileMapWidth, int cellSize)
        {
            // Create the tile array
            Tiles = new Unity_TileTexture[tileMapColors.Count / (cellSize * cellSize)];

            // Create each tile
            for (var index = 0; index < Tiles.Length; index++)
            {
                // Create the texture
                Texture2D tex = TextureHelpers.CreateTexture2D(cellSize, cellSize);

                // Get the tile x and y
                var tileY = (int)Math.Floor(index / (double)tileMapWidth);
                var tileX = (index - (tileMapWidth * tileY));

                var tileOffset = (tileY * tileMapWidth * cellSize * cellSize) + (tileX * cellSize);

                // Set every pixel
                for (int y = 0; y < cellSize; y++)
                {
                    for (int x = 0; x < cellSize; x++)
                    {
                        tex.SetPixel(x, y, tileMapColors[(tileOffset + (y * cellSize * tileMapWidth + x))].GetColor());
                    }
                }

                // Apply the pixels
                tex.Apply();

                // Create a tile
                Tiles[index] = tex.CreateTile();
            }
        }
Example #4
0
 /// <summary>
 /// Creates an empty tileset with a single transparent tile
 /// </summary>
 public Unity_TileSet(int cellSize)
 {
     Tiles = new Unity_TileTexture[]
     {
         TextureHelpers.CreateTexture2D(cellSize, cellSize, true, true).CreateTile()
     };
 }
Example #5
0
        public Texture2D ToTexture(Context context)
        {
            // Create the texture
            var tex = TextureHelpers.CreateTexture2D(Width, Height);

            // Get the block width
            var blockWidth = GetBlockWidth(context.Settings.EngineVersion);

            // Write each block
            for (int blockIndex = 0; blockIndex < ImageBlocks.Length; blockIndex++)
            {
                // Get the block data
                var blockData = ImageBlocks[blockIndex];

                // Write the block
                for (int y = 0; y < Height; y++)
                {
                    for (int x = 0; x < blockWidth; x++)
                    {
                        // Get the color
                        var c = blockData[x + (y * blockWidth)];

                        c.Alpha = Byte.MaxValue;

                        // Set the pixel
                        tex.SetPixel((x + (blockIndex * blockWidth)), tex.height - y - 1, c.GetColor());
                    }
                }
            }

            tex.Apply();

            return(tex);
        }
        public virtual Unity_MapTileMap GetTileSet(Context context, SNES_Proto_ROM rom)
        {
            // Read the tiles
            const int block_size = 0x20;

            uint length = (uint)rom.TileDescriptors.Length * 8 * 8;

            // Get the tile-set texture
            var tex = TextureHelpers.CreateTexture2D(256, Mathf.CeilToInt(length / 256f / Settings.CellSize) * Settings.CellSize);

            for (int i = 0; i < rom.TileDescriptors.Length; i++)
            {
                var descriptor = rom.TileDescriptors[i];

                var x = ((i / 4) * 2) % (256 / 8) + ((i % 2) == 0 ? 0 : 1);
                var y = (((i / 4) * 2) / (256 / 8)) * 2 + ((i % 4) < 2 ? 0 : 1);

                var curOff = block_size * descriptor.TileIndex;

                FillTextureBlock(tex, 0, 0, x, y, rom.TileMap, curOff, rom.Palettes, descriptor.Palette, descriptor.FlipX, descriptor.FlipY);
            }

            tex.Apply();

            return new Unity_MapTileMap(tex, Settings.CellSize);
        }
Example #7
0
        /// <summary>
        /// Creates a tileset with a single colored tile
        /// </summary>
        public Unity_TileSet(int cellSize, Color color)
        {
            var tex = TextureHelpers.CreateTexture2D(cellSize, cellSize);

            tex.SetPixels(Enumerable.Repeat(color, cellSize * cellSize).ToArray());

            tex.Apply();

            Tiles = new Unity_TileTexture[]
            {
                tex.CreateTile()
            };
        }
Example #8
0
        public void ExportTileset()
        {
            var tileSetIndex = 0;

            // Export every tile set
            foreach (var tileSet in LevelEditorData.Level.Maps[LevelEditorData.CurrentMap].TileSet.Where(x => x?.Tiles?.Any(y => y != null) == true))
            {
                // Get values
                var       tileCount     = tileSet.Tiles.Length;
                const int tileSetWidth  = 16;
                var       tileSetHeight = (int)Math.Ceiling(tileCount / (double)tileSetWidth);
                var       tileSize      = (int)tileSet.Tiles.First().rect.width;

                // Create the texture
                var tileTex = TextureHelpers.CreateTexture2D(tileSetWidth * tileSize, tileSetHeight * tileSize);

                // Default to fully transparent
                tileTex.SetPixels(Enumerable.Repeat(new Color(0, 0, 0, 0), tileTex.width * tileTex.height).ToArray());

                // Add every tile to it
                for (int i = 0; i < tileCount; i++)
                {
                    // Get the tile texture
                    var tile = tileSet.Tiles[i];

                    // Get the texture offsets
                    var offsetY = (i / tileSetWidth) * tileSize;
                    var offsetX = (i % tileSetWidth) * tileSize;

                    // Set the pixels
                    for (int y = 0; y < tile.rect.height; y++)
                    {
                        for (int x = 0; x < tile.rect.width; x++)
                        {
                            tileTex.SetPixel(x + offsetX, tileTex.height - (y + offsetY) - 1, tile.texture.GetPixel((int)tile.rect.x + x, (int)tile.rect.y + y));
                        }
                    }
                }

                tileTex.Apply();

                var destPath = $@"Tilemaps\{LevelEditorData.CurrentSettings.GameModeSelection}\{LevelEditorData.CurrentSettings.GameModeSelection} - {LevelEditorData.CurrentSettings.World} {LevelEditorData.CurrentSettings.Level:00} ({tileSetIndex}).png";

                Directory.CreateDirectory(Path.GetDirectoryName(destPath));

                // Save the tile map
                File.WriteAllBytes(destPath, tileTex.EncodeToPNG());

                tileSetIndex++;
            }
        }
Example #9
0
        public async UniTask ExportSpritesAsync(GameSettings settings, string outputDir)
        {
            using (var context = new Context(settings))
            {
                // Load rom
                await LoadFilesAsync(context);

                var rom = FileFactory.Read <SNES_Proto_ROM>(GetROMFilePath, context);

                var graphicsGroups = GetGraphicsGroups(rom);

                foreach (var graphicsGroup in graphicsGroups)
                {
                    // Export every sprite
                    for (int i = 0; i < graphicsGroup.Sprites.Length; i++)
                    {
                        var spriteIndex   = i % graphicsGroup.ImageDescriptors.Length;
                        var vramConfig    = i / graphicsGroup.ImageDescriptors.Length;
                        var imgDescriptor = graphicsGroup.ImageDescriptors[spriteIndex];
                        var sprite        = graphicsGroup.Sprites[i];
                        if (sprite == null)
                        {
                            continue;
                        }

                        var xPos = imgDescriptor.TileIndex % 16;
                        var yPos = (imgDescriptor.TileIndex - xPos) / 16;

                        var width  = (int)sprite.rect.width;
                        var height = (int)sprite.rect.height;

                        var newTex = TextureHelpers.CreateTexture2D(width, height);

                        var flipX = false;
                        var flipY = true;

                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                newTex.SetPixel(flipX ? width - x - 1 : x, (!flipY) ? height - y - 1 : y, sprite.texture.GetPixel((int)sprite.rect.x + x, (int)sprite.rect.y + y));
                            }
                        }

                        newTex.Apply();

                        Util.ByteArrayToFile(Path.Combine(outputDir, graphicsGroup.Name, $"{spriteIndex} - {vramConfig}.png"), newTex.EncodeToPNG());
                    }
                }
            }
        }
Example #10
0
        void ExportVignette(GBC_PalmOS_Vignette vignette, string outputPath)
        {
            if (vignette == null)
            {
                throw new Exception("Not a vignette");
            }
            if (vignette.Width > 0x1000 || vignette.Height > 0x1000 || vignette.Width == 0 || vignette.Height == 0)
            {
                throw new Exception("Not a vignette");
            }
            int w = (int)vignette.Width;
            int h = (int)vignette.Height;

            var palette = vignette.BPP == 8 ? Util.CreateDummyPalette(256, firstTransparent: false) : Util.CreateDummyPalette(16, firstTransparent: false).Reverse().ToArray();

            Texture2D tex = TextureHelpers.CreateTexture2D(w, h);

            for (int y = 0; y < h; y++)
            {
                for (int x = 0; x < w; x++)
                {
                    int ind = y * w + x;
                    if (vignette.BPP == 16)
                    {
                        BaseColor col = vignette.DataPPC[ind];
                        tex.SetPixel(x, h - 1 - y, col.GetColor());
                    }
                    else if (vignette.BPP == 8)
                    {
                        int col = vignette.Data[ind];
                        tex.SetPixel(x, h - 1 - y, palette[col].GetColor());
                    }
                    else
                    {
                        int col = vignette.Data[ind / 2];
                        if (ind % 2 == 0)
                        {
                            col = BitHelpers.ExtractBits(col, 4, 4);
                        }
                        else
                        {
                            col = BitHelpers.ExtractBits(col, 4, 0);
                        }
                        tex.SetPixel(x, h - 1 - y, palette[col].GetColor());
                    }
                }
            }
            tex.Apply();
            Util.ByteArrayToFile(outputPath, tex.EncodeToPNG());
        }
Example #11
0
        /// <summary>
        /// Exports the v-ram as an image
        /// </summary>
        /// <param name="outputPath">The path to export to</param>
        /// <param name="vram">The v-ram</param>
        public static void ExportVram(string outputPath, PS1_VRAM vram)
        {
            Texture2D vramTex = TextureHelpers.CreateTexture2D(16 * 128, 2 * 256);

            for (int x = 0; x < 16 * 128; x++)
            {
                for (int y = 0; y < 2 * 256; y++)
                {
                    byte val = vram.GetPixel8(0, y / 256, x, y % 256);
                    vramTex.SetPixel(x, (2 * 256) - 1 - y, new Color(val / 255f, val / 255f, val / 255f));
                }
            }
            vramTex.Apply();
            Util.ByteArrayToFile(outputPath, vramTex.EncodeToPNG());
        }
        public IEnumerable <Texture2D> GetAnimationFrames(Context context, GBAIsometric_RHR_AnimSet animSet, GBAIsometric_RHR_Animation anim, Dictionary <ushort, byte[]> decompressedDictionary, RGBA5551Color[] palette)
        {
            SerializerObject s = context.Deserializer;

            var startFrame = anim.StartFrameIndex;
            var frameCount = anim.FrameCount;

            Color[] pal = Util.ConvertGBAPalette(palette);

            for (int f = 0; f < frameCount; f++)
            {
                var frame = animSet.Frames[startFrame + f];

                Texture2D tex = TextureHelpers.CreateTexture2D(animSet.Width * CellSize, animSet.Height * CellSize, clear: true);

                if (frame.PatternIndex == 0xFFFF || frame.TileIndicesIndex == 0xFFFF)
                {
                    // Empty frame
                }
                else
                {
                    var patIndex = frame.PatternIndex;

                    int curTile = frame.TileIndicesIndex;

                    for (int p = 0; p < animSet.Patterns[patIndex].Length; p++)
                    {
                        var pattern = animSet.Patterns[patIndex][p];
                        for (int y = 0; y < pattern.Height; y++)
                        {
                            for (int x = 0; x < pattern.Width; x++)
                            {
                                int    actualX   = x + pattern.XPosition;
                                int    actualY   = y + pattern.YPosition;
                                ushort tileIndex = animSet.TileIndices[curTile];

                                if (!decompressedDictionary.ContainsKey(tileIndex))
                                {
                                    s.Goto(animSet.GraphicsDataPointer.Value.CompressedDataPointer);

                                    s.DoEncoded(new RHR_SpriteEncoder(animSet.Is8Bit,
                                                                      animSet.GraphicsDataPointer.Value.CompressionLookupBuffer,
                                                                      animSet.GraphicsDataPointer.Value.CompressedDataPointer,
                                                                      tileIndex), () => {
                                        decompressedDictionary[tileIndex] = s.SerializeArray <byte>(default, s.CurrentLength, name: $"{animSet.Name}:Tiles[{curTile}]:{tileIndex}");
Example #13
0
        public Texture2D ToTexture2D()
        {
            if (Width == 0 || Height == 0)
            {
                return(null);
            }
            Texture2D tex = TextureHelpers.CreateTexture2D(Width * 8, Height * 8);

            for (int y = 0; y < Height; y++)
            {
                var pal = Util.ConvertAndSplitGBCPalette(Palette[y], transparentIndex: null);
                for (int x = 0; x < Width; x++)
                {
                    var tileInd = (y * Width + x);
                    tex.FillInTile(TileSet, tileInd * 0x10, pal[PalIndices[tileInd]], Util.TileEncoding.Planar_2bpp, 8, true, x * 8, y * 8);
                }
            }
            tex.Apply();
            return(tex);
        }
        public Texture2D ToTexture2D()
        {
            const int tileWidth  = 8;
            const int tileLength = tileWidth * tileWidth / 2;

            var tex = TextureHelpers.CreateTexture2D(Width * AssembleWidth * tileWidth, Height * AssembleHeight * tileWidth);

            var assembleLength = Width * Height * tileLength;

            for (int assembleY = 0; assembleY < AssembleHeight; assembleY++)
            {
                for (int assembleX = 0; assembleX < AssembleWidth; assembleX++)
                {
                    var assembleOffset = assembleLength * (assembleY * AssembleWidth + assembleX);

                    for (int y = 0; y < Height; y++)
                    {
                        for (int x = 0; x < Width; x++)
                        {
                            var relTileOffset = tileLength * (y * Width + x);

                            tex.FillInTile(
                                imgData: TileData,
                                imgDataOffset: assembleOffset + relTileOffset,
                                pal: Util.ConvertGBAPalette(Palette),
                                encoding: Util.TileEncoding.Linear_4bpp,
                                tileWidth: tileWidth,
                                flipTextureY: true,
                                tileX: tileWidth * (assembleX * Width + x),
                                tileY: tileWidth * (assembleY * Height + y));
                        }
                    }
                }
            }

            tex.Apply();

            return(tex);
        }
Example #15
0
        public Texture2D ToTexture2D()
        {
            const int cellSize = 8;
            const int tileSize = cellSize * cellSize;

            var tex = TextureHelpers.CreateTexture2D(Map.Width * cellSize, Map.Height * cellSize);
            var pal = Util.ConvertGBAPalette(Palette);

            var fullTileSet = TileSets.SelectMany(x => x).ToArray();

            for (int y = 0; y < Map.Height; y++)
            {
                for (int x = 0; x < Map.Width; x++)
                {
                    var tile = Map.MapData[y * Map.Width + x];
                    tex.FillInTile(fullTileSet, tile.TileMapY * tileSize, pal, Util.TileEncoding.Linear_8bpp, cellSize, true, x * cellSize, y * cellSize, tile.HorizontalFlip, tile.VerticalFlip);
                }
            }

            tex.Apply();

            return(tex);
        }
Example #16
0
        /// <summary>
        /// Converts the PCX data to a texture
        /// </summary>
        /// <returns>The texture</returns>
        public Texture2D ToTexture(bool flip = false)
        {
            // Create the texture
            var tex = TextureHelpers.CreateTexture2D(ImageWidth, ImageHeight);

            // Set every pixel
            for (int y = 0; y < ImageHeight; y++)
            {
                for (int x = 0; x < ImageWidth; x++)
                {
                    // Get the palette index
                    var paletteIndex = ScanLines[y][x];

                    // Set the pixel
                    tex.SetPixel(x, flip ? (ImageHeight - y - 1) : y, VGAPalette[paletteIndex].GetColor());
                }
            }

            // Apply the pixels
            tex.Apply();

            // Return the texture
            return(tex);
        }
Example #17
0
        /// <summary>
        /// Exports all vignette textures to the specified output directory
        /// </summary>
        /// <param name="settings">The game settings</param>
        /// <param name="outputDir">The output directory</param>
        public override void ExportVignetteTextures(GameSettings settings, string outputDir)
        {
            // Create a new context
            using (var context = new Context(settings))
            {
                void exportBit(string file, int width = 16, bool swizzled = true, int blockWidth = 8, int blockHeight = 8, IList <Vector2> sizes = null)
                {
                    // Add the file to the context
                    context.AddFile(new LinearSerializedFile(context)
                    {
                        filePath   = file,
                        Endianness = BinaryFile.Endian.Big
                    });

                    // Read the file
                    BIT bit = FileFactory.Read <BIT>(file, context);

                    // Get the texture
                    var tex = bit.ToTexture(width, swizzled: swizzled, blockWidth: blockWidth, blockHeight: blockHeight, invertYAxis: true);

                    if (sizes?.Any() == true)
                    {
                        // Get the pixels
                        var pixels = tex.GetPixels();

                        var pixelOffset = 0;

                        // TODO: This doesn't work...
                        for (int i = 0; i < sizes.Count; i++)
                        {
                            // Get the output file path
                            var outputPath = Path.Combine(outputDir, FileSystem.ChangeFilePathExtension(file, $" - {i}.png"));

                            // Create a new texture
                            var newTex = TextureHelpers.CreateTexture2D((int)sizes[i].x, (int)sizes[i].y);

                            // Set the pixels
                            newTex.SetPixels(pixels.Reverse().Skip(pixelOffset).Take(newTex.width * newTex.height).ToArray());

                            newTex.Apply();

                            pixelOffset += newTex.width * newTex.height;

                            Util.ByteArrayToFile(outputPath, newTex.EncodeToPNG());
                        }
                    }
                    else
                    {
                        // Get the output file path
                        var outputPath = Path.Combine(outputDir, FileSystem.ChangeFilePathExtension(file, $".png"));

                        Util.ByteArrayToFile(outputPath, tex.EncodeToPNG());
                    }
                }

                void exportVig(string file, int width)
                {
                    // Add the file to the context
                    context.AddFile(new LinearSerializedFile(context)
                    {
                        filePath   = file,
                        Endianness = BinaryFile.Endian.Big
                    });

                    // Read the raw data
                    var rawData = FileFactory.Read <ObjectArray <ARGB1555Color> >(file, context, onPreSerialize: (s, x) => x.Length = s.CurrentLength / 2);

                    // Create the texture
                    var tex = TextureHelpers.CreateTexture2D(width, (int)(rawData.Length / width));

                    // Set the pixels
                    for (int y = 0; y < tex.height; y++)
                    {
                        for (int x = 0; x < tex.width; x++)
                        {
                            var c = rawData.Value[y * tex.width + x];

                            tex.SetPixel(x, tex.height - y - 1, c.GetColor());
                        }
                    }

                    // Apply the pixels
                    tex.Apply();

                    // Get the output file path
                    var outputPath = Path.Combine(outputDir, FileSystem.ChangeFilePathExtension(file, $".png"));

                    Util.ByteArrayToFile(outputPath, tex.EncodeToPNG());
                }

                foreach (var bitFile in Directory.GetFiles(settings.GameDirectory, "*.bit", SearchOption.AllDirectories))
                {
                    var relativePath = bitFile.Substring(context.BasePath.Length).Replace('\\', '/');

                    if (!VigWidths.ContainsKey(relativePath))
                    {
                        Debug.LogWarning($"Vignette file {relativePath} has no width");
                        continue;
                    }

                    exportBit(relativePath, width: VigWidths[relativePath]);
                }
                foreach (var vigFile in Directory.GetFiles(settings.GameDirectory, "*.vig", SearchOption.AllDirectories))
                {
                    var relativePath = vigFile.Substring(context.BasePath.Length).Replace('\\', '/');

                    if (!VigWidths.ContainsKey(relativePath))
                    {
                        Debug.LogWarning($"Vignette file {relativePath} has no width");
                        continue;
                    }

                    exportVig(relativePath, width: VigWidths[relativePath]);
                }
            }
        }
        /// <summary>
        /// Gets the sprite texture for an event
        /// </summary>
        /// <param name="context">The context</param>
        /// <param name="imgBuffer">The image buffer, if available</param>
        /// <param name="s">The image descriptor to use</param>
        /// <returns>The texture</returns>
        public override Texture2D GetSpriteTexture(Context context, byte[] imgBuffer, R1_ImageDescriptor s)
        {
            if (s.ImageType != 2 && s.ImageType != 3)
            {
                return(null);
            }

            // Ignore dummy sprites
            if (s.IsDummySprite())
            {
                return(null);
            }

            // Get the image properties
            var width  = s.Width;
            var height = s.Height;
            var offset = s.ImageBufferOffset;

            var pal4 = FileFactory.Read <ObjectArray <RGBA5551Color> >(GetPalettePath(context.Settings, 4), context, (y, x) => x.Length = 256);
            var pal8 = FileFactory.Read <ObjectArray <RGBA5551Color> >(GetPalettePath(context.Settings, 8), context, (y, x) => x.Length = 256);

            // Select correct palette
            var palette       = s.ImageType == 3 ? pal8.Value : pal4.Value;
            var paletteOffset = 16 * s.Unknown1;

            // Create the texture
            Texture2D tex = TextureHelpers.CreateTexture2D(width, height);

            // Set every pixel
            if (s.ImageType == 3)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var paletteIndex = imgBuffer[offset + width * y + x];

                        // Set the pixel
                        tex.SetPixel(x, height - 1 - y, palette[paletteIndex].GetColor());
                    }
                }
            }
            else if (s.ImageType == 2)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int actualX      = (s.ImageOffsetInPageX + x) / 2;
                        var paletteIndex = imgBuffer[offset + (width * y + x) / 2];
                        if (x % 2 == 0)
                        {
                            paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 0);
                        }
                        else
                        {
                            paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 4);
                        }

                        // Set the pixel
                        tex.SetPixel(x, height - 1 - y, palette[paletteOffset + paletteIndex].GetColor());
                    }
                }
            }

            // Apply the changes
            tex.Apply();

            // Return the texture
            return(tex);
        }
Example #19
0
        /// <summary>
        /// Gets the sprite texture for an event
        /// </summary>
        /// <param name="context">The context</param>
        /// <param name="imgBuffer">The image buffer, if available</param>
        /// <param name="s">The image descriptor to use</param>
        /// <returns>The texture</returns>
        public override Texture2D GetSpriteTexture(Context context, byte[] imgBuffer, R1_ImageDescriptor img)
        {
            if (img.ImageType != 2 && img.ImageType != 3)
            {
                return(null);
            }
            if (img.Unknown2 == 0)
            {
                return(null);
            }
            ImageBuffer buf = context.GetStoredObject <ImageBuffer>("vram");

            // Get the image properties
            var width  = img.Width;
            var height = img.Height;
            var offset = img.ImageBufferOffset;

            Texture2D tex = TextureHelpers.CreateTexture2D(width, height);

            var palette       = FileFactory.Read <R1_PS1_Executable>(ExeFilePath, context).Saturn_Palettes;
            var paletteOffset = img.PaletteInfo;

            var isBigRay = img.Offset.file.filePath == GetBigRayFilePath();
            var isFont   = context.GetStoredObject <R1_PS1_FontData[]>("Font")?.SelectMany(x => x.ImageDescriptors).Contains(img) == true;

            //paletteOffset = (ushort)(256 * (img.Unknown2 >> 4));
            if (img.ImageType == 3)
            {
                //paletteOffset = 20 * 256;
                paletteOffset = isBigRay ? (ushort)(21 * 256) : isFont ? (ushort)(19 * 256) : (ushort)((GetPaletteIndex(context) * 256));
            }
            else
            {
                paletteOffset = isBigRay ? (ushort)(21 * 256) : isFont ? (ushort)(19 * 256) : (ushort)((GetPaletteIndex(context) * 256) + ((img.PaletteInfo >> 8)) * 16);
                //paletteOffset = (ushort)((GetPaletteIndex(context) * 256) + ((img.Unknown2 >> 4) - 1) * 16);
                //paletteOffset = (ushort)(19 * 256 + ((img.Unknown2 >> 4) - 1) * 16);
            }

            // Set every pixel
            if (img.ImageType == 3)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var paletteIndex = buf.GetPixel8((uint)(offset + width * y + x));

                        // Set the pixel
                        var color = palette[paletteOffset + paletteIndex].GetColor();
                        if (paletteIndex == 0)
                        {
                            color = new Color(color.r, color.g, color.b, 0f);
                        }
                        else
                        {
                            color = new Color(color.r, color.g, color.b, 1f);
                        }
                        tex.SetPixel(x, height - 1 - y, color);
                    }
                }
            }
            else if (img.ImageType == 2)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var paletteIndex = buf.GetPixel8((uint)(offset + (width * y + x) / 2));
                        if (x % 2 == 0)
                        {
                            paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 4);
                        }
                        else
                        {
                            paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 0);
                        }

                        // Set the pixel
                        var color = palette[paletteOffset + paletteIndex].GetColor();
                        if (paletteIndex == 0)
                        {
                            color = new Color(color.r, color.g, color.b, 0f);
                        }
                        else
                        {
                            color = new Color(color.r, color.g, color.b, 1f);
                        }
                        tex.SetPixel(x, height - 1 - y, color);
                    }
                }
            }


            //tex.SetPixels(Enumerable.Repeat(Color.blue, tex.width * tex.height).ToArray());
            tex.Apply();

            return(tex);
        }
Example #20
0
        public Texture2D CreateLevelScreenshot()
        {
            // Hide unused links and show gendoors
            foreach (var e in Objects)
            {
                // Update the event to make sure it has rendered
                e.ForceUpdate();

                if (e.ObjData is Unity_Object_R1 r1Obj)
                {
                    Enum[] exceptions = new Enum[]
                    {
                        R1_EventType.TYPE_GENERATING_DOOR,
                        R1_EventType.TYPE_DESTROYING_DOOR,
                        R1_EventType.MS_scintillement,
                        R1_EventType.MS_super_gendoor,
                        R1_EventType.MS_super_kildoor,
                        R1_EventType.MS_compteur,
                        R1_EventType.TYPE_RAY_POS,
                        R1_EventType.TYPE_INDICATOR,
                    };

                    if (exceptions.Contains(r1Obj.EventData.Type))
                    {
                        e.gameObject.SetActive(true);
                    }
                }
                else if (e.ObjData is Unity_Object_GBA gbaObj)
                {
                    if (gbaObj.Actor.ActorID == 0)
                    {
                        e.gameObject.SetActive(true);
                    }
                }

                // Always hide events with no graphics
                if (e.defautRenderer.enabled)
                {
                    e.gameObject.SetActive(false);
                }

                // TODO: Change this option
                // Helper method
                bool showLinksForObj(Unity_ObjBehaviour ee)
                {
                    if (ee.ObjData is Unity_Object_R1 r1Object)
                    {
                        return(r1Object.EventData.Type == R1_EventType.TYPE_GENERATING_DOOR ||
                               r1Object.EventData.Type == R1_EventType.TYPE_DESTROYING_DOOR ||
                               r1Object.EventData.Type == R1_EventType.MS_scintillement ||
                               r1Object.EventData.Type == R1_EventType.MS_super_gendoor ||
                               r1Object.EventData.Type == R1_EventType.MS_super_kildoor ||
                               r1Object.EventData.Type == R1_EventType.MS_compteur);
                    }

                    return(ee.ObjData.EditorLinkGroup != 0);
                }

                if (e.ObjData.EditorLinkGroup == 0)
                {
                    e.lineRend.enabled = false;
                    e.linkCube.gameObject.SetActive(false);
                }
                else
                {
                    // Hide link if not linked to gendoor
                    bool gendoorFound = showLinksForObj(e);
                    var  allofSame    = new List <Unity_ObjBehaviour> {
                        e
                    };

                    foreach (Unity_ObjBehaviour f in Objects.Where(f => f.ObjData.EditorLinkGroup == e.ObjData.EditorLinkGroup))
                    {
                        allofSame.Add(f);
                        if (showLinksForObj(f))
                        {
                            gendoorFound = true;
                        }
                    }

                    if (!gendoorFound)
                    {
                        foreach (var a in allofSame)
                        {
                            a.lineRend.enabled = false;
                            a.linkCube.gameObject.SetActive(false);
                        }
                    }
                }
            }

            RenderTexture renderTex = new RenderTexture(LevelEditorData.MaxWidth * LevelEditorData.Level.CellSize / 1, LevelEditorData.MaxHeight * LevelEditorData.Level.CellSize / 1, 24);

            renderCamera.targetTexture = renderTex;
            var cellSizeInUnits = LevelEditorData.Level.CellSize / (float)LevelEditorData.Level.PixelsPerUnit;

            renderCamera.transform.position = new Vector3((LevelEditorData.MaxWidth) * cellSizeInUnits / 2f, -(LevelEditorData.MaxHeight) * cellSizeInUnits / 2f, renderCamera.transform.position.z);
            renderCamera.orthographicSize   = (LevelEditorData.MaxHeight * cellSizeInUnits / 2f);
            renderCamera.rect = new Rect(0, 0, 1, 1);
            renderCamera.Render();

            // Save to picture
            RenderTexture.active = renderTex;

            tex = TextureHelpers.CreateTexture2D(renderTex.width, renderTex.height);
            tex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
            tex.Apply();

            RenderTexture.active = null;
            renderCamera.rect    = new Rect(0, 0, 0, 0);

            return(tex);
        }
Example #21
0
        // Used to redraw all tiles with different palette (0 = auto, 1-3 = palette)
        public void RefreshTiles(int palette)
        {
            Debug.Log($"Refreshing tiles with palette {palette}");

            // Change button visibility
            _currentPalette = palette;
            for (int i = 0; i < paletteButtons.Length; i++)
            {
                ColorBlock b = paletteButtons[i].colors;
                b.normalColor            = _currentPalette == i ? new Color(1, 1, 1) : new Color(0.5f, 0.5f, 0.5f);
                paletteButtons[i].colors = b;
            }

            // Get the current level and map
            var lvl = LevelEditorData.Level;


            // If auto, refresh indexes
            if (palette == 0)
            {
                lvl.AutoApplyPalette();
            }

            // Refresh tiles for every map
            if (GraphicsTilemaps.Length != LevelEditorData.Level.Maps.Length)
            {
                Array.Resize(ref GraphicsTilemaps, LevelEditorData.Level.Maps.Length);
                for (int i = 1; i < GraphicsTilemaps.Length; i++)
                {
                    GraphicsTilemaps[i] = Instantiate <SpriteRenderer>(GraphicsTilemaps[0], new Vector3(0, 0, -i), Quaternion.identity, GraphicsTilemaps[0].transform.parent);
                    GraphicsTilemaps[i].gameObject.name = "Tilemap Graphics " + i;
                    if (lvl.Maps[i].IsForeground)
                    {
                        Debug.Log($"{i} is in front");
                        //TilemapRenderer tr = GraphicsTilemaps[i].GetComponent<TilemapRenderer>();
                        SpriteRenderer tr = GraphicsTilemaps[i];
                        tr.sortingLayerName = "Tiles Front";
                    }
                }
            }
            animatedTiles = new Dictionary <Unity_AnimatedTile, List <Unity_AnimatedTile.Instance> > [GraphicsTilemaps.Length];
            for (int mapIndex = 0; mapIndex < LevelEditorData.Level.Maps.Length; mapIndex++)
            {
                var map = lvl.Maps[mapIndex];
                animatedTiles[mapIndex] = new Dictionary <Unity_AnimatedTile, List <Unity_AnimatedTile.Instance> >();
                if (map.IsAdditive)
                {
                    GraphicsTilemaps[mapIndex].material = additiveMaterial;
                }
                if (map.Alpha.HasValue)
                {
                    GraphicsTilemaps[mapIndex].color = new Color(1f, 1f, 1f, map.Alpha.Value);
                }
                int       cellSize = LevelEditorData.Level.CellSize;
                Texture2D tex      = TextureHelpers.CreateTexture2D(map.Width * cellSize, map.Height * cellSize);

                for (int y = 0; y < map.Height; y++)
                {
                    for (int x = 0; x < map.Width; x++)
                    {
                        var t = map.MapTiles[y * map.Width + x];

                        if (palette != 0)
                        {
                            t.PaletteIndex = palette;
                        }

                        if (t.PaletteIndex - 1 >= map.TileSet.Length)
                        {
                            t.PaletteIndex = 1;
                        }

                        Unity_TileTexture tile = map.GetTile(t, LevelEditorData.CurrentSettings);
                        var atInstance         = map.GetAnimatedTile(t, LevelEditorData.CurrentSettings);
                        if (atInstance != null)
                        {
                            atInstance.x = x;
                            atInstance.y = y;
                            var at = atInstance.animatedTile;
                            if (!animatedTiles[mapIndex].ContainsKey(at))
                            {
                                animatedTiles[mapIndex][at] = new List <Unity_AnimatedTile.Instance>();
                            }
                            animatedTiles[mapIndex][at].Add(atInstance);
                        }
                        FillInTilePixels(tex, tile, t, x, y, cellSize);

                        /*GraphicsTilemaps[mapIndex].SetTile(new Vector3Int(x, y, 0), map.GetTile(t, LevelEditorData.CurrentSettings));
                         * GraphicsTilemaps[mapIndex].SetTransformMatrix(new Vector3Int(x, y, 0), GraphicsTilemaps[mapIndex].GetTransformMatrix(new Vector3Int(x, y, 0)) * Matrix4x4.Scale(new Vector3(t.Data.HorizontalFlip ? -1 : 1, t.Data.VerticalFlip ? -1 : 1, 1)));*/
                    }
                }
                tex.filterMode = FilterMode.Point;
                tex.Apply();
                // Note: FullRect is important, otherwise when editing you need to create a new sprite
                GraphicsTilemaps[mapIndex].sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0, 0), LevelEditorData.Level.PixelsPerUnit, 0, SpriteMeshType.FullRect);
            }

            CreateTilemapFull();
        }
Example #22
0
        public Sprite[] GetSprites(SNES_Proto_ROM rom, SNES_Proto_ImageDescriptor[] imageDescriptors)
        {
            var sprites = new Sprite[imageDescriptors.Length * 3];

            var pal    = Util.ConvertAndSplitGBAPalette(rom.SpritePalette);
            var buffer = new byte[rom.SpriteTileSet.Length];

            for (int addBlock = 0; addBlock < 3; addBlock++)
            {
                Array.Copy(rom.SpriteTileSet, buffer, buffer.Length);
                switch (addBlock)
                {
                case 0:
                    Array.Copy(rom.SpriteTileSetAdd0, 0, buffer, 0xC00, 0x400);
                    Array.Copy(rom.SpriteTileSetAdd0, 0x400, buffer, 0x1000, 0x100);
                    Array.Copy(rom.SpriteTileSetAdd0, 0x500, buffer, 0x1200, 0x100);
                    break;

                case 1:
                    Array.Copy(rom.SpriteTileSetAdd1, 0, buffer, 0xC00, 0x400);
                    Array.Copy(rom.SpriteTileSetAdd1, 0x400, buffer, 0x1000, 0x100);
                    Array.Copy(rom.SpriteTileSetAdd1, 0x500, buffer, 0x1200, 0x100);
                    break;

                case 2:
                    Array.Copy(rom.SpriteTileSetAdd2, 0, buffer, 0xC00, 0x400);
                    break;
                }



                var tileSets = pal.Select(x => Util.ToTileSetTexture(buffer, x, Util.TileEncoding.Planar_4bpp, 8, true, wrap: 16, flipTileX: true)).ToArray();

                for (int i = 0; i < imageDescriptors.Length; i++)
                {
                    if (i == 0)
                    {
                        sprites[i] = null;
                        continue;
                    }

                    var imgDescriptor = imageDescriptors[i];

                    var xPos = imgDescriptor.TileIndex % 16;
                    var yPos = (imgDescriptor.TileIndex - xPos) / 16;
                    var size = imgDescriptor.IsLarge ? 16 : 8;

                    var spriteTex = TextureHelpers.CreateTexture2D(size, size);

                    var flipX = imgDescriptor.FlipX;
                    var flipY = !imgDescriptor.FlipY;

                    var texX   = xPos * 8;
                    var texY   = tileSets[imgDescriptor.Palette].height - yPos * 8 - size;
                    var width  = size;
                    var height = size;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            spriteTex.SetPixel(flipX ? width - x - 1 : x, (!flipY) ? height - y - 1 : y, tileSets[imgDescriptor.Palette].GetPixel(texX + x, texY + y));
                        }
                    }

                    spriteTex.Apply();
                    sprites[addBlock * imageDescriptors.Length + i] = spriteTex.CreateSprite();
                }
            }
            return(sprites);
        }
Example #23
0
        /// <summary>
        /// Converts the PCX data to a texture
        /// </summary>
        /// <returns>The texture</returns>
        public Texture2D ToTexture(int width, int blockWidth = 8, int blockHeight = 8, bool swizzled = true, bool invertYAxis = false)
        {
            int height = (PixelsPaletted?.Length ?? Pixels.Length) / width;

            // Create the texture
            var tex = TextureHelpers.CreateTexture2D(width, height, clear: true);

            var blockSwizzlePattern = new Coordinate[]
            {
                new Coordinate(0, 0),
                new Coordinate(1, 0),
                new Coordinate(0, 1),
                new Coordinate(1, 1)
            };

            // Set every pixel
            int curPixel = 0;
            int xStep, yStep;

            if (swizzled)
            {
                xStep = blockSwizzlePattern.Max(c => c.x) + 1;
                yStep = blockSwizzlePattern.Max(c => c.y) + 1;
                if (width < xStep * blockWidth)
                {
                    blockSwizzlePattern = blockSwizzlePattern.Where(c => c.x * blockWidth < width).ToArray();
                }
                if (height < yStep * blockWidth)
                {
                    blockSwizzlePattern = blockSwizzlePattern.Where(c => c.y * blockHeight < height).ToArray();
                }
                xStep = blockSwizzlePattern.Max(c => c.x) + 1;
                yStep = blockSwizzlePattern.Max(c => c.y) + 1;
            }
            else
            {
                blockSwizzlePattern = new Coordinate[] { new Coordinate(0, 0) };
                xStep = 1;
                yStep = 1;
            }
            for (int y = 0; y < height / blockHeight / yStep; y++)
            {
                for (int x = 0; x < width / blockWidth / xStep; x++)
                {
                    for (int b = 0; b < blockSwizzlePattern.Length; b++)
                    {
                        int Bx = ((x * xStep) + blockSwizzlePattern[b].x) * blockWidth;
                        int By = ((y * yStep) + blockSwizzlePattern[b].y) * blockHeight;
                        if (Bx >= width)
                        {
                            continue;
                        }
                        if (By >= height)
                        {
                            continue;
                        }
                        for (int by = 0; by < blockHeight; by++)
                        {
                            for (int bx = 0; bx < blockWidth; bx++)
                            {
                                if (Bx + bx >= width)
                                {
                                    continue;
                                }
                                if (By + by >= height)
                                {
                                    continue;
                                }
                                if (PixelsPaletted != null)
                                {
                                    byte index    = PixelsPaletted[curPixel];
                                    int  pltIndex = ((y * yStep)) * blockHeight + x;
                                    if (pltIndex < PLT.Value.Length)
                                    {
                                        byte  numPalette = PLT.Value[pltIndex];
                                        uint  palIndex   = 256 * (uint)numPalette + index;
                                        Color col        = PAL.Value[palIndex].GetColor(); // 555? huh?
                                        tex.SetPixel(Bx + bx, invertYAxis ? height - 1 - (By + by) : (By + by), new Color(col.r, col.g, col.b, 1f));
                                        //tex.SetPixel(Bx + bx, height - 1 - (By + by), new Color(index / 255f, index / 255f, index / 255f, 1f));
                                    }
                                }
                                else
                                {
                                    tex.SetPixel(Bx + bx, invertYAxis ? height - 1 - (By + by) : (By + by), Pixels[curPixel].GetColor());
                                }
                                curPixel++;
                            }
                        }
                    }
                }
            }

            // Apply the pixels
            tex.Apply();

            // Return the texture
            return(tex);
        }
        public override Unity_ObjGraphics GetCommonDesign(GBA_ActorGraphicData graphicData)
        {
            // Create the design
            var des = new Unity_ObjGraphics {
                Sprites    = new List <Sprite>(),
                Animations = new List <Unity_ObjAnimation>(),
            };

            if (graphicData == null)
            {
                return(des);
            }

            var       tileMap     = graphicData.SpriteGroup_BatmanVengeance.TileMap;
            var       pal         = graphicData.SpriteGroup_BatmanVengeance.Palette.Palette;
            const int tileWidth   = 8;
            const int tileSize    = (tileWidth * tileWidth) / 2;
            var       numPalettes = graphicData.SpriteGroup_BatmanVengeance.Palette.Palette.Length / 16;

            // Add sprites for each palette
            for (int palIndex = 0; palIndex < numPalettes; palIndex++)
            {
                for (int i = 0; i < tileMap.TileMapLength; i++)
                {
                    var tex = TextureHelpers.CreateTexture2D(CellSize, CellSize);

                    for (int y = 0; y < tileWidth; y++)
                    {
                        for (int x = 0; x < tileWidth; x++)
                        {
                            int index = (i * tileSize) + ((y * tileWidth + x) / 2);

                            var b = tileMap.TileMap[index];
                            var v = BitHelpers.ExtractBits(b, 4, x % 2 == 0 ? 0 : 4);

                            Color c = pal[palIndex * 16 + v].GetColor();

                            if (v != 0)
                            {
                                c = new Color(c.r, c.g, c.b, 1f);
                            }

                            tex.SetPixel(x, (tileWidth - 1 - y), c);
                        }
                    }

                    tex.Apply();
                    des.Sprites.Add(tex.CreateSprite());
                }
            }

            Unity_ObjAnimationPart[] GetPartsForLayer(GBA_BatmanVengeance_SpriteGroup s, GBA_BatmanVengeance_Animation a, int frame, GBA_BatmanVengeance_AnimationChannel l)
            {
                /*if (l.TransformMode == GBA_AnimationLayer.AffineObjectMode.Hide
                || l.RenderMode == GBA_AnimationLayer.GfxMode.Window
                || l.RenderMode == GBA_AnimationLayer.GfxMode.Regular
                || l.Mosaic) return new Unity_ObjAnimationPart[0];
                || if (l.Color == GBA_AnimationLayer.ColorMode.Color8bpp) {
                ||  Debug.LogWarning("Animation Layer @ " + l.Offset + " has 8bpp color mode, which is currently not supported.");
                ||  return new Unity_ObjAnimationPart[0];
                || }*/
                Unity_ObjAnimationPart[] parts = new Unity_ObjAnimationPart[l.XSize * l.YSize];
                if (l.ImageIndex > graphicData.SpriteGroup_BatmanVengeance.TileMap.TileMapLength)
                {
                    Controller.print("Image index too high: " + graphicData.Offset + " - " + l.Offset);
                }
                if (l.PaletteIndex > graphicData.SpriteGroup_BatmanVengeance.Palette.Palette.Length / 16)
                {
                    Controller.print("Palette index too high: " + graphicData.Offset + " - " + l.Offset + " - " + l.PaletteIndex + " - " + (graphicData.SpriteGroup_BatmanVengeance.Palette.Palette.Length / 16));
                }
                float   rot = 0;    // l.GetRotation(a, s, frame);
                Vector2?scl = null; // l.GetScale(a, s, frame);

                for (int y = 0; y < l.YSize; y++)
                {
                    for (int x = 0; x < l.XSize; x++)
                    {
                        parts[y * l.XSize + x] = new Unity_ObjAnimationPart {
                            ImageIndex            = tileMap.TileMapLength * l.PaletteIndex + (l.ImageIndex + y * l.XSize + x),
                            IsFlippedHorizontally = l.IsFlippedHorizontally,
                            IsFlippedVertically   = l.IsFlippedVertically,
                            XPosition             = (l.XPosition + (l.IsFlippedHorizontally ? (l.XSize - 1 - x) : x) * CellSize),
                            YPosition             = (l.YPosition + (l.IsFlippedVertically ? (l.YSize - 1 - y) : y) * CellSize),
                            Rotation         = rot,
                            Scale            = scl,
                            TransformOriginX = (l.XPosition + l.XSize * CellSize / 2f),
                            TransformOriginY = (l.YPosition + l.YSize * CellSize / 2f)
                        };
                    }
                }
                return(parts);
            }

            // Add first animation for now
            foreach (var a in graphicData.SpriteGroup_BatmanVengeance.Animations)
            {
                var unityAnim = new Unity_ObjAnimation();
                var frames    = new List <Unity_ObjAnimationFrame>();
                for (int i = 0; i < a.FrameCount; i++)
                {
                    frames.Add(new Unity_ObjAnimationFrame(a.Frames[i].Layers /*.OrderByDescending(l => l.Priority)*/.SelectMany(l => GetPartsForLayer(graphicData.SpriteGroup_BatmanVengeance, a, i, l)).Reverse().ToArray()));
                }
                unityAnim.Frames    = frames.ToArray();
                unityAnim.AnimSpeed = 1;
                des.Animations.Add(unityAnim);
            }

            return(des);
        }
Example #25
0
        public async UniTask ExportAnimFramesAsync(GameSettings settings, string outputDir, bool saveAsGif)
        {
            using (var context = new Context(settings))
            {
                // Load rom
                await LoadFilesAsync(context);

                var rom = FileFactory.Read <SNES_Proto_ROM>(GetROMFilePath, context);

                foreach (var graphicsGroup in GetGraphicsGroups(rom))
                {
                    var groupDir = Path.Combine(outputDir, graphicsGroup.Name);

                    Directory.CreateDirectory(groupDir);

                    var sprites = graphicsGroup.Sprites;
                    var states  = graphicsGroup.States;

                    var animIndex = 0;

                    foreach (var stateGroup in states.Select(x => x.SNES_State).GroupBy(x => x.Animation))
                    {
                        // Get the animation
                        var    anim           = stateGroup.Key;
                        var    layersPerFrame = anim.LayersPerFrame;
                        var    frameCount     = anim.FrameCount;
                        string animPointer    = stateGroup.Key.Offset != null ? $"{(stateGroup.Key.Offset.FileOffset + 4) % 0x8000 + 0x8000:X4}" : null;
                        int    vramConfig     = stateGroup.First().VRAMConfigIndex;
                        var    spriteOffset   = graphicsGroup.ImageDescriptors.Length * vramConfig;

                        // Calculate frame size
                        int minX        = anim.Layers.Where(x => sprites[x.ImageIndex] != null).Min(x => x.XPosition);
                        int minY        = anim.Layers.Where(x => sprites[x.ImageIndex] != null).Min(x => x.YPosition);
                        int frameWidth  = (int)anim.Layers.Where(x => sprites[x.ImageIndex] != null).Max(x => sprites[x.ImageIndex].rect.width + x.XPosition);
                        int frameHeight = (int)anim.Layers.Where(x => sprites[x.ImageIndex] != null).Max(x => sprites[x.ImageIndex].rect.height + x.YPosition);

                        // Create frame textures
                        var frames = new Texture2D[frameCount];

                        // Create each animation frame
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            var tex = TextureHelpers.CreateTexture2D(frameWidth - minX, frameHeight - minY, clear: true);

                            // Write each layer
                            for (var layerIndex = 0; layerIndex < layersPerFrame; layerIndex++)
                            {
                                var animationLayer = anim.Layers[frameIndex * layersPerFrame + layerIndex];

                                if ((spriteOffset + animationLayer.ImageIndex) >= sprites.Length)
                                {
                                    continue;
                                }

                                // Get the sprite
                                var sprite = sprites[spriteOffset + animationLayer.ImageIndex];

                                if (sprite == null)
                                {
                                    continue;
                                }

                                // Set every pixel
                                for (int y = 0; y < sprite.rect.height; y++)
                                {
                                    for (int x = 0; x < sprite.rect.width; x++)
                                    {
                                        var c = sprite.texture.GetPixel((int)sprite.rect.x + x, (int)sprite.rect.y + y);

                                        var xPosition = (animationLayer.IsFlippedHorizontally ? (sprite.rect.width - 1 - x) : x) + animationLayer.XPosition;
                                        var yPosition = (!animationLayer.IsFlippedVertically ? (sprite.rect.height - 1 - y) : y) + animationLayer.YPosition;

                                        xPosition -= minX;
                                        yPosition -= minY;

                                        if (c.a != 0)
                                        {
                                            tex.SetPixel((int)xPosition, (int)(tex.height - yPosition - 1), c);
                                        }
                                    }
                                }
                            }

                            tex.Apply();

                            frames[frameIndex] = tex;
                        }

                        // Export animation
                        if (saveAsGif)
                        {
                            var speeds = stateGroup.Select(x => x.AnimSpeed).Distinct();

                            foreach (var speed in speeds)
                            {
                                using (MagickImageCollection collection = new MagickImageCollection())
                                {
                                    int index = 0;

                                    foreach (var tex in frames)
                                    {
                                        var img = tex.ToMagickImage();
                                        collection.Add(img);
                                        collection[index].AnimationDelay          = speed;
                                        collection[index].AnimationTicksPerSecond = 60;
                                        collection[index].Trim();

                                        collection[index].GifDisposeMethod = GifDisposeMethod.Background;
                                        index++;
                                    }

                                    // Save gif
                                    collection.Write(Path.Combine(groupDir, $"{animIndex} ({speed}){(animPointer != null ? $" - {animPointer}" : String.Empty)}.gif"));
                                }
                            }
                        }
                        else
                        {
                            for (int i = 0; i < frames.Length; i++)
                            {
                                Util.ByteArrayToFile(Path.Combine(groupDir, $"{animIndex}", $"{i}.png"), frames[i].EncodeToPNG());
                            }
                        }

                        animIndex++;
                    }
                }
            }
        }
Example #26
0
        public Unity_TileSet LoadTileSet(byte[] tileSet, RGBA5551Color[] palette, bool is2bpp, bool flipX, SNES_Proto_AnimatedTileEntry[] animatedTiles = null, bool shadow = false)
        {
            var pal = is2bpp ? Util.ConvertAndSplitGBCPalette(palette) : Util.ConvertAndSplitGBAPalette(palette);

            int       numPalettes         = pal.Length;
            const int wrap                = 64;
            int       bpp                 = is2bpp ? 2 : 4;
            const int tileWidth           = 8;
            int       tileSize            = tileWidth * tileWidth * bpp / 8;
            int       tilesetLength       = tileSet.Length / tileSize;
            int       animatedTilesLength = animatedTiles?.Sum(at => at.GraphicsBuffer.Length / tileSize) ?? 0;
            int       totalTilesetLength  = tilesetLength + animatedTilesLength;

            int tilesX = Math.Min(totalTilesetLength * numPalettes, wrap);
            int tilesY = Mathf.CeilToInt(totalTilesetLength * numPalettes / (float)wrap);

            var tex = TextureHelpers.CreateTexture2D(tilesX * tileWidth, tilesY * tileWidth);

            for (int p = 0; p < numPalettes; p++)
            {
                for (int i = 0; i < tilesetLength; i++)
                {
                    int tileInd = i + p * totalTilesetLength;
                    int tileY   = (tileInd / wrap) * tileWidth;
                    int tileX   = (tileInd % wrap) * tileWidth;

                    tex.FillInTile(
                        imgData: tileSet,
                        imgDataOffset: i * tileSize,
                        pal: pal[p],
                        encoding: is2bpp ? Util.TileEncoding.Planar_2bpp : Util.TileEncoding.Planar_4bpp,
                        tileWidth: tileWidth,
                        flipTextureY: false,
                        tileX: tileX,
                        tileY: tileY,
                        flipTileX: flipX);
                }

                if (animatedTiles != null)
                {
                    int curAnimatedTile = 0;
                    for (int i = 0; i < animatedTiles.Length; i++)
                    {
                        int numTiles = animatedTiles[i].GraphicsBuffer.Length / tileSize;
                        for (int t = 0; t < numTiles; t++)
                        {
                            int tileInd = tilesetLength + curAnimatedTile + p * totalTilesetLength;
                            int tileY   = (tileInd / wrap) * tileWidth;
                            int tileX   = (tileInd % wrap) * tileWidth;

                            tex.FillInTile(
                                imgData: animatedTiles[i].GraphicsBuffer,
                                imgDataOffset: t * tileSize,
                                pal: pal[p],
                                encoding: is2bpp ? Util.TileEncoding.Planar_2bpp : Util.TileEncoding.Planar_4bpp,
                                tileWidth: tileWidth,
                                flipTextureY: false,
                                tileX: tileX,
                                tileY: tileY,
                                flipTileX: flipX);
                            curAnimatedTile++;
                        }
                    }
                }
            }
            if (shadow)
            {
                var colors = tex.GetPixels();
                colors = colors.Select(c => c.a == 0 ? c : Color.black).ToArray();
                tex.SetPixels(colors);
            }

            tex.Apply();
            Unity_AnimatedTile[] unityAnimatedTiles = null;
            if (animatedTiles != null)
            {
                int curAnimatedTile = 0;
                var animTilesDict   = new Dictionary <int, List <int> >();
                foreach (var at in animatedTiles)
                {
                    var tileInd  = (at.VRAMAddress * 2) / 0x20;
                    int numTiles = at.GraphicsBuffer.Length / tileSize;
                    for (int i = 0; i < numTiles; i++)
                    {
                        int key = tileInd + i;
                        if (!animTilesDict.ContainsKey(key))
                        {
                            animTilesDict[key] = new List <int>();
                            animTilesDict[key].Add(key);
                        }
                        animTilesDict[key].Add(tilesetLength + curAnimatedTile);
                        curAnimatedTile++;
                    }
                }
                var unityAnimTilesList = new List <Unity_AnimatedTile>();
                for (int p = 0; p < numPalettes; p++)
                {
                    foreach (var kv in animTilesDict)
                    {
                        Unity_AnimatedTile newAT = new Unity_AnimatedTile()
                        {
                            AnimationSpeed = 2,
                            TileIndices    = kv.Value.Select(t => t + p * totalTilesetLength).ToArray()
                        };
                        //Debug.Log(string.Join(",",newAT.TileIndices));
                        unityAnimTilesList.Add(newAT);
                    }
                }
                unityAnimatedTiles = unityAnimTilesList.ToArray();
            }
            return(new Unity_TileSet(tex, tileWidth)
            {
                SNES_BaseLength = totalTilesetLength,
                AnimatedTiles = unityAnimatedTiles
            });
        }