static void Write(IReadOnlyTexture <byte> existing, ISerializer s) { if (existing.Regions.Count > 255) { throw new ArgumentOutOfRangeException($"Tried to save an image with more than 255 frames as a multi-header sprite ({existing.Name} with {existing.Regions.Count} regions)"); } for (int i = 0; i < existing.Regions.Count; i++) { var region = existing.Regions[i]; s.UInt16("FrameWidth", (ushort)region.Width); s.UInt16("FrameHeight", (ushort)region.Height); s.UInt8(null, 0); s.UInt8(null, (byte)existing.Regions.Count); var frameSize = region.Width * region.Height; byte[] frameBytes = ArrayPool <byte> .Shared.Rent(frameSize); try { Debug.Assert(existing != null, nameof(existing) + " != null"); BlitUtil.BlitDirect( existing.GetRegionBuffer(i), new ImageBuffer <byte>(region.Width, region.Height, region.Width, frameBytes)); s.Bytes("Frame" + i, frameBytes, region.Width * region.Height); } finally { ArrayPool <byte> .Shared.Return(frameBytes); } } }
static void Write(IReadOnlyTexture <byte> existing, ISerializer s) { var distinctSizes = existing.Regions.Select(x => (x.Width, x.Height)).Distinct(); if (distinctSizes.Count() > 1) { var parts = distinctSizes.Select(x => $"({x.Width}, {x.Height})"); var joined = string.Join(", ", parts); throw new InvalidOperationException($"Tried to a write an image with non-uniform frames to a single-header sprite (sizes: {joined})"); } var width = (ushort)existing.Regions[0].Width; var height = (ushort)existing.Regions[0].Height; var frameCount = (byte)existing.Regions.Count; s.UInt16("Width", width); s.UInt16("Height", height); s.UInt8(null, 0); s.UInt8("Frames", frameCount); var frameBytes = new byte[width * height]; var frame = new ImageBuffer <byte>(width, height, width, frameBytes); for (int i = 0; i < frameCount; i++) { BlitUtil.BlitDirect(existing.GetRegionBuffer(i), frame); s.Bytes("Frame" + i, frameBytes, width * height); } }
IReadOnlyTexture <byte> Write(IReadOnlyTexture <byte> existing, AssetInfo info, AssetMapping mapping, ISerializer s, IJsonUtil jsonUtil) { if (existing == null) { throw new ArgumentNullException(nameof(existing)); } int width = info.Width; int height = info.Height; if (width == 0 || height == 0) { throw new ArgumentException("Explicit width and height must be defined when using FontSpriteLoader", nameof(info)); } var repacked = new SimpleTexture <byte>(existing.Id, existing.Name, width, height * existing.Regions.Count); for (int i = 0; i < existing.Regions.Count; i++) { var oldFrame = existing.GetRegionBuffer(i); repacked.AddRegion(0, i * height, width, height); BlitUtil.BlitDirect(oldFrame, repacked.GetMutableRegionBuffer(i)); } var font = _loader.Serdes(repacked, info, mapping, s, jsonUtil); return(font == null ? null : existing); }
void TrackFrameCount_ValueChanged(object sender, EventArgs e) { var asset = _core.SelectedObject; if (_logicalSprite != null && asset != null) { int?newHeight = trackFrameCount.Value <= 1 ? (int?)null : _logicalSprite.Height / trackFrameCount.Value; if (!asset.File.Height.HasValue && asset.File.Loader == FixedSizeSpriteLoader.TypeString && asset.Height != newHeight) { asset.Set(AssetProperty.Height, newHeight); _logicalSprite = null; // Force sprite reload _visualSprite = null; Render(); } } if (sender != numFrameCount && (int)numFrameCount.Value != trackFrameCount.Value) { numFrameCount.Value = trackFrameCount.Value; } }
public IReadOnlyTexture <byte> Serdes(IReadOnlyTexture <byte> existing, AssetInfo info, AssetMapping mapping, ISerializer s, IJsonUtil jsonUtil) { if (info == null) { throw new ArgumentNullException(nameof(info)); } if (s == null) { throw new ArgumentNullException(nameof(s)); } var paletteNum = info.Get(AssetProperty.PaletteId, 0); var paletteId = new PaletteId(AssetType.Palette, paletteNum); var palette = Resolve <IAssetManager>().LoadPalette(paletteId); if (palette == null) { throw new InvalidOperationException($"Could not load palette {paletteId} ({paletteNum}) for asset {info.AssetId} in file {info.File.Filename}"); } var unambiguousPalette = palette.GetUnambiguousPalette(); if (s.IsWriting()) { if (existing == null) { throw new ArgumentNullException(nameof(existing)); } var encoder = new PngEncoder(); PackedChunks.Pack(s, existing.Regions.Count, frameNum => Write(encoder, unambiguousPalette, existing, frameNum)); return(existing); } // Read var decoder = new PngDecoder(); var configuration = new Configuration(); var images = new List <Image <Rgba32> >(); try { foreach (var(bytes, _) in PackedChunks.Unpack(s)) { using var stream = new MemoryStream(bytes); images.Add(decoder.Decode <Rgba32>(configuration, stream)); } return(Read(info.AssetId, unambiguousPalette, images)); } finally { foreach (var image in images) { image.Dispose(); } } }
Bitmap GenerateBitmap(IReadOnlyTexture <byte> sprite, int frameNumber, int width, int magnify, uint[] palette) { var frame = sprite.Regions[frameNumber]; var offset = frame.Y * sprite.Width; int height = Math.Min(frame.Height, (sprite.PixelData.Length - offset + (width - 1)) / width); if (height == 0) { return(new Bitmap(1, 1)); } Bitmap bmp; if (canvas.Image?.Width == width * magnify && canvas.Image?.Height == height * magnify) { bmp = (Bitmap)canvas.Image; } else { bmp = new Bitmap(width * magnify, height * magnify); } var d = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); try { for (int n = offset; n < offset + width * height && n < sprite.PixelData.Length; n++) { unsafe { for (int my = 0; my < magnify; my++) { for (int mx = 0; mx < magnify; mx++) { int x = magnify * ((n - offset) % width) + mx; int y = magnify * ((n - offset) / width) + my; byte *p = (byte *)d.Scan0 + y * d.Stride + x * 3; byte color = sprite.PixelData[n]; p[0] = (byte)((palette[color] & 0x00ff0000) >> 16); p[1] = (byte)((palette[color] & 0x0000ff00) >> 8); p[2] = (byte)(palette[color] & 0x000000ff); } } } } } finally { bmp.UnlockBits(d); } return(bmp); }
static byte[] Write(IImageEncoder encoder, uint[] palette, IReadOnlyTexture <byte> existing, int frameNum) { var frame = existing.Regions[frameNum]; var buffer = new ReadOnlyImageBuffer <byte>( frame.Width, frame.Height, existing.Width, existing.PixelData.Slice(frame.PixelOffset, frame.PixelLength)); Image <Rgba32> image = ImageSharpUtil.ToImageSharp(buffer, palette); var bytes = FormatUtil.BytesFromStream(stream => encoder.Encode(image, stream)); return(bytes); }
public IReadOnlyTexture <byte> Serdes(IReadOnlyTexture <byte> existing, AssetInfo info, AssetMapping mapping, ISerializer s, IJsonUtil jsonUtil) { if (s == null) { throw new ArgumentNullException(nameof(s)); } if (info == null) { throw new ArgumentNullException(nameof(info)); } return(s.IsWriting() ? Write(existing, info, s) : Read(info, s)); }
public CommonColors() { var texture = new ArrayTexture <byte>( AssetId.None, "CommonColors", 1, 1, Palette.Count, Palette.OrderBy(x => x.Value).Select(x => (byte)x.Key).ToArray()); foreach (var entry in Palette.OrderBy(x => x.Value)) { texture.AddRegion(0, 0, 1, 1, (int)entry.Value); } BorderTexture = texture; }
public IReadOnlyTexture <byte> Serdes(IReadOnlyTexture <byte> existing, AssetInfo info, AssetMapping mapping, ISerializer s, IJsonUtil jsonUtil) { if (info == null) { throw new ArgumentNullException(nameof(info)); } if (s == null) { throw new ArgumentNullException(nameof(s)); } var paletteId = info.Get(AssetProperty.PaletteId, 0); var palette = Resolve <IAssetManager>() .LoadPalette(new PaletteId(AssetType.Palette, paletteId)) .GetUnambiguousPalette(); if (info.AssetId.Type == AssetType.Font) { palette = new uint[256]; palette[1] = 0xffffffff; palette[2] = 0xffcccccc; palette[3] = 0xffaaaaaa; palette[4] = 0xff777777; palette[5] = 0xff555555; } if (s.IsWriting()) { if (existing == null) { throw new ArgumentNullException(nameof(existing)); } var encoder = new PngEncoder(); var bytes = Write(encoder, palette, existing); s.Bytes(null, bytes, bytes.Length); return(existing); } else // Read { var decoder = new PngDecoder(); var configuration = new Configuration(); var bytes = s.Bytes(null, null, (int)s.BytesRemaining); using var stream = new MemoryStream(bytes); using var image = decoder.Decode <Rgba32>(configuration, stream); return(Read(info.AssetId, palette, image, info.Width, info.Height)); } }
static void InnerWrite(IReadOnlyTexture <byte> sprite, ISerializer s) { var f = sprite.Regions[0]; int frameSize = f.Width * f.Height; byte[] pixelData = ArrayPool <byte> .Shared.Rent(frameSize); try { for (int i = 0; i < sprite.Regions.Count; i++) { BlitUtil.BlitDirect( sprite.GetRegionBuffer(i), new ImageBuffer <byte>(f.Width, f.Height, f.Width, pixelData)); s.Bytes(null, pixelData, frameSize); } } finally { ArrayPool <byte> .Shared.Return(pixelData); } }
static IReadOnlyTexture <byte> Write(IReadOnlyTexture <byte> existing, AssetInfo info, ISerializer s) { if (existing == null) { throw new ArgumentNullException(nameof(existing)); } var f = existing.Regions[0]; foreach (var frame in existing.Regions) { ApiUtil.Assert(f.Width == frame.Width, "FixedSizeSpriteLoader tried to serialise sprite with non-uniform frames"); ApiUtil.Assert(f.Height == frame.Height, "FixedSizeSpriteLoader tried to serialise sprite with non-uniform frames"); } var sprite = info.Get(AssetProperty.Transposed, false) ? Transpose(existing) : existing; InnerWrite(sprite, s); return(existing); }
static IReadOnlyTexture <byte> Transpose(IReadOnlyTexture <byte> sprite) { var firstFrame = sprite.Regions[0]; int width = firstFrame.Width; int height = firstFrame.Height; int spriteCount = sprite.Regions.Count; int rotatedFrameHeight = width; byte[] pixelData = new byte[spriteCount * width * height]; var frames = new Region[spriteCount]; for (int i = 0; i < spriteCount; i++) { var oldFrame = sprite.Regions[i]; frames[i] = new Region(0, rotatedFrameHeight * i, height, rotatedFrameHeight, height, width * spriteCount, 0); ApiUtil.TransposeImage(width, height, // TODO: This should really take stride via ImageBuffers etc sprite.PixelData.Slice(oldFrame.PixelOffset, oldFrame.PixelLength), pixelData.AsSpan(frames[i].PixelOffset, frames[i].PixelLength)); } return(new SimpleTexture <byte>(sprite.Id, sprite.Name, height, width * spriteCount, pixelData, frames)); }
public IReadOnlyTexture <byte> Serdes(IReadOnlyTexture <byte> existing, AssetInfo info, AssetMapping mapping, ISerializer s, IJsonUtil jsonUtil) { IReadOnlyTexture <byte> singleFrame = null; if (s.IsWriting()) { if (existing == null) { throw new ArgumentNullException(nameof(existing)); } singleFrame = new SimpleTexture <byte>( existing.Id, existing.Name, existing.Width, existing.Height, existing.PixelData.ToArray()) .AddRegion(existing.Regions[0].X, existing.Regions[0].Y, existing.Regions[0].Width, existing.Regions[0].Height); } var sprite = new FixedSizeSpriteLoader().Serdes(singleFrame, info, mapping, s, jsonUtil); if (sprite == null) { return(null); } return(new SimpleTexture <byte>( sprite.Id, sprite.Name, sprite.Width, sprite.Height, sprite.PixelData.ToArray()) .AddRegion(0, 0, sprite.Width, sprite.Height) .AddRegion(0, sprite.Height - StatusBarHeight, sprite.Width, StatusBarHeight)); }
void TrackWidth_ValueChanged(object sender, EventArgs e) { var asset = _core.SelectedObject; if (asset == null) { return; } if (!asset.File.Width.HasValue && asset.File.Loader == FixedSizeSpriteLoader.TypeString && asset.Width != trackWidth.Value) { asset.Width = trackWidth.Value; _logicalSprite = null; // Force sprite reload _visualSprite = null; Render(); } if (sender != numWidth && (int)numWidth.Value != trackWidth.Value) { numWidth.Value = trackWidth.Value; } }
static byte[] Write(IImageEncoder encoder, uint[] palette, IReadOnlyTexture <byte> existing) { var image = ImageSharpUtil.PackSpriteSheet(palette, existing.Regions.Count, existing.GetRegionBuffer); return(FormatUtil.BytesFromStream(stream => encoder.Encode(image, stream))); }
public static unsafe Texture CreateSimpleTexture <T>(GraphicsDevice gd, TextureUsage usage, IReadOnlyTexture <T> texture) where T : unmanaged { if (gd == null) { throw new ArgumentNullException(nameof(gd)); } if (texture == null) { throw new ArgumentNullException(nameof(texture)); } var pixelFormat = GetFormat(typeof(T)); bool mip = (usage & TextureUsage.GenerateMipmaps) != 0; uint mipLevels = mip ? MipLevelCount(texture.Width, texture.Height) : 1; using Texture staging = gd.ResourceFactory.CreateTexture(new TextureDescription( (uint)texture.Width, (uint)texture.Height, 1, mipLevels, 1, pixelFormat, TextureUsage.Staging, TextureType.Texture2D)); staging.Name = "T_" + texture.Name + "_Staging"; var buffer = texture.PixelData; fixed(T *texDataPtr = &buffer[0]) { gd.UpdateTexture( staging, (IntPtr)texDataPtr, (uint)(buffer.Length * Unsafe.SizeOf <T>()), 0, 0, 0, (uint)texture.Width, (uint)texture.Height, 1, 0, 0); } Texture veldridTexture = gd.ResourceFactory.CreateTexture(new TextureDescription( (uint)texture.Width, (uint)texture.Height, 1, mipLevels, 1, pixelFormat, usage, TextureType.Texture2D)); veldridTexture.Name = "T_" + texture.Name; using CommandList cl = gd.ResourceFactory.CreateCommandList(); cl.Begin(); cl.CopyTexture(staging, veldridTexture); if (mip) { cl.GenerateMipmaps(veldridTexture); } cl.End(); gd.SubmitCommands(cl); return(veldridTexture); }
public static unsafe Texture CreateArrayTexture <T>(GraphicsDevice gd, TextureUsage usage, IReadOnlyTexture <T> texture) where T : unmanaged { if (gd == null) { throw new ArgumentNullException(nameof(gd)); } if (texture == null) { throw new ArgumentNullException(nameof(texture)); } var pixelFormat = GetFormat(typeof(T)); bool mip = (usage & TextureUsage.GenerateMipmaps) != 0; uint mipLevels = mip ? MipLevelCount(texture.Width, texture.Height) : 1; using Texture staging = gd.ResourceFactory.CreateTexture(new TextureDescription( (uint)texture.Width, (uint)texture.Height, 1, mipLevels, (uint)texture.ArrayLayers, pixelFormat, TextureUsage.Staging, TextureType.Texture2D)); staging.Name = "T_" + texture.Name + "_Staging"; for (int layer = 0; layer < texture.ArrayLayers; layer++) { var mapped = gd.Map(staging, MapMode.Write, (uint)layer * mipLevels); try { var span = new Span <T>(mapped.Data.ToPointer(), (int)mapped.SizeInBytes / sizeof(T)); int pitch = (int)(mapped.RowPitch / sizeof(T)); var source = texture.GetLayerBuffer(layer); var dest = new ImageBuffer <T>(texture.Width, texture.Height, pitch, span); BlitUtil.BlitDirect(source, dest); //gd.UpdateTexture( // staging, (IntPtr) texDataPtr, (uint) (buffer.Buffer.Length * Unsafe.SizeOf<T>()), // 0, 0, 0, // (uint) texture.Width, (uint) texture.Height, 1, // 0, (uint) layer); } finally { gd.Unmap(staging, (uint)layer * mipLevels); } } Texture veldridTexture = gd.ResourceFactory.CreateTexture(new TextureDescription( (uint)texture.Width, (uint)texture.Height, 1, mipLevels, (uint)texture.ArrayLayers, pixelFormat, usage, TextureType.Texture2D)); veldridTexture.Name = "T_" + texture.Name; using CommandList cl = gd.ResourceFactory.CreateCommandList(); cl.Begin(); cl.CopyTexture(staging, veldridTexture); if (mip) { cl.GenerateMipmaps(veldridTexture); } cl.End(); gd.SubmitCommands(cl); return(veldridTexture); }
void Render() { var asset = _core.SelectedObject; if (asset == null) { return; } Bitmap bmp; if (IsSprite(asset.File)) { // if (asset.File.Filename != _logicalSprite?.Name) // ?? // { // Ugh bool isRotated = asset.File.Get(AssetProperty.Transposed, false); asset.File.Set <bool?>(AssetProperty.Transposed, null); _logicalSprite = LoadSprite(_core.GetRawPath(asset), asset); asset.File.Set <bool?>(AssetProperty.Transposed, isRotated); _visualSprite = isRotated ? LoadSprite(asset.File.Filename, asset) : _logicalSprite; // } if (_logicalSprite == null) { return; } trackFrameCount.Maximum = _logicalSprite.Height; numFrameCount.Maximum = trackFrameCount.Maximum; trackFrame.Maximum = _logicalSprite.Regions.Count - 1; numFrame.Maximum = trackFrame.Maximum; if (trackWidth.Value == 1) { trackWidth.Value = _logicalSprite.Width; } var palette = (AlbionPalette)(chkListPalettes.SelectedItem ?? chkListPalettes.Items[0]); uint[] curPalette = palette.GetPaletteAtTime((int)((DateTime.Now - _startTime).TotalSeconds * 4)); var width = _visualSprite.Width; var frame = Math.Max(0, trackFrame.Value); bmp = GenerateBitmap(_visualSprite, frame, width, Magnify, curPalette); } //else if (asset.Layer == FileFormat.Map2D) //{ // _logicalSprite = null; // _visualSprite = null; // bmp = new Bitmap(1, 1); //} else { _logicalSprite = null; _visualSprite = null; bmp = new Bitmap(1, 1); } canvas.Image = bmp; }