private IEnumerable <CfsBitmap> LoadCfsBitmapFromBlob(LoadedBlobFile blob) { var entries = blob.BlobFile.Entries .Where(e => e.Name.Trim().ToLower().EndsWith(".cfs")) .SelectMany(e => { using (var stream = new MemoryStream()) { blob.Stream.Seek(e.Offset, SeekOrigin.Begin); blob.Stream.CopyTo(stream, (int)e.Size); stream.Seek(0, SeekOrigin.Begin); var spriteFile = new SpriteFile(); spriteFile.Deserialize(stream); return(CfsBitmap.FromSpriteFile(spriteFile, blob.BlobName, e.Name)); } }).ToList(); blob.Stream.Close(); blob.Stream.Dispose(); return(entries); }
public void TestSaveMethod() { SpriteFile spriteFile = new SpriteFile(); spriteFile.Load(TEST_FILE); MemoryStream savedStream = new MemoryStream(); spriteFile.Save(savedStream); savedStream.Seek(0, SeekOrigin.Begin); SpriteFile savedSpriteFile = new SpriteFile(); savedSpriteFile.Load(savedStream); savedStream.Close(); Assert.AreEqual(spriteFile.Textures.Count, savedSpriteFile.Textures.Count, "Texture counts do not match"); Assert.AreEqual(spriteFile.Sprites.Count, savedSpriteFile.Sprites.Count, "Sprite counts do not match"); for (int i = 0; i < spriteFile.Textures.Count; i++) { Assert.AreEqual(spriteFile.Textures[i].FileName, savedSpriteFile.Textures[i].FileName, "Texture file names values do not match"); Assert.AreEqual(spriteFile.Textures[i].ColourKey, savedSpriteFile.Textures[i].ColourKey, "Texture colour key values do not match"); } for (int i = 0; i < spriteFile.Sprites.Count; i++) { Assert.AreEqual(spriteFile.Sprites[i].Texture, savedSpriteFile.Sprites[i].Texture, "Sprite texture values do not match"); Assert.AreEqual(spriteFile.Sprites[i].X1, savedSpriteFile.Sprites[i].X1, "Sprite X1 values do not match"); Assert.AreEqual(spriteFile.Sprites[i].Y1, savedSpriteFile.Sprites[i].Y1, "Sprite Y1 values do not match"); Assert.AreEqual(spriteFile.Sprites[i].X2, savedSpriteFile.Sprites[i].X2, "Sprite X2 values do not match"); Assert.AreEqual(spriteFile.Sprites[i].Y2, savedSpriteFile.Sprites[i].Y2, "Sprite Y2 values do not match"); Assert.AreEqual(spriteFile.Sprites[i].ID, savedSpriteFile.Sprites[i].ID, "Sprite ID values do not match"); } }
public SpriteModel(string name, uint crc, SpriteFile spriteFile) : base(name, crc, new Vector3(spriteFile.MaximumWidth / -2, spriteFile.MaximumWidth / -2, spriteFile.MaximumHeight / -2), new Vector3(spriteFile.MaximumWidth / 2, spriteFile.MaximumWidth / 2, spriteFile.MaximumHeight / 2)) { SpriteFile = spriteFile ?? throw new ArgumentNullException(nameof(spriteFile)); }
public static void Main(string[] args) { using (var input = File.OpenRead("AtlasFlying.cfs")) { var cfs = new SpriteFile(); cfs.Deserialize(input); } }
private static void Export(string inputPath, string outputPath) { var inputBytes = File.ReadAllBytes(inputPath); if (BitConverter.ToUInt32(inputBytes, 0) == 0x67687361) // 'ashg' { inputBytes = RLE.Decompress(inputBytes, 0, inputBytes.Length); } var file = new SpriteFile(); using (var input = new MemoryStream(inputBytes, false)) { file.Deserialize(input, Endian.Little); } var sprite = file.Sprite; if (sprite.Texture != null) { var texture = sprite.Texture.Value; if (sprite.Palettes.Length == 1) { var bitmapPath = Path.ChangeExtension(outputPath, ".png"); var data = ExportPalettized(texture, sprite.Palettes[0]); var bitmap = MakeBitmapPalettized( texture.TotalWidth, texture.TotalHeight, data, sprite.Palettes[0]); using (bitmap) { bitmap.Save(bitmapPath, ImageFormat.Png); } } else { int i = 0; foreach (var palette in sprite.Palettes) { var bitmapPath = Path.ChangeExtension($"{outputPath}_{i}", ".png"); var data = ExportPalettized(texture, palette); var bitmap = MakeBitmapPalettized( texture.TotalWidth, texture.TotalHeight, data, palette); using (bitmap) { bitmap.Save(bitmapPath, ImageFormat.Png); } i++; } } } }
public SpriteItemViewModel(SpriteFile sprite, IOverrideSpriteProvider spriteProvider, IDialogService dialogService, SpriteTypeViewModel parent) { _parent = parent; _dialogService = dialogService; _spriteProvider = spriteProvider; Id = sprite.Id; _spriteType = sprite.Type; _isOverride = sprite.IsOverride; _displayFile = sprite.File; RevertCommand = new RelayCommand(Revert, () => _isOverride); ExportCommand = new RelayCommand(Export); SetOverrideCommand = new RelayCommand(SetOverride); UpdateDisplayImage(); }
public void TestLoadMethod() { const int TEXTURE_COUNT = 38; const int SPRITE_COUNT = 648; Stream stream = File.OpenRead(TEST_FILE); stream.Seek(0, SeekOrigin.End); long fileSize = stream.Position; stream.Seek(0, SeekOrigin.Begin); SpriteFile spriteFile = new SpriteFile(); spriteFile.Load(stream); long streamPosition = stream.Position; stream.Close(); Assert.AreEqual(fileSize, streamPosition, "Not all of the file was read"); Assert.AreEqual(TEXTURE_COUNT, spriteFile.Textures.Count, "Incorrect texture count"); Assert.AreEqual(SPRITE_COUNT, spriteFile.Sprites.Count, "Incorrect sprite count"); }
private void ReloadSprite() { if (String.IsNullOrEmpty(SpriteFile)) { return; } if (SpriteFile.EndsWith(".sprite")) { Sprite = SpriteManager.Create(SpriteFile); try { Sprite.Action = action; } catch (System.Collections.Generic.KeyNotFoundException) { Console.WriteLine($"error: action '{action}' not found in '{SpriteFile}'"); } } else { DefaultSpriteFile = SpriteFile; Sprite = SpriteManager.CreateFromImage(DefaultSpriteFile); } }
public void InitializeWithEntryAndStream(BlobFile.Entry entry, Stream stream) { var dontFixSpecialColors = true; sprite = new SpriteFile(); sprite.Deserialize(stream); lblFileName.Text = entry.Name; if (!string.IsNullOrWhiteSpace(sprite.Category)) { lblFileName.Text = $"{entry.Name} ({sprite.Category})"; } pictureBoxPreview.Width = sprite.Width; pictureBoxPreview.Height = sprite.Height; bitmap = new Bitmap(sprite.Width, sprite.Height, PixelFormat.Format8bppIndexed); var palette = bitmap.Palette; var shadowIndex = 256 - sprite.ShadowCount; var lightIndex = shadowIndex - sprite.LightCount; for (int i = 0; i < 256; i++) { var color = sprite.Palette[i]; var r = (int)((color >> 16) & 0xFF); var g = (int)((color >> 8) & 0xFF); var b = (int)((color >> 0) & 0xFF); //var a = (int)((color >> 24) & 0xFF); int a; if (i == 0) { // transparent pixel a = 0; } else if (sprite.ShadowCount > 0 && i >= shadowIndex) { if (dontFixSpecialColors == false) { // make shadows black+alpha a = 64 + (((i - shadowIndex) + 1) * 16); r = g = b = 0; } else { a = 255; } } else if (sprite.LightCount > 0 && i >= lightIndex) { if (dontFixSpecialColors == false) { // make lights white+alpha a = 64 + (((i - lightIndex) + 1) * 4); r = g = b = 255; } else { a = 255; } } /*else if (i > sprite.MaxSolidIndex) * { * a = 0; * }*/ else { a = 255; } palette.Entries[i] = Color.FromArgb(a, r, g, b); } this.palette = palette; RenderFrameAtIndex(index); if (sprite.Frames.Count() == 1) { btnPlayStop.Enabled = false; } }
public static void Main(string[] args) { bool showHelp = false; bool dontFixSpecialColors = false; var options = new OptionSet() { { "ncf|no-color-fix", "don't fix special colors (such as shadows, lights)", v => dontFixSpecialColors = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_cfs [output_png]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".png"); SpriteFile sprite; using (var input = File.OpenRead(inputPath)) { sprite = new SpriteFile(); sprite.Deserialize(input); } var bitmap = new Bitmap( sprite.Width * sprite.ColumnCount, sprite.Height * sprite.RowCount, PixelFormat.Format8bppIndexed); var palette = bitmap.Palette; var shadowIndex = 256 - sprite.ShadowCount; var lightIndex = shadowIndex - sprite.LightCount; for (int i = 0; i < 256; i++) { var color = sprite.Palette[i]; var r = (int)((color >> 16) & 0xFF); var g = (int)((color >> 8) & 0xFF); var b = (int)((color >> 0) & 0xFF); //var a = (int)((color >> 24) & 0xFF); int a; if (i == 0) { // transparent pixel a = 0; } else if (sprite.ShadowCount > 0 && i >= shadowIndex) { if (dontFixSpecialColors == false) { // make shadows black+alpha a = 64 + (((i - shadowIndex) + 1) * 16); r = g = b = 0; } else { a = 255; } } else if (sprite.LightCount > 0 && i >= lightIndex) { if (dontFixSpecialColors == false) { // make lights white+alpha a = 64 + (((i - lightIndex) + 1) * 4); r = g = b = 255; } else { a = 255; } } /*else if (i > sprite.MaxSolidIndex) * { * a = 0; * }*/ else { a = 255; } palette.Entries[i] = Color.FromArgb(a, r, g, b); } bitmap.Palette = palette; for (int i = 0, y = 0; y < sprite.Height * sprite.RowCount; y += sprite.Height) { for (int x = 0; x < sprite.Width * sprite.ColumnCount; x += sprite.Width) { var frame = sprite.Frames[i++]; if (frame.Width == 0 || frame.Height == 0) { continue; } var area = new Rectangle( x + frame.X, y + frame.Y, frame.Width, frame.Height); var data = bitmap.LockBits(area, ImageLockMode.WriteOnly, bitmap.PixelFormat); var scan = data.Scan0; for (int o = 0; o < frame.Height * frame.Width; o += frame.Width) { Marshal.Copy(frame.Pixels, o, scan, frame.Width); scan += data.Stride; } bitmap.UnlockBits(data); } } bitmap.Save(outputPath, ImageFormat.Png); }
public static (Image <Rgba32>, DeviceBuffer[]) CreateSpriteAtlas( SpriteFile spriteFile, GraphicsDevice gd, ResourceFactory disposeFactory, TextureLoader textureLoader) { //Merge all of the sprite frames together into one texture //The sprite's bounds are the maximum size that a frame can be //Since most sprites have identical frame sizes, this lets us optimize pretty well //Determine how many frames to put on one line //This helps optimize texture size var framesPerLine = (int)Math.Ceiling(Math.Sqrt(spriteFile.Frames.Count)); //Account for the change in size when converting textures (var maximumWith, var maximumHeight) = textureLoader.ComputeScaledSize(spriteFile.MaximumWidth, spriteFile.MaximumHeight); var totalWidth = maximumWith * framesPerLine; var totalHeight = maximumHeight * framesPerLine; var atlasImage = new Image <Rgba32>(totalWidth, totalHeight); var graphicsOptions = GraphicsOptions.Default; graphicsOptions.BlenderMode = PixelBlenderMode.Src; var nextFramePosition = new Point(); //Determine which texture format it is TextureFormat textureFormat; switch (spriteFile.TextureFormat) { case SpriteTextureFormat.Normal: case SpriteTextureFormat.Additive: textureFormat = TextureFormat.Normal; break; case SpriteTextureFormat.AlphaTest: textureFormat = TextureFormat.AlphaTest; break; default: textureFormat = TextureFormat.IndexAlpha; break; } var vertexBuffers = new List <DeviceBuffer>(); foreach (var frame in spriteFile.Frames) { //Each individual texture is converted before being added to the atlas to avoid bleeding effects between frames var frameImage = textureLoader.ConvertTexture( new IndexedColor256Image(spriteFile.Palette, frame.TextureData, frame.Area.Width, frame.Area.Height), textureFormat); atlasImage.Mutate(context => context.DrawImage(graphicsOptions, frameImage, nextFramePosition)); //Note: The frame origin does not apply to texture coordinates, only to vertex offsets //Important! these are float types PointF frameOrigin = nextFramePosition; var frameSize = new SizeF(frameImage.Width, frameImage.Height); //Convert to texture coordinates frameOrigin.X /= totalWidth; frameOrigin.Y /= totalHeight; frameSize.Width /= totalWidth; frameSize.Height /= totalHeight; //The vertices should be scaled to match the frame size //These don't need to be modified to account for texture scale! var scale = new Vector3(0, frame.Area.Width, frame.Area.Height); var translation = new Vector3(0, frame.Area.X, frame.Area.Y); //Construct the vertices var vertices = new WorldTextureCoordinate[] { new WorldTextureCoordinate { Vertex = (Vertices[0] * scale) + translation, Texture = new Vector2(frameOrigin.X, frameOrigin.Y) }, new WorldTextureCoordinate { Vertex = (Vertices[1] * scale) + translation, Texture = new Vector2(frameOrigin.X + frameSize.Width, frameOrigin.Y) }, new WorldTextureCoordinate { Vertex = (Vertices[2] * scale) + translation, Texture = new Vector2(frameOrigin.X + frameSize.Width, frameOrigin.Y + frameSize.Height) } , new WorldTextureCoordinate { Vertex = (Vertices[3] * scale) + translation, Texture = new Vector2(frameOrigin.X, frameOrigin.Y + frameSize.Height) } }; var vb = disposeFactory.CreateBuffer(new BufferDescription(vertices.SizeInBytes(), BufferUsage.VertexBuffer)); gd.UpdateBuffer(vb, 0, vertices); //TODO: could refactor this by having one vertex and one index buffer, and returning the start & count of indices for each frame vertexBuffers.Add(vb); nextFramePosition.X += maximumWith; //Wrap to next line if (nextFramePosition.X >= totalWidth) { nextFramePosition.X = 0; nextFramePosition.Y += maximumHeight; } } return(atlasImage, vertexBuffers.ToArray()); }
public static void GenerateCFSPreview(string inputFile, string outputFile, bool dontFixSpecialColors = false) { SpriteFile sprite; using (var input = File.OpenRead(inputFile)) { sprite = new SpriteFile(); sprite.Deserialize(input); } var bitmap = new Bitmap( sprite.Width, sprite.Height, PixelFormat.Format8bppIndexed); var palette = bitmap.Palette; var shadowIndex = 256 - sprite.ShadowCount; var lightIndex = shadowIndex - sprite.LightCount; for (int i = 0; i < 256; i++) { var color = sprite.Palette[i]; var r = (int)((color >> 16) & 0xFF); var g = (int)((color >> 8) & 0xFF); var b = (int)((color >> 0) & 0xFF); //var a = (int)((color >> 24) & 0xFF); int a; if (i == 0) { // transparent pixel a = 0; } else if (sprite.ShadowCount > 0 && i >= shadowIndex) { if (dontFixSpecialColors == false) { // make shadows black+alpha a = 64 + (((i - shadowIndex) + 1) * 16); r = g = b = 0; } else { a = 255; } } else if (sprite.LightCount > 0 && i >= lightIndex) { if (dontFixSpecialColors == false) { // make lights white+alpha a = 64 + (((i - lightIndex) + 1) * 4); r = g = b = 255; } else { a = 255; } } /*else if (i > sprite.MaxSolidIndex) * { * a = 0; * }*/ else { a = 255; } palette.Entries[i] = Color.FromArgb(a, r, g, b); } bitmap.Palette = palette; for (int i = 0, y = 0; y < sprite.Height; y += sprite.Height) { for (int x = 0; x < sprite.Width; x += sprite.Width) { try { var frame = sprite.Frames[0]; if (frame.Width == 0 || frame.Height == 0) { continue; } var area = new Rectangle( x + frame.X, y + frame.Y, frame.Width, frame.Height); var data = bitmap.LockBits(area, ImageLockMode.WriteOnly, bitmap.PixelFormat); var scan = data.Scan0; for (int o = 0; o < frame.Height * frame.Width; o += frame.Width) { Marshal.Copy(frame.Pixels, o, scan, frame.Width); scan += data.Stride; } bitmap.UnlockBits(data); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } bitmap.Save(outputFile, ImageFormat.Png); }
/// <summary> /// Returns one or more CfsBitmaps from a given sprite file. /// </summary> /// <param name="file"></param> /// <returns></returns> public static List <CfsBitmap> FromSpriteFile(SpriteFile sprite, string blobName, string cfsName) { List <CfsBitmap> output = new List <CfsBitmap>(); var bitmap = new Bitmap(sprite.Width, sprite.Height, PixelFormat.Format8bppIndexed); var dontFixSpecialColors = true; var palette = bitmap.Palette; var shadowIndex = 256 - sprite.ShadowCount; var lightIndex = shadowIndex - sprite.LightCount; // Parse the palette first. for (int i = 0; i < 256; i++) { var color = sprite.Palette[i]; var r = (int)((color >> 16) & 0xFF); var g = (int)((color >> 8) & 0xFF); var b = (int)((color >> 0) & 0xFF); //var a = (int)((color >> 24) & 0xFF); int a; if (i == 0) { // transparent pixel a = 0; } else if (sprite.ShadowCount > 0 && i >= shadowIndex) { if (dontFixSpecialColors == false) { // make shadows black+alpha a = 64 + (((i - shadowIndex) + 1) * 16); r = g = b = 0; } else { a = 255; } } else if (sprite.LightCount > 0 && i >= lightIndex) { if (dontFixSpecialColors == false) { // make lights white+alpha a = 64 + (((i - lightIndex) + 1) * 4); r = g = b = 255; } else { a = 255; } } /*else if (i > sprite.MaxSolidIndex) * { * a = 0; * }*/ else { a = 255; } palette.Entries[i] = Color.FromArgb(a, r, g, b); } // Next, parse all the frames. for (var i = 0; i < sprite.Frames.Count(); i++) { var frame = sprite.Frames[i]; if (frame.Width == 0 || frame.Height == 0) { continue; } var area = new Rectangle(frame.X, frame.Y, frame.Width, frame.Height); bitmap = new Bitmap(sprite.Width, sprite.Height, PixelFormat.Format8bppIndexed); var data = bitmap.LockBits(area, ImageLockMode.WriteOnly, bitmap.PixelFormat); var scan = data.Scan0; for (int o = 0; o < frame.Height * frame.Width; o += frame.Width) { Marshal.Copy(frame.Pixels, o, scan, frame.Width); scan += data.Stride; } bitmap.UnlockBits(data); bitmap.Palette = palette; output.Add(new CfsBitmap { Bitmap = bitmap, FrameIndex = i, BloFilename = blobName.ToLower().Trim(), CfsFilename = cfsName.ToLower().Trim(), SpriteFile = sprite }); } return(output); }
private static Bitmap GenerateBitmapFromCfs(Stream s, string fileName) { bool dontFixSpecialColors = true; var sprite = new SpriteFile(); sprite.Deserialize(s, fileName); var bitmap = new Bitmap(sprite.Width * sprite.ColumnCount, sprite.Height * sprite.RowCount, PixelFormat.Format8bppIndexed); var palette = bitmap.Palette; var shadowIndex = 256 - sprite.ShadowCount; var lightIndex = shadowIndex - sprite.LightCount; for (int i = 0; i < 256; i++) { var color = sprite.Palette[i]; var r = (int)((color >> 16) & 0xFF); var g = (int)((color >> 8) & 0xFF); var b = (int)((color >> 0) & 0xFF); //var a = (int)((color >> 24) & 0xFF); int a; if (i == 0) { // transparent pixel a = 0; } else if (sprite.ShadowCount > 0 && i >= shadowIndex) { if (dontFixSpecialColors == false) { // make shadows black+alpha a = 64 + (((i - shadowIndex) + 1) * 16); r = g = b = 0; } else { a = 255; } } else if (sprite.LightCount > 0 && i >= lightIndex) { if (dontFixSpecialColors == false) { // make lights white+alpha a = 64 + (((i - lightIndex) + 1) * 4); r = g = b = 255; } else { a = 255; } } /*else if (i > sprite.MaxSolidIndex) * { * a = 0; * }*/ else { a = 255; } palette.Entries[i] = Color.FromArgb(a, r, g, b); } bitmap.Palette = palette; for (int i = 0, y = 0; y < sprite.Height * sprite.RowCount; y += sprite.Height) { for (int x = 0; x < sprite.Width * sprite.ColumnCount; x += sprite.Width) { var frame = sprite.Frames[i++]; if (frame.Width == 0 || frame.Height == 0) { continue; } var area = new Rectangle( x + frame.X, y + frame.Y, frame.Width, frame.Height); var data = bitmap.LockBits(area, ImageLockMode.WriteOnly, bitmap.PixelFormat); var scan = data.Scan0; for (int o = 0; o < frame.Height * frame.Width; o += frame.Width) { Marshal.Copy(frame.Pixels, o, scan, frame.Width); scan += data.Stride; } bitmap.UnlockBits(data); } } return(bitmap); }