From 9595629d0a18d72b013aef4c0337fa76d98f7094 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 19 Feb 2017 14:51:42 +1100 Subject: [PATCH] Now /imgprint auto calculates shading of layers --- MCGalaxy/Commands/building/CmdImageprint.cs | 4 +- MCGalaxy/Commands/building/CmdPalette.cs | 91 ++++++++++++++-- MCGalaxy/Drawing/Image/IPaletteMatcher.cs | 26 ++--- MCGalaxy/Drawing/Image/ImagePalette.cs | 114 ++++++-------------- MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs | 32 +++++- MCGalaxy/util/Utils.cs | 2 +- 6 files changed, 162 insertions(+), 107 deletions(-) diff --git a/MCGalaxy/Commands/building/CmdImageprint.cs b/MCGalaxy/Commands/building/CmdImageprint.cs index d090bbf05..50d8432a0 100644 --- a/MCGalaxy/Commands/building/CmdImageprint.cs +++ b/MCGalaxy/Commands/building/CmdImageprint.cs @@ -60,8 +60,8 @@ namespace MCGalaxy.Commands.Building { Player.Message(p, "Palette {0} not found.", parts[1]); return; } - if (dArgs.palette.FrontLayer == null || dArgs.palette.FrontLayer.Length == 0) { - Player.Message(p, "Palette {0} does not have any entries"); + if (dArgs.palette.Entries == null || dArgs.palette.Entries.Length == 0) { + Player.Message(p, "Palette {0} does not have any entries", dArgs.palette.Name); Player.Message(p, "Use %T/palette %Sto add entries to it"); return; } } diff --git a/MCGalaxy/Commands/building/CmdPalette.cs b/MCGalaxy/Commands/building/CmdPalette.cs index 2bc68bba5..98a47c0b7 100644 --- a/MCGalaxy/Commands/building/CmdPalette.cs +++ b/MCGalaxy/Commands/building/CmdPalette.cs @@ -16,6 +16,7 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; using MCGalaxy.Drawing; namespace MCGalaxy.Commands.Building { @@ -27,7 +28,7 @@ namespace MCGalaxy.Commands.Building { public override LevelPermission defaultRank { get { return LevelPermission.Admin; } } public override void Use(Player p, string message) { - string[] args = message.SplitSpaces(4); + string[] args = message.SplitSpaces(5); if (message == "") { Help(p); return; } if (args[0].CaselessEq("create")) { @@ -35,9 +36,9 @@ namespace MCGalaxy.Commands.Building { } else if (args[0].CaselessEq("delete")) { HandleDelete(p, args); } else if (args[0].CaselessEq("add")) { - Player.Message(p, "?????"); + HandleAdd(p, args); } else if (args[0].CaselessEq("remove")) { - Player.Message(p, "?????"); + HandleRemove(p, args); } } @@ -66,13 +67,91 @@ namespace MCGalaxy.Commands.Building { } } + void HandleAdd(Player p, string[] args) { + if (args.Length != 4) { Help(p); return; } + + ImagePalette palette = ImagePalette.Find(args[1]); + if (palette == null) { + Player.Message(p, "Palette {0} does not exist.", args[1]); return; + } + + byte block = GetBlock(p, args[2]); + if (block == Block.Invalid) return; + + if (!Utils.CheckHex(p, ref args[3])) return; + CustomColor rgb = Colors.ParseHex(args[3]); + PaletteEntry entry = new PaletteEntry(rgb.R, rgb.G, rgb.B, block); + AddEntry(p, palette, entry); + } + + static void AddEntry(Player p, ImagePalette palette, PaletteEntry entry) { + PaletteEntry[] entries = palette.Entries; + List newEntries = new List(); + if (entries != null) newEntries.AddRange(entries); + + newEntries.Add(entry); + palette.Entries = newEntries.ToArray(); + palette.Save(); + Player.Message(p, "Added block to entries of palette {0}", palette.Name); + } + + void HandleRemove(Player p, string[] args) { + if (args.Length != 3) { Help(p); return; } + + ImagePalette palette = ImagePalette.Find(args[1]); + if (palette == null) { + Player.Message(p, "Palette {0} does not exist.", args[1]); return; + } + + byte block = GetBlock(p, args[2]); + if (block == Block.Invalid) return; + RemoveEntry(p, palette, block); + } + + + static void RemoveEntry(Player p, ImagePalette palette, byte block) { + PaletteEntry[] entries = palette.Entries; + if (entries == null) { + Player.Message(p, "Block not found in entries of palette {0}", palette.Name); + } + + List newEntries = new List(); + foreach (PaletteEntry entry in entries) { + if (entry.Block == block) continue; + newEntries.Add(entry); + } + + if (newEntries.Count == entries.Length) { + Player.Message(p, "Block not found in entries of palette {0}", palette.Name); return; + } + + palette.Entries = newEntries.ToArray(); + palette.Save(); + Player.Message(p, "Removed block from entries of palette {0}", palette.Name); + } + + static byte GetBlock(Player p, string name) { + byte extBlock; + int block = DrawCmd.GetBlock(p, name, out extBlock); + + if (block == -1) return Block.Invalid; + if (block == Block.Invalid) { + Player.Message(p, "Skip block may not be used for palettes."); return Block.Invalid; + } + if (block >= Block.CpeCount) { + Player.Message(p, "Physics blocks may not be used for palettes."); return Block.Invalid; + } + + return block == Block.custom_block ? extBlock : (byte)block; + } + public override void Help(Player p) { Player.Message(p, "%T/palette create/delete [name]"); Player.Message(p, "%HCreates or deletes a palette for %T/imageprint"); - Player.Message(p, "%T/palette add [name] [block] [hex color] "); - Player.Message(p, "???"); + Player.Message(p, "%T/palette add [name] [block] [hex color]"); + Player.Message(p, "%HAdds a block to a palette's entries."); Player.Message(p, "%T/palette remove [name] [block]"); - Player.Message(p, "???"); + Player.Message(p, "%HRemoves a block from a palette's entries."); Player.Message(p, "%HPalettes: &f{0}", ImagePalette.Palettes.Join(pal => pal.Name)); } } diff --git a/MCGalaxy/Drawing/Image/IPaletteMatcher.cs b/MCGalaxy/Drawing/Image/IPaletteMatcher.cs index 756c3615f..2026f7cb9 100644 --- a/MCGalaxy/Drawing/Image/IPaletteMatcher.cs +++ b/MCGalaxy/Drawing/Image/IPaletteMatcher.cs @@ -23,7 +23,7 @@ namespace MCGalaxy.Drawing { public interface IPaletteMatcher { /// Sets the palette of blocks used to match colours from. - void SetPalette(ImagePalette palette); + void SetPalette(PaletteEntry[] front, PaletteEntry[] back); /// Returns the best matching block for the given color, /// based on this palette's colourspace. @@ -36,24 +36,24 @@ namespace MCGalaxy.Drawing { public sealed class RgbPaletteMatcher : IPaletteMatcher { - ImagePalette palette; - public void SetPalette(ImagePalette palette) { - this.palette = palette; + PaletteEntry[] front, back; + public void SetPalette(PaletteEntry[] front, PaletteEntry[] back) { + this.front = front; this.back = back; } public byte BestMatch(byte R, byte G, byte B) { int pos; - MinDist(R, G, B, palette.FrontLayer, out pos); - return palette.FrontLayer[pos].Block; + MinDist(R, G, B, front, out pos); + return front[pos].Block; } public byte BestMatch(byte R, byte G, byte B, out bool backLayer) { int frontPos, backPos; - int frontDist = MinDist(R, G, B, palette.FrontLayer, out frontPos); - int backDist = MinDist(R, G, B, palette.BackLayer, out backPos); + int frontDist = MinDist(R, G, B, front, out frontPos); + int backDist = MinDist(R, G, B, back, out backPos); backLayer = backDist <= frontDist; - return backLayer ? palette.BackLayer[backPos].Block : palette.FrontLayer[frontPos].Block; + return backLayer ? back[backPos].Block : front[frontPos].Block; } @@ -75,10 +75,10 @@ namespace MCGalaxy.Drawing { public sealed class LabPaletteMatcher : IPaletteMatcher { LabColor[] palette; - public void SetPalette(ImagePalette palette) { - this.palette = new LabColor[palette.FrontLayer.Length]; - for (int i = 0; i < palette.FrontLayer.Length; i++) - this.palette[i] = RgbToLab(palette.FrontLayer[i]); + public void SetPalette(PaletteEntry[] front, PaletteEntry[] back) { + this.palette = new LabColor[front.Length]; + for (int i = 0; i < front.Length; i++) + this.palette[i] = RgbToLab(front[i]); } public byte BestMatch(byte R, byte G, byte B) { diff --git a/MCGalaxy/Drawing/Image/ImagePalette.cs b/MCGalaxy/Drawing/Image/ImagePalette.cs index 7be0e269f..ad162d8f6 100644 --- a/MCGalaxy/Drawing/Image/ImagePalette.cs +++ b/MCGalaxy/Drawing/Image/ImagePalette.cs @@ -29,16 +29,12 @@ namespace MCGalaxy.Drawing { /// Relative file path on disc. public string FileName { get { return "extra/palettes/" + Name + ".pal"; } } - /// Blocks in the front, used in vertical and layer mode. - public PaletteEntry[] FrontLayer; - - /// Blocks in the back, used only in two-layer vertical mode. - public PaletteEntry[] BackLayer; - - public ImagePalette(string name, PaletteEntry[] front, PaletteEntry[] back) { - Name = name; FrontLayer = front; BackLayer = back; - } + /// Block mapping in this paleete. + public PaletteEntry[] Entries; + public ImagePalette(string name, PaletteEntry[] entries) { + Name = name; Entries = entries; + } /// All supported palettes. public static List Palettes = new List(); @@ -50,12 +46,13 @@ namespace MCGalaxy.Drawing { return null; } + public static void Load() { Palettes.Clear(); - Palettes.Add(new ImagePalette("Color", Color_Front, Color_Back)); - Palettes.Add(new ImagePalette("Grayscale", Grayscale_Front, Grayscale_Back)); - Palettes.Add(new ImagePalette("BlackWhite", BlackWhite_Front, null)); - Palettes.Add(new ImagePalette("SimpleGrayscale", Grayscale_Mathematical, null)); + Palettes.Add(new ImagePalette("Color", Color)); + Palettes.Add(new ImagePalette("Grayscale", Grayscale)); + Palettes.Add(new ImagePalette("BlackWhite", BlackWhite)); + Palettes.Add(new ImagePalette("SimpleGrayscale", GrayscaleSimple)); if (!Directory.Exists("extra/palettes")) Directory.CreateDirectory("extra/palettes"); @@ -68,54 +65,42 @@ namespace MCGalaxy.Drawing { string name = Path.GetFileNameWithoutExtension(file); ImagePalette palette = Find(name); if (palette != null) Palettes.Remove(palette); - palette = new ImagePalette(name, null, null); - + string[] lines = File.ReadAllLines(file); - List front = new List(); - List back = new List(); + List entries = new List(); foreach (string line in lines) { + Server.s.Log(line); if (line.StartsWith("#") || line.Length == 0) continue; string[] parts = line.Split(':'); - if (parts.Length != 5) continue; - - if (parts[0].CaselessEq("front")) { - front.Add(ParseEntry(parts)); - } else if (parts[0].CaselessEq("back")) { - back.Add(ParseEntry(parts)); - } + if (parts.Length != 4) continue; + entries.Add(ParseEntry(parts)); } - - palette.FrontLayer = front.ToArray(); - if (back.Count > 0) palette.BackLayer = back.ToArray(); + + palette = new ImagePalette(name, entries.ToArray()); Palettes.Add(palette); } static PaletteEntry ParseEntry(string[] parts) { - byte r = byte.Parse(parts[4]), g = byte.Parse(parts[3]); - byte b = byte.Parse(parts[2]), block = byte.Parse(parts[1]); + byte r = byte.Parse(parts[3]), g = byte.Parse(parts[2]); + byte b = byte.Parse(parts[1]), block = byte.Parse(parts[0]); return new PaletteEntry(r, g, b, block); } - public static void SavePalette(ImagePalette palette) { - using (StreamWriter w = new StreamWriter(palette.FileName)) { + + public void Save() { + using (StreamWriter w = new StreamWriter(FileName)) { w.WriteLine("#Line layout - type:block:red:green:blue"); - if (palette.FrontLayer != null) { - foreach (PaletteEntry e in palette.FrontLayer) - w.WriteLine("front:" + e.Block + ":" + e.R + ":" + e.G + ":" + e.B); - } - - if (palette.BackLayer != null) { - foreach (PaletteEntry e in palette.BackLayer) - w.WriteLine("back:" + e.Block + ":" + e.R + ":" + e.G + ":" + e.B); - } + if (Entries == null) return; + foreach (PaletteEntry e in Entries) + w.WriteLine(e.Block + ":" + e.R + ":" + e.G + ":" + e.B); } } public static void Add(string name) { - ImagePalette palette = new ImagePalette(name, null, null); + ImagePalette palette = new ImagePalette(name, null); Palettes.Add(palette); using (File.Create(palette.FileName)) { } } @@ -127,7 +112,7 @@ namespace MCGalaxy.Drawing { } - static PaletteEntry[] Color_Front = { + static PaletteEntry[] Color = { new PaletteEntry(128, 86, 57, Block.dirt), new PaletteEntry(162, 129, 75, Block.wood), new PaletteEntry(244, 237, 174, Block.sand), @@ -149,60 +134,23 @@ namespace MCGalaxy.Drawing { new PaletteEntry(230, 240, 225, Block.white), new PaletteEntry(163, 163, 163, Block.staircasefull), new PaletteEntry(0, 0, 0, Block.obsidian), - }; - /*Turns out the back layer blocks are handled awfully. - new PaletteEntry(217, 131, 155, 55), - new PaletteEntry(56, 77, 24, 56), - new PaletteEntry(86, 51, 28, 57), - new PaletteEntry(39, 51, 154, 58), - new PaletteEntry(39, 117, 149, 59),*/ - - static PaletteEntry[] Color_Back = { - new PaletteEntry(57, 38, 25, Block.dirt), - new PaletteEntry(72, 57, 33, Block.wood), - new PaletteEntry(109, 105, 77, Block.sand), - new PaletteEntry(41, 31, 16, Block.trunk), - new PaletteEntry(101, 13, 16, Block.red), - new PaletteEntry(99, 60, 16, Block.orange), - new PaletteEntry(102, 107, 11, Block.yellow), - new PaletteEntry(56, 104, 11, Block.lightgreen), - new PaletteEntry(11, 104, 8, Block.green), - new PaletteEntry(13, 104, 54, Block.aquagreen), - new PaletteEntry(12, 106, 100, Block.cyan), - new PaletteEntry(44, 74, 101, Block.lightblue), - new PaletteEntry(49, 55, 105, Block.blue), - new PaletteEntry(56, 15, 97, Block.purple), - new PaletteEntry(75, 31, 97, Block.lightpurple), - new PaletteEntry(101, 17, 100, Block.pink), - new PaletteEntry(104, 17, 54, Block.darkpink), - new PaletteEntry(20, 30, 21, Block.darkgrey), - new PaletteEntry(60, 64, 58, Block.lightgrey), - new PaletteEntry(102, 107, 100, Block.white), - new PaletteEntry(0, 0, 0, Block.obsidian), - }; + }; - static PaletteEntry[] Grayscale_Front = { + static PaletteEntry[] Grayscale = { new PaletteEntry(0, 0, 0, Block.obsidian), new PaletteEntry(46, 68, 47, Block.darkgrey), new PaletteEntry(135, 145, 130, Block.lightgrey), new PaletteEntry(230, 240, 225, Block.white), }; - static PaletteEntry[] Grayscale_Back = { - new PaletteEntry(0, 0, 0, Block.obsidian), - new PaletteEntry(20, 30, 21, Block.darkgrey), - new PaletteEntry(60, 64, 58, Block.lightgrey), - new PaletteEntry(102, 107, 100, Block.white), - }; - - static PaletteEntry[] Grayscale_Mathematical = { + static PaletteEntry[] GrayscaleSimple = { new PaletteEntry(32, 32, 32, Block.obsidian), new PaletteEntry(96, 96, 96, Block.darkgrey), new PaletteEntry(160, 160, 160, Block.lightgrey), new PaletteEntry(224, 224, 224, Block.white), }; - static PaletteEntry[] BlackWhite_Front = { + static PaletteEntry[] BlackWhite = { new PaletteEntry(255, 255, 255, Block.white), new PaletteEntry(0, 0, 0, Block.obsidian), }; diff --git a/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs b/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs index 86fb92e6c..503a43a58 100644 --- a/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs +++ b/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs @@ -44,7 +44,7 @@ namespace MCGalaxy.Drawing.Ops { CalcState(Direction); selector = new RgbPaletteMatcher(); - selector.SetPalette(Palette); + CalcLayerColors(); using (PixelGetter getter = new PixelGetter(Source)) { getter.Init(); @@ -58,6 +58,34 @@ namespace MCGalaxy.Drawing.Ops { Player.Message(Player, "Finished printing image using {0} palette.", Palette.Name); } + void CalcLayerColors() { + PaletteEntry[] front = new PaletteEntry[Palette.Entries.Length]; + PaletteEntry[] back = new PaletteEntry[Palette.Entries.Length]; + + CustomColor sun = Colors.ParseHex("FFFFFF"); + CustomColor dark = Colors.ParseHex("9B9B9B"); + if (Utils.IsValidHex(Level.LightColor)) { + sun = Colors.ParseHex(Level.LightColor); + } + if (Utils.IsValidHex(Level.ShadowColor)) { + dark = Colors.ParseHex(Level.ShadowColor); + } + + for (int i = 0; i < Palette.Entries.Length; i++) { + PaletteEntry entry = Palette.Entries[i]; + front[i] = Multiply(entry, sun); + back[i] = Multiply(entry, dark); + } + selector.SetPalette(front, back); + } + + static PaletteEntry Multiply(PaletteEntry entry, CustomColor rgb) { + entry.R = (byte)(entry.R * rgb.R / 255); + entry.G = (byte)(entry.G * rgb.G / 255); + entry.B = (byte)(entry.B * rgb.B / 255); + return entry; + } + void OutputPixel(Pixel P, Action output) { ushort x = (ushort)(Origin.X + dx.X * P.X + dy.X * P.Y); ushort y = (ushort)(Origin.Y + dx.Y * P.X + dy.Y * P.Y); @@ -83,7 +111,7 @@ namespace MCGalaxy.Drawing.Ops { void CalcState(int dir) { dx = default(Vec3S32); dy = default(Vec3S32); adj = default(Vec3S32); - DualLayer = DualLayer && !LayerMode && Palette.BackLayer != null; + DualLayer = DualLayer && !LayerMode; // Calculate back layer offset if (dir == 0) adj.Z = -1; diff --git a/MCGalaxy/util/Utils.cs b/MCGalaxy/util/Utils.cs index 31ef4a7f5..c2a5551c3 100644 --- a/MCGalaxy/util/Utils.cs +++ b/MCGalaxy/util/Utils.cs @@ -34,7 +34,7 @@ namespace MCGalaxy { return true; } - static bool IsValidHex(string hex) { + public static bool IsValidHex(string hex) { for (int i = 0; i < hex.Length; i++) { if (!Colors.IsStandardColor(hex[i])) return false; }