private void Redraw() { if (this.disableRedrawing) { return; } var selectedSpec = this.config.GetSpecById((int)this.tilesetComboBox.SelectedItem); var selectedPalette = this.palettes.BackgroundPalettes.First(p => p.Id == (int)this.paletteComboBox.SelectedItem); var bgSpec = selectedSpec.GetBgSpec(); var blocking = MyBitmap.FromFile(bgSpec.BlockingFile).Scale(2); var nonBlocking = MyBitmap.FromFile(bgSpec.NonBlockingFile).Scale(2); var threats = MyBitmap.FromFile(bgSpec.ThreatFile).Scale(2); var packed = Packer.Pack(new Size[] { blocking.Size, nonBlocking.Size, threats.Size }, maxWidth); var width = packed.Max(tpl => tpl.Item1.X + tpl.Item2.Width); var height = packed.Max(tpl => tpl.Item1.Y + tpl.Item2.Height); var blockingPosition = packed.First(tpl => tpl.Item2 == blocking.Size); packed.Remove(blockingPosition); var nonBlockingPosition = packed.First(tpl => tpl.Item2 == nonBlocking.Size); packed.Remove(nonBlockingPosition); var threatsPosition = packed.First(); // only one left var palette = this.palettes.BackgroundPalettes[this.SelectedPalette]; var bgColor = palette.Palettes.First().ActualColors.First(); var bigBitmap = new MyBitmap(2 * width + 30, 2 * height + 30, bgColor); for (var i = 0; i <= 3; i++) { var bitmap = new MyBitmap(width, height, bgColor); var blockingClone = blocking.Clone(); blockingClone.UpdateColors(blockingClone.UniqueColors(), palette.Palettes[i].ActualColors); var nonBlockingClone = nonBlocking.Clone(); nonBlockingClone.UpdateColors(nonBlockingClone.UniqueColors(), palette.Palettes[i].ActualColors); var threatsClone = threats.Clone(); threatsClone.UpdateColors(threatsClone.UniqueColors(), palette.Palettes[i].ActualColors); bitmap.DrawImage(blockingClone, blockingPosition.Item1.X, blockingPosition.Item1.Y); bitmap.DrawImage(nonBlockingClone, nonBlockingPosition.Item1.X, nonBlockingPosition.Item1.Y); bitmap.DrawImage(threatsClone, threatsPosition.Item1.X, threatsPosition.Item1.Y); bigBitmap.DrawImage(bitmap, 10 + (i % 2) * (bitmap.Width + 10), 10 + (i / 2) * (bitmap.Height + 10)); } this.pictureBox.Image = bigBitmap.ToBitmap(); var newWidth = Math.Max(bigBitmap.Width, minWidth); var newHeight = bigBitmap.Height + heightOffset; this.Width = newWidth + widthOffset; this.Height = Math.Min(newHeight, maxHeight); this.Refresh(); }
private void LoadDirectory() { this.images = new Dictionary <string, Bitmap>(); var directory = new DirectoryInfo(this.directoryTextBox.Text); int?width = null; int?height = null; foreach (var file in directory.EnumerateFiles().OrderBy(f => f.Name)) { int ignore; if (!int.TryParse(file.Name.Substring(0, file.Name.Length - file.Extension.Length), out ignore)) { continue; } var image = MyBitmap.FromFile(file.FullName); if (width == null) { width = image.Width; } else if (width != image.Width) { throw new Exception("Invalid width " + file.Name); } if (height == null) { height = image.Height; } else if (height != image.Height) { throw new Exception("Invalid height " + file.Name); } this.images.Add(file.Name, image.Scale((int)this.zoomPicker.Value).ToBitmap()); } this.framesListBox.Items.Clear(); foreach (var item in images.Keys) { this.framesListBox.Items.Add(item); } this.StartAnimation(); }
public static void ProcessFont(string fontBmp, IList <MyBitmap> tiles, IList <int> atts = null) { var emptyFound = false; var secondEmptyFound = false; var fontBitmap = MyBitmap.FromFile(fontBmp); for (var y = 0; y < fontBitmap.Height; y += Constants.SpriteHeight) { for (var x = 0; x < fontBitmap.Width; x += Constants.SpriteWidth) { var part = fontBitmap.GetPart(x, y, Constants.SpriteWidth, Constants.SpriteHeight); if (part.IsSolidColor(part.GetPixel(0, 0))) { if (!emptyFound) { emptyFound = true; tiles.Add(part); if (atts != null) { atts.Add(1); } } else { secondEmptyFound = true; } } else { if (secondEmptyFound) { throw new Exception("Empty font tile in the middle of other tiles"); } tiles.Add(part); if (atts != null) { atts.Add(1); } } } } }
public MyBitmap GetChrImage() => MyBitmap.FromFile(this.ChrImagePath());
private void LoadButtonClick(object sender, EventArgs e) { var fileName = this.inputTextBox.Text; if (!File.Exists(fileName)) { MessageBox.Show("File doesn't exit"); } this.bitmap = MyBitmap.FromFile(fileName); if (this.bitmap.Width != Constants.BgWidth || this.bitmap.Height != Constants.BgHeight) { MessageBox.Show($"Incorrect size, should be {Constants.BgWidth}x{Constants.BgHeight}"); } this.tiles = new List <MyBitmap>(); this.positions = new List <Point>(); var indices = new int[32, 24]; for (var y = 0; y < this.bitmap.Height / Constants.NesTileSize; y++) { for (var x = 0; x < this.bitmap.Width / Constants.NesTileSize; x++) { var smallImage = bitmap.GetPart(x * Constants.NesTileSize, y * Constants.NesTileSize, Constants.NesTileSize, Constants.NesTileSize); if (this.tiles.Any(v => v.Equals(smallImage))) { indices[x, y] = this.tiles.IndexOf(smallImage); } else { this.tiles.Add(smallImage); this.positions.Add(new Point(x * Constants.NesTileSize, y * Constants.NesTileSize)); indices[x, y] = this.tiles.Count - 1; } } } const int entryWidth = 65; const int horizontalSpacing = 8; const int entriesInRow = 7; const int leftPadding = 12; const int imageWidth = entryWidth + (entryWidth + horizontalSpacing) * (entriesInRow - 1) + leftPadding; const int entryHeight = 33; const int verticalSpacing = 2; const int topPadding = 12; var rowCount = (this.tiles.Count + entriesInRow - 1) / entriesInRow; var imageHeight = rowCount * entryHeight + (rowCount - 1) * verticalSpacing + topPadding; this.smallImagesBitmap = new MyBitmap(imageWidth, imageHeight); var font = new Font("Calibri", 8); for (var i = 0; i < this.tiles.Count; i++) { var x = (i % entriesInRow) * (entryWidth + horizontalSpacing) + leftPadding; var y = (i / entriesInRow) * (entryHeight + verticalSpacing) + topPadding; var tile = this.tiles[i].Scale(2); var subImage = new MyBitmap(entryWidth, entryHeight); subImage.DrawImage(tile, (entryWidth - tile.Width) / 2, 0); var tempBitmap = subImage.ToBitmap(); using (var g = Graphics.FromImage(tempBitmap)) { g.DrawString(string.Format("{0:D3}: {1:D3}/{2:D3}", i, this.positions[i].X, this.positions[i].Y), font, Brushes.Black, 0, 18); } this.smallImagesBitmap.DrawImage(MyBitmap.FromBitmap(tempBitmap), x, y); } this.smallImagesPanel.BackgroundImage = this.smallImagesBitmap.ToBitmap(); var str = string.Empty; for (var y = 0; y < this.bitmap.Height / Constants.NesTileSize; y++) { for (var x = 0; x < this.bitmap.Width / Constants.NesTileSize; x++) { str += indices[x, y].ToString("D3") + " "; } str += Environment.NewLine; } this.textBox.Text = str; this.UpdateImage(); }
private void GetConfigAndSprites( string nonBlockingFile, string blockingFile, string threatFile, bool handleEmptyTile, out BackgroundConfig configRes, out List <MyBitmap> spritesRes, out Dictionary <string, MyBitmap> tilesWithImagesRes) { // Create config with file names. var config = new BackgroundConfig { NonBlockingFile = nonBlockingFile, BlockingFile = blockingFile, ThreatFile = threatFile }; // Get all files. Handle some not existing. var nonBlocking = File.Exists(nonBlockingFile) ? MyBitmap.FromFile(config.NonBlockingFile) : null; var blocking = File.Exists(blockingFile) ? MyBitmap.FromFile(config.BlockingFile) : null; var threat = File.Exists(threatFile) ? MyBitmap.FromFile(config.ThreatFile) : null; // Get all tiles and sprites var allTiles = new List <MyBitmap>(); var tiles = new List <Tile>(); var sprites = new List <MyBitmap>(); var tilesWithImages = new Dictionary <string, MyBitmap>(); // Processing function Tile emptyTile = null; Action <MyBitmap, TileType> processList = (bitmap, tileType) => { bitmap.MakeNesGreyscale(); for (var x = 0; x < bitmap.Width; x += Constants.BackgroundTileWidth) { for (var y = 0; y < bitmap.Height; y += Constants.BackgroundTileHeight) { var newTile = bitmap.GetPart(x, y, Constants.BackgroundTileWidth, Constants.BackgroundTileHeight); var isEmptyTile = newTile.IsNesColor(0); if (allTiles.Any(tile => tile.Equals(newTile))) { if (!isEmptyTile) { throw new Exception(string.Format("Tile {0}/{1} in file {2} is repeated somewhere", x, y, bitmap.FileName)); } continue; } if (isEmptyTile && tileType != TileType.NonBlocking) { throw new Exception("Empty tile found first in file other than non-blocking"); } var tileConfig = new Tile { Type = tileType, X = x / Constants.BackgroundTileWidth, Y = y / Constants.BackgroundTileHeight }; if (isEmptyTile) { emptyTile = tileConfig; } tileConfig.Sprites = new int[4]; var spritesInTile = new MyBitmap[] { newTile.GetPart(0, 0, Constants.SpriteWidth, Constants.SpriteHeight), newTile.GetPart(0, Constants.SpriteHeight, Constants.SpriteWidth, Constants.SpriteHeight), newTile.GetPart(Constants.SpriteWidth, 0, Constants.SpriteWidth, Constants.SpriteHeight), newTile.GetPart(Constants.SpriteWidth, Constants.SpriteHeight, Constants.SpriteWidth, Constants.SpriteHeight), }; for (var i = 0; i < spritesInTile.Length; i++) { var sprite = spritesInTile[i]; var indexOfSprite = -1; var spriteFromList = sprites.FirstOrDefault(s => s.Equals(sprite)); if (spriteFromList != null) { indexOfSprite = sprites.IndexOf(spriteFromList); } else { sprites.Add(sprite); indexOfSprite = sprites.Count - 1; } tileConfig.Sprites[i] = indexOfSprite; } tiles.Add(tileConfig); allTiles.Add(newTile); tilesWithImages.Add(tileConfig.Id, newTile); } } }; // Process all tiles (non blocking first) if (nonBlocking != null) { processList(nonBlocking, TileType.NonBlocking); } if (blocking != null) { processList(blocking, TileType.Blocking); } if (threat != null) { processList(threat, TileType.Threat); } // Move empty tile to the 1st place if (handleEmptyTile) { if (emptyTile == null) { throw new Exception("Empty tile not found"); } tiles.Remove(emptyTile); tiles.Insert(0, emptyTile); } // Set tiles in the config config.Tiles = tiles.ToArray(); // Set results. configRes = config; spritesRes = sprites; tilesWithImagesRes = tilesWithImages; }
public static SpriteConfig Read(string file, Palettes palettes) { // Read the XML. SpriteConfig config; var xml = File.ReadAllText(file); var xmlSerializer = new XmlSerializer(typeof(SpriteConfig)); using (var memoryStream = new MemoryStream()) { using (var streamWriter = new StreamWriter(memoryStream)) { streamWriter.Write(xml); streamWriter.Flush(); memoryStream.Position = 0; config = (SpriteConfig)xmlSerializer.Deserialize(memoryStream); } } // Get the image (same name). var sourceImagePath = file.Substring(0, file.Length - 3) + "png"; var source = MyBitmap.FromFile(sourceImagePath); // Prepare all sprites. foreach (var sprite in config.Sprites) { // Prepare sprite - get the image. sprite.PrepareSprite(source); // Validate number of unique colors. var uniqueColors = sprite.GetSprite().UniqueColors(); if (uniqueColors.Length > 4) { sprite.GetSprite().ToBitmap().Save("debug.bmp"); throw new Exception(string.Format("Too many colors in sprite {0}", sprite.Id)); } // Get and validate the palette mapping. var mapping = config.PaletteMappings.First(m => m.Id == sprite.Mapping); foreach (var color in uniqueColors) { if (!mapping.ColorMappings.Select(c => c.Color).Contains(color)) { sprite.GetSprite().ToBitmap().Save("debug.bmp"); throw new Exception(string.Format("Color not mapped in sprite {0}", sprite.Id)); } } // Prepare sprite with pallete applied and all reverse combinations. sprite.PreparePalettes(palettes, mapping); sprite.PrepareReversed(); } // Prepare frames. foreach (var frame in config?.Frames ?? new Frame[0]) { foreach (var sprite in frame.Sprites) { if (sprite.Id != -1) { sprite.ActualSprite = config.Sprites.First(s => s.Id == sprite.Id); } else { sprite.IsEmpty = true; } } } // Prepare animations. foreach (var animation in config.Animations ?? new Animation[0]) { // No copy of animation 0 possible since it defaults to 0 if (animation.CopyOf > 0) { var copyFrom = config.Animations.First(a => a.Id == animation.CopyOf); //// Essentially what's happening here is we clone the animation, frames and sprites and change the palette // Copy everything except for Frames. animation.SetFrom(copyFrom); // Now we must copy Frames. var newFrames = new List <Frame>(); foreach (var frame in copyFrom.Frames) { var frameClone = frame.Clone(); foreach (var sprite in frameClone.Sprites) { var mapping = config.PaletteMappings.First(m => m.Id == sprite.ActualSprite.Mapping); sprite.ActualSprite.PreparePalettes(palettes, mapping, animation.AttsUpdate); sprite.ActualSprite.PrepareReversed(); } newFrames.Add(frameClone); } animation.Frames = newFrames.ToArray(); continue; } for (var i = 0; i < animation.Frames.Length; i++) { animation.Frames[i] = config.Frames.First(frame => frame.Id == animation.Frames[i].Id); } } // Prepare bullets foreach (var bullet in config?.Bullets ?? new Bullet[0]) { bullet.Sprite = config.Sprites.First(s => s.Id == bullet.SpriteId); } return(config); }
private void ProcessButtonClick(object sender, EventArgs e) { var tiles = new List <MyBitmap>(); var atts = new List <int>(); var bgColor = Color.Black; // Font ProcessFont(this.fontTextBox.Text, tiles, atts); if (tiles.Count != Chars.Count) { throw new Exception("Invalid number of tiles in the font bmp"); } // Logo var logo = MyBitmap.FromFile(this.logoTextBox.Text); var ids = new int[logo.Width / Constants.SpriteWidth, logo.Height / Constants.SpriteHeight]; for (var y = 0; y < logo.Height; y += Constants.SpriteHeight) { for (var x = 0; x < logo.Width; x += Constants.SpriteWidth) { var tile = logo.GetPart(x, y, Constants.SpriteWidth, Constants.SpriteHeight); if (!tiles.Any(t => t.Equals(tile))) { tiles.Add(tile); atts.Add(3); } ids[x / Constants.SpriteWidth, y / Constants.SpriteHeight] = tiles.IndexOf(tile); } } // Cursor. var cursor = MyBitmap.FromFile(this.cursorTextBox.Text); var cursorId = tiles.Count; tiles.Add(cursor); atts.Add(2); // Create CHR. // 1st empty sprite var bytes = new List <byte>(); for (var i = 0; i < tiles.Count; i++) { var tile = tiles[i]; var attsForTile = atts[i]; var lowBits = new List <byte>(); var highBits = new List <byte>(); for (var y = 0; y < Constants.SpriteHeight; y++) { byte lowBit = 0; byte highBit = 0; for (var x = 0; x < Constants.SpriteWidth; x++) { lowBit = (byte)(lowBit << 1); highBit = (byte)(highBit << 1); var pixel = tile.GetPixel(x, y).ToArgb(); if (pixel != bgColor.ToArgb()) { if (attsForTile == 1 || attsForTile == 3) { lowBit |= 1; } if (attsForTile == 2 || attsForTile == 3) { highBit |= 1; } } } lowBits.Add(lowBit); highBits.Add(highBit); } bytes.AddRange(lowBits); bytes.AddRange(highBits); } bytes.AddRange(Enumerable.Repeat((byte)0, 4096 - bytes.Count)); File.WriteAllBytes(chrOutputTextBox.Text, bytes.ToArray()); // Get code. var code = this.GetCode(logo, ids, cursorId); new CodeWindow(code).ShowDialog(); }