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.Parent.Height.HasValue && asset.Parent.Format == FileFormat.FixedSizeSprite && asset.Height != newHeight) { asset.Height = newHeight; _logicalSprite = null; // Force sprite reload _visualSprite = null; Render(); } } if (sender != numFrameCount && (int)numFrameCount.Value != trackFrameCount.Value) { numFrameCount.Value = trackFrameCount.Value; } }
public object Load(BinaryReader br, long streamLength, string name, AssetInfo config) { Debug.Assert(config.Transposed != true); long initialPosition = br.BaseStream.Position; var sizes = ParseSpriteSizes(config.SubSprites); AlbionSprite sprite = new AlbionSprite { Name = name, Width = 0, UniformFrames = false, Frames = new List <AlbionSprite.Frame>() }; int currentY = 0; var frameBytes = new List <byte[]>(); foreach (var(width, height) in sizes) { if (br.BaseStream.Position >= initialPosition + streamLength) { break; } var bytes = br.ReadBytes(width * height); sprite.Frames.Add(new AlbionSprite.Frame(0, currentY, width, height)); frameBytes.Add(bytes); currentY += height; if (width > sprite.Width) { sprite.Width = width; } } sprite.Height = currentY; sprite.PixelData = new byte[sprite.Frames.Count * sprite.Width * currentY]; for (int n = 0; n < sprite.Frames.Count; n++) { var frame = sprite.Frames[n]; for (int j = 0; j < frame.Height; j++) { for (int i = 0; i < frame.Width; i++) { sprite.PixelData[(frame.Y + j) * sprite.Width + frame.X + i] = frameBytes[n][j * frame.Width + i]; } } } Debug.Assert(br.BaseStream.Position == initialPosition + streamLength); return(sprite); }
Bitmap GenerateBitmap(AlbionSprite sprite, int frameNumber, int width, int magnify, uint[] palette) { var frame = sprite.Frames[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); }
void TrackWidth_ValueChanged(object sender, EventArgs e) { var asset = _core.SelectedObject; if (asset == null) { return; } if (!asset.Parent.Width.HasValue && asset.Parent.Format == FileFormat.FixedSizeSprite && 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; } }
public object Serdes(object existing, AssetInfo config, AssetMapping mapping, ISerializer s) { if (s == null) { throw new ArgumentNullException(nameof(s)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } if (s.Mode != SerializerMode.Reading) { throw new NotImplementedException("Fixed size sprite saving not currently supported"); } var streamLength = s.BytesRemaining; if (streamLength == 0) { return(null); } int width = config.EffectiveWidth; int height = config.EffectiveHeight; if (width == 0) { width = (int)Math.Sqrt(streamLength); } if (height == 0) { height = (int)streamLength / width; } // ApiUtil.Assert(streamLength % width == 0); // ApiUtil.Assert(streamLength % (width * height) == 0); // long initialPosition = s.BaseStream.Position; int spriteCount = Math.Max(1, unchecked ((int)(streamLength / (width * height)))); height = (int)streamLength / (width * spriteCount); int currentY = 0; var pixelData = new byte[spriteCount * width * height]; var frames = new AlbionSpriteFrame[spriteCount]; for (int n = 0; n < spriteCount; n++) { frames[n] = new AlbionSpriteFrame(0, currentY, width, height); var bytes = s.ByteArray(null, null, width * height); for (int i = 0; i < width * height; i++) { pixelData[n * width * height + i] = bytes[i]; } currentY += height; } var sprite = new AlbionSprite(config.AssetId.ToString(), width, height * spriteCount, true, pixelData, frames); if (!config.Transposed) { return(sprite); } int rotatedFrameHeight = width; pixelData = new byte[spriteCount * width * height]; frames = new AlbionSpriteFrame[spriteCount]; for (int n = 0; n < spriteCount; n++) { frames[n] = new AlbionSpriteFrame(0, rotatedFrameHeight * n, height, rotatedFrameHeight); ApiUtil.RotateImage(width, height, new ReadOnlySpan <byte>(sprite.PixelData, n * width * height, width * height), new Span <byte>(pixelData, n * width * height, width * height)); } return(new AlbionSprite(config.AssetId.ToString(), height, width * spriteCount, true, pixelData, frames)); }
void Render() { const int magnify = 3; var asset = _core.SelectedObject; if (asset == null) { return; } Bitmap bmp; if (IsSprite(asset.Parent.Format)) { if (asset.Filename != _logicalSprite?.Name) { // Ugh bool isRotated = asset.Parent.Transposed ?? false; asset.Parent.Transposed = false; _logicalSprite = LoadSprite(asset.Filename, asset); asset.Parent.Transposed = isRotated; _visualSprite = isRotated ? LoadSprite(asset.Filename, asset) : _logicalSprite; } if (_logicalSprite == null) { return; } trackFrameCount.Maximum = _logicalSprite.Height; numFrameCount.Maximum = trackFrameCount.Maximum; trackFrame.Maximum = _logicalSprite.Frames.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; }
public object Load(BinaryReader br, long streamLength, string name, AssetInfo config) { if (streamLength == 0) { return(null); } int width = config.EffectiveWidth; int height = config.EffectiveHeight; if (width == 0) { width = (int)Math.Sqrt(streamLength); } if (height == 0) { height = (int)streamLength / width; } // Debug.Assert(streamLength % width == 0); // Debug.Assert(streamLength % (width * height) == 0); long initialPosition = br.BaseStream.Position; int spriteCount = unchecked ((int)(streamLength / (width * height))); height = (int)streamLength / (width * spriteCount); var sprite = new AlbionSprite { Name = name, Width = width, Height = height * spriteCount, Frames = new AlbionSprite.Frame[spriteCount], UniformFrames = true, PixelData = new byte[spriteCount * width * height] }; int currentY = 0; for (int n = 0; n < spriteCount; n++) { sprite.Frames[n] = new AlbionSprite.Frame(0, currentY, width, height); var bytes = br.ReadBytes(width * height); for (int i = 0; i < width * height; i++) { sprite.PixelData[n * width * height + i] = bytes[i]; } currentY += height; } if (config.Transposed) { var rotatedSprite = new AlbionSprite { Name = name, Width = height, Height = width * spriteCount, Frames = new AlbionSprite.Frame[spriteCount], UniformFrames = true, PixelData = new byte[spriteCount * width * height] }; int rotatedFrameHeight = width; for (int n = 0; n < spriteCount; n++) { rotatedSprite.Frames[n] = new AlbionSprite.Frame( 0, rotatedFrameHeight * n, rotatedSprite.Width, rotatedFrameHeight); Util.RotateImage(width, height, new Span <byte>(sprite.PixelData, n * width * height, width * height), new Span <byte>(rotatedSprite.PixelData, n * width * height, width * height)); } return(rotatedSprite); } // Debug.Assert(br.BaseStream.Position == initialPosition + streamLength); return(sprite); }
public object Load(BinaryReader br, long streamLength, AssetKey key, AssetInfo config) { ApiUtil.Assert(config.Transposed != true); var sprite = new AlbionSprite(); long initialPosition = br.BaseStream.Position; sprite.Name = key.ToString(); sprite.UniformFrames = config.Format == FileFormat.SingleHeaderSprite; int width = br.ReadUInt16(); int height = br.ReadUInt16(); int something = br.ReadByte(); ApiUtil.Assert(something == 0); int spriteCount = br.ReadByte(); sprite.Frames = new AlbionSprite.Frame[spriteCount]; var frameBytes = new List <byte[]>(); int currentY = 0; sprite.Width = 0; for (int i = 0; i < spriteCount; i++) { if (!sprite.UniformFrames && i > 0) { width = br.ReadUInt16(); height = br.ReadUInt16(); something = br.ReadByte(); ApiUtil.Assert(something == 0); int spriteCount2 = br.ReadByte(); ApiUtil.Assert(spriteCount2 == spriteCount); } var bytes = br.ReadBytes(width * height); sprite.Frames[i] = new AlbionSprite.Frame(0, currentY, width, height); frameBytes.Add(bytes); currentY += height; if (width > sprite.Width) { sprite.Width = width; } } sprite.Height = currentY; sprite.PixelData = new byte[spriteCount * sprite.Width * currentY]; for (int n = 0; n < spriteCount; n++) { var frame = sprite.Frames[n]; for (int j = 0; j < frame.Height; j++) { for (int i = 0; i < frame.Width; i++) { sprite.PixelData[(frame.Y + j) * sprite.Width + frame.X + i] = frameBytes[n][j * frame.Width + i]; } } } ApiUtil.Assert(br.BaseStream.Position == initialPosition + streamLength); return(sprite); }
void AddToTree(string location, FullXldInfo xld) { var parts = location.Split('\\'); TreeNode node = _rootNode; foreach (var dir in parts.Take(parts.Length - 1)) // Ensure parent nodes exist { if (!node.Nodes.ContainsKey(dir)) { node.Nodes.Add(dir, dir); } node = node.Nodes[dir]; } string key = parts.Last(); if (!key.EndsWith(".bin")) { return; } key = key.Substring(0, key.Length - 4); int number = int.Parse(key); if (!xld.Assets.ContainsKey(number)) { xld.Assets[number] = new FullAssetInfo { Width = 32 } } ; FullAssetInfo asset = xld.Assets[number]; string name = string.IsNullOrEmpty(asset.Name) ? key : $"{asset.Name} ({number})"; if (!node.Nodes.ContainsKey(key)) { var newNode = node.Nodes.Add(key, name); newNode.Tag = asset; newNode.NodeFont = (asset.PaletteHints?.Count == 0) ? _boldFont : _defaultFont; _nodes[asset] = newNode; } } (string, FullXldInfo) CurrentXld { get { if (fileTree.SelectedNode == null) { return(null, null); } var node = fileTree.SelectedNode; if (int.TryParse(fileTree.SelectedNode.Name, out _)) { node = fileTree.SelectedNode.Parent; } string filename = ""; while (node != _rootNode) { filename = node.Name + "\\" + filename; node = node.Parent; } filename = filename.TrimEnd('\\'); var fullXldPath = Path.GetFullPath(Path.Combine(Path.Combine(_generalConfig.BasePath, _generalConfig.ExportedXldPath), filename)); return(_config.Xlds.ContainsKey(filename) ? (fullXldPath, _config.Xlds[filename]) : (null, null)); } } (string, FullAssetInfo) CurrentObject { get { if (!int.TryParse(fileTree.SelectedNode?.Name, out int number)) { return(null, null); } var(xldFilename, xld) = CurrentXld; if (xld == null || !xld.Assets.ContainsKey(number)) { return(null, null); } var filename = $"{xldFilename}\\{number:00}.bin"; return(filename, xld.Assets[number]); } } void SyncSelectedPalettes() { var(filename, asset) = CurrentObject; if (asset == null) { return; } if (asset.PaletteHints == null) { asset.PaletteHints = new List <int>(); } for (int index = 0; index < chkListPalettes.Items.Count; index++) { var item = (AlbionPalette)chkListPalettes.Items[index]; chkListPalettes.SetItemChecked(index, asset.PaletteHints.Contains(item.Id)); } if (!chkListPalettes.GetItemChecked(chkListPalettes.SelectedIndex) && chkListPalettes.CheckedIndices.Count > 0) { chkListPalettes.SelectedIndex = chkListPalettes.CheckedIndices[0]; } } void FileTree_AfterSelect(object sender, TreeViewEventArgs e) { var(filename, asset) = CurrentObject; if (asset == null) { return; } SyncSelectedPalettes(); trackWidth.Value = asset.EffectiveWidth == 0 ? 1 : asset.EffectiveWidth; trackFrame.Value = 0; textName.Text = asset.Name; Render(); if (_logicalSprite != null) { trackFrameCount.Value = _logicalSprite.Frames.Count; if (asset.Parent.Format == FileFormat.FixedSizeSprite && asset.Height != null && _logicalSprite.Frames[0].Height != asset.Height) { asset.Height = _logicalSprite.Frames[0].Height; } } } #region Width void TrackWidth_ValueChanged(object sender, EventArgs e) { var(filename, asset) = CurrentObject; if (asset == null) { return; } if (!asset.Parent.Width.HasValue && asset.Parent.Format == FileFormat.FixedSizeSprite && 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; } } void TrackWidth_KeyDown(object sender, KeyEventArgs e) { if (e.Control && e.KeyCode == Keys.Left && trackWidth.Value != 0) { trackWidth.Value = (int)(trackWidth.Value / (e.Shift ? 1.5 : 2.0)); e.Handled = true; } if (e.Control && e.KeyCode == Keys.Right) { var newValue = (int)(trackWidth.Value * (e.Shift ? 1.5 : 2.0)); if (newValue > trackWidth.Maximum) { newValue = trackWidth.Maximum; } trackWidth.Value = newValue; e.Handled = true; } } void NumWidth_ValueChanged(object sender, EventArgs e) { if (sender != trackWidth && trackWidth.Value != (int)numWidth.Value) { trackWidth.Value = (int)numWidth.Value; } } void NumWidth_Enter(object sender, EventArgs e) { numWidth.Select(0, numWidth.Text.Length); } #endregion void TextName_TextChanged(object sender, EventArgs e) { var(filename, asset) = CurrentObject; if (asset != null) { asset.Name = textName.Text; } } void TrackFrameCount_ValueChanged(object sender, EventArgs e) { var(filename, asset) = CurrentObject; if (_logicalSprite != null && asset != null) { int?newHeight = trackFrameCount.Value <= 1 ? (int?)null : _logicalSprite.Height / trackFrameCount.Value; if (!asset.Parent.Height.HasValue && asset.Parent.Format == FileFormat.FixedSizeSprite && asset.Height != newHeight) { asset.Height = newHeight; _logicalSprite = null; // Force sprite reload _visualSprite = null; Render(); } } if (sender != numFrameCount && (int)numFrameCount.Value != trackFrameCount.Value) { numFrameCount.Value = trackFrameCount.Value; } } void NumFrameCount_ValueChanged(object sender, EventArgs e) { if (sender != trackFrameCount && trackFrameCount.Value != (int)numFrameCount.Value) { trackFrameCount.Value = (int)numFrameCount.Value; } } void TrackFrame_ValueChanged(object sender, EventArgs e) { Render(); if (sender != numFrame && (int)numFrame.Value != trackFrame.Value) { numFrame.Value = trackFrame.Value; } } void NumFrame_ValueChanged(object sender, EventArgs e) { if (sender != trackFrame && trackFrame.Value != (int)numFrame.Value) { trackFrame.Value = (int)numFrame.Value; } } void BtnSave_Click(object sender, EventArgs e) { SaveClicked?.Invoke(this, EventArgs.Empty); } void ChkListPalettes_SelectedIndexChanged(object sender, EventArgs e) { Render(); } void ChkAnimate_CheckedChanged(object sender, EventArgs e) { if (chkAnimate.Checked) { _timer.Start(); } else { _timer.Stop(); } } void FileTree_KeyDown(object sender, KeyEventArgs e) { if (e.Control && e.KeyCode == Keys.X && _logicalSprite != null) { trackWidth.Value = _logicalSprite.Frames[0].Height; } var(_, asset) = CurrentObject; if (e.Control && e.KeyCode == Keys.C && asset != null) { _savedPalettes = asset.PaletteHints.ToList(); } if (e.Control && e.KeyCode == Keys.V && asset != null && _savedPalettes != null) { asset.PaletteHints.Clear(); foreach (var palette in _savedPalettes) { asset.PaletteHints.Add(palette); } SyncSelectedPalettes(); } } void ChkListPalettes_ItemCheck(object sender, ItemCheckEventArgs e) { var(_, asset) = CurrentObject; if (asset == null) { return; } var palette = (AlbionPalette)chkListPalettes.Items[e.Index]; if (e.NewValue == CheckState.Checked) { if (!asset.PaletteHints.Contains(palette.Id)) { asset.PaletteHints.Add(palette.Id); } } else { asset.PaletteHints.Remove(palette.Id); } _nodes[asset].NodeFont = asset.PaletteHints?.Count == 0 ? _boldFont : _defaultFont; } }