Now /imgprint auto calculates shading of layers

This commit is contained in:
UnknownShadow200 2017-02-19 14:51:42 +11:00
parent d325a7c087
commit 9595629d0a
6 changed files with 162 additions and 107 deletions

View File

@ -60,8 +60,8 @@ namespace MCGalaxy.Commands.Building {
Player.Message(p, "Palette {0} not found.", parts[1]); return; Player.Message(p, "Palette {0} not found.", parts[1]); return;
} }
if (dArgs.palette.FrontLayer == null || dArgs.palette.FrontLayer.Length == 0) { if (dArgs.palette.Entries == null || dArgs.palette.Entries.Length == 0) {
Player.Message(p, "Palette {0} does not have any entries"); 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; Player.Message(p, "Use %T/palette %Sto add entries to it"); return;
} }
} }

View File

@ -16,6 +16,7 @@
permissions and limitations under the Licenses. permissions and limitations under the Licenses.
*/ */
using System; using System;
using System.Collections.Generic;
using MCGalaxy.Drawing; using MCGalaxy.Drawing;
namespace MCGalaxy.Commands.Building { namespace MCGalaxy.Commands.Building {
@ -27,7 +28,7 @@ namespace MCGalaxy.Commands.Building {
public override LevelPermission defaultRank { get { return LevelPermission.Admin; } } public override LevelPermission defaultRank { get { return LevelPermission.Admin; } }
public override void Use(Player p, string message) { public override void Use(Player p, string message) {
string[] args = message.SplitSpaces(4); string[] args = message.SplitSpaces(5);
if (message == "") { Help(p); return; } if (message == "") { Help(p); return; }
if (args[0].CaselessEq("create")) { if (args[0].CaselessEq("create")) {
@ -35,9 +36,9 @@ namespace MCGalaxy.Commands.Building {
} else if (args[0].CaselessEq("delete")) { } else if (args[0].CaselessEq("delete")) {
HandleDelete(p, args); HandleDelete(p, args);
} else if (args[0].CaselessEq("add")) { } else if (args[0].CaselessEq("add")) {
Player.Message(p, "?????"); HandleAdd(p, args);
} else if (args[0].CaselessEq("remove")) { } 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<PaletteEntry> newEntries = new List<PaletteEntry>();
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<PaletteEntry> newEntries = new List<PaletteEntry>();
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) { public override void Help(Player p) {
Player.Message(p, "%T/palette create/delete [name]"); Player.Message(p, "%T/palette create/delete [name]");
Player.Message(p, "%HCreates or deletes a palette for %T/imageprint"); Player.Message(p, "%HCreates or deletes a palette for %T/imageprint");
Player.Message(p, "%T/palette add [name] [block] [hex color] <back>"); Player.Message(p, "%T/palette add [name] [block] [hex color]");
Player.Message(p, "???"); Player.Message(p, "%HAdds a block to a palette's entries.");
Player.Message(p, "%T/palette remove [name] [block]"); 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)); Player.Message(p, "%HPalettes: &f{0}", ImagePalette.Palettes.Join(pal => pal.Name));
} }
} }

View File

@ -23,7 +23,7 @@ namespace MCGalaxy.Drawing {
public interface IPaletteMatcher { public interface IPaletteMatcher {
/// <summary> Sets the palette of blocks used to match colours from. </summary> /// <summary> Sets the palette of blocks used to match colours from. </summary>
void SetPalette(ImagePalette palette); void SetPalette(PaletteEntry[] front, PaletteEntry[] back);
/// <summary> Returns the best matching block for the given color, /// <summary> Returns the best matching block for the given color,
/// based on this palette's colourspace. </summary> /// based on this palette's colourspace. </summary>
@ -36,24 +36,24 @@ namespace MCGalaxy.Drawing {
public sealed class RgbPaletteMatcher : IPaletteMatcher { public sealed class RgbPaletteMatcher : IPaletteMatcher {
ImagePalette palette; PaletteEntry[] front, back;
public void SetPalette(ImagePalette palette) { public void SetPalette(PaletteEntry[] front, PaletteEntry[] back) {
this.palette = palette; this.front = front; this.back = back;
} }
public byte BestMatch(byte R, byte G, byte B) { public byte BestMatch(byte R, byte G, byte B) {
int pos; int pos;
MinDist(R, G, B, palette.FrontLayer, out pos); MinDist(R, G, B, front, out pos);
return palette.FrontLayer[pos].Block; return front[pos].Block;
} }
public byte BestMatch(byte R, byte G, byte B, out bool backLayer) { public byte BestMatch(byte R, byte G, byte B, out bool backLayer) {
int frontPos, backPos; int frontPos, backPos;
int frontDist = MinDist(R, G, B, palette.FrontLayer, out frontPos); int frontDist = MinDist(R, G, B, front, out frontPos);
int backDist = MinDist(R, G, B, palette.BackLayer, out backPos); int backDist = MinDist(R, G, B, back, out backPos);
backLayer = backDist <= frontDist; 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 { public sealed class LabPaletteMatcher : IPaletteMatcher {
LabColor[] palette; LabColor[] palette;
public void SetPalette(ImagePalette palette) { public void SetPalette(PaletteEntry[] front, PaletteEntry[] back) {
this.palette = new LabColor[palette.FrontLayer.Length]; this.palette = new LabColor[front.Length];
for (int i = 0; i < palette.FrontLayer.Length; i++) for (int i = 0; i < front.Length; i++)
this.palette[i] = RgbToLab(palette.FrontLayer[i]); this.palette[i] = RgbToLab(front[i]);
} }
public byte BestMatch(byte R, byte G, byte B) { public byte BestMatch(byte R, byte G, byte B) {

View File

@ -29,16 +29,12 @@ namespace MCGalaxy.Drawing {
/// <summary> Relative file path on disc. </summary> /// <summary> Relative file path on disc. </summary>
public string FileName { get { return "extra/palettes/" + Name + ".pal"; } } public string FileName { get { return "extra/palettes/" + Name + ".pal"; } }
/// <summary> Blocks in the front, used in vertical and layer mode. </summary> /// <summary> Block mapping in this paleete. </summary>
public PaletteEntry[] FrontLayer; public PaletteEntry[] Entries;
/// <summary> Blocks in the back, used only in two-layer vertical mode. </summary>
public PaletteEntry[] BackLayer;
public ImagePalette(string name, PaletteEntry[] front, PaletteEntry[] back) {
Name = name; FrontLayer = front; BackLayer = back;
}
public ImagePalette(string name, PaletteEntry[] entries) {
Name = name; Entries = entries;
}
/// <summary> All supported palettes. </summary> /// <summary> All supported palettes. </summary>
public static List<ImagePalette> Palettes = new List<ImagePalette>(); public static List<ImagePalette> Palettes = new List<ImagePalette>();
@ -50,12 +46,13 @@ namespace MCGalaxy.Drawing {
return null; return null;
} }
public static void Load() { public static void Load() {
Palettes.Clear(); Palettes.Clear();
Palettes.Add(new ImagePalette("Color", Color_Front, Color_Back)); Palettes.Add(new ImagePalette("Color", Color));
Palettes.Add(new ImagePalette("Grayscale", Grayscale_Front, Grayscale_Back)); Palettes.Add(new ImagePalette("Grayscale", Grayscale));
Palettes.Add(new ImagePalette("BlackWhite", BlackWhite_Front, null)); Palettes.Add(new ImagePalette("BlackWhite", BlackWhite));
Palettes.Add(new ImagePalette("SimpleGrayscale", Grayscale_Mathematical, null)); Palettes.Add(new ImagePalette("SimpleGrayscale", GrayscaleSimple));
if (!Directory.Exists("extra/palettes")) if (!Directory.Exists("extra/palettes"))
Directory.CreateDirectory("extra/palettes"); Directory.CreateDirectory("extra/palettes");
@ -68,54 +65,42 @@ namespace MCGalaxy.Drawing {
string name = Path.GetFileNameWithoutExtension(file); string name = Path.GetFileNameWithoutExtension(file);
ImagePalette palette = Find(name); ImagePalette palette = Find(name);
if (palette != null) Palettes.Remove(palette); if (palette != null) Palettes.Remove(palette);
palette = new ImagePalette(name, null, null);
string[] lines = File.ReadAllLines(file); string[] lines = File.ReadAllLines(file);
List<PaletteEntry> front = new List<PaletteEntry>(); List<PaletteEntry> entries = new List<PaletteEntry>();
List<PaletteEntry> back = new List<PaletteEntry>();
foreach (string line in lines) { foreach (string line in lines) {
Server.s.Log(line);
if (line.StartsWith("#") || line.Length == 0) continue; if (line.StartsWith("#") || line.Length == 0) continue;
string[] parts = line.Split(':'); string[] parts = line.Split(':');
if (parts.Length != 5) continue; if (parts.Length != 4) continue;
entries.Add(ParseEntry(parts));
if (parts[0].CaselessEq("front")) {
front.Add(ParseEntry(parts));
} else if (parts[0].CaselessEq("back")) {
back.Add(ParseEntry(parts));
}
} }
palette.FrontLayer = front.ToArray(); palette = new ImagePalette(name, entries.ToArray());
if (back.Count > 0) palette.BackLayer = back.ToArray();
Palettes.Add(palette); Palettes.Add(palette);
} }
static PaletteEntry ParseEntry(string[] parts) { static PaletteEntry ParseEntry(string[] parts) {
byte r = byte.Parse(parts[4]), g = byte.Parse(parts[3]); byte r = byte.Parse(parts[3]), g = byte.Parse(parts[2]);
byte b = byte.Parse(parts[2]), block = byte.Parse(parts[1]); byte b = byte.Parse(parts[1]), block = byte.Parse(parts[0]);
return new PaletteEntry(r, g, b, block); 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"); w.WriteLine("#Line layout - type:block:red:green:blue");
if (palette.FrontLayer != null) { if (Entries == null) return;
foreach (PaletteEntry e in palette.FrontLayer) foreach (PaletteEntry e in Entries)
w.WriteLine("front:" + e.Block + ":" + e.R + ":" + e.G + ":" + e.B); w.WriteLine(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);
}
} }
} }
public static void Add(string name) { public static void Add(string name) {
ImagePalette palette = new ImagePalette(name, null, null); ImagePalette palette = new ImagePalette(name, null);
Palettes.Add(palette); Palettes.Add(palette);
using (File.Create(palette.FileName)) { } 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(128, 86, 57, Block.dirt),
new PaletteEntry(162, 129, 75, Block.wood), new PaletteEntry(162, 129, 75, Block.wood),
new PaletteEntry(244, 237, 174, Block.sand), new PaletteEntry(244, 237, 174, Block.sand),
@ -149,60 +134,23 @@ namespace MCGalaxy.Drawing {
new PaletteEntry(230, 240, 225, Block.white), new PaletteEntry(230, 240, 225, Block.white),
new PaletteEntry(163, 163, 163, Block.staircasefull), new PaletteEntry(163, 163, 163, Block.staircasefull),
new PaletteEntry(0, 0, 0, Block.obsidian), 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(0, 0, 0, Block.obsidian),
new PaletteEntry(46, 68, 47, Block.darkgrey), new PaletteEntry(46, 68, 47, Block.darkgrey),
new PaletteEntry(135, 145, 130, Block.lightgrey), new PaletteEntry(135, 145, 130, Block.lightgrey),
new PaletteEntry(230, 240, 225, Block.white), new PaletteEntry(230, 240, 225, Block.white),
}; };
static PaletteEntry[] Grayscale_Back = { static PaletteEntry[] GrayscaleSimple = {
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 = {
new PaletteEntry(32, 32, 32, Block.obsidian), new PaletteEntry(32, 32, 32, Block.obsidian),
new PaletteEntry(96, 96, 96, Block.darkgrey), new PaletteEntry(96, 96, 96, Block.darkgrey),
new PaletteEntry(160, 160, 160, Block.lightgrey), new PaletteEntry(160, 160, 160, Block.lightgrey),
new PaletteEntry(224, 224, 224, Block.white), new PaletteEntry(224, 224, 224, Block.white),
}; };
static PaletteEntry[] BlackWhite_Front = { static PaletteEntry[] BlackWhite = {
new PaletteEntry(255, 255, 255, Block.white), new PaletteEntry(255, 255, 255, Block.white),
new PaletteEntry(0, 0, 0, Block.obsidian), new PaletteEntry(0, 0, 0, Block.obsidian),
}; };

View File

@ -44,7 +44,7 @@ namespace MCGalaxy.Drawing.Ops {
CalcState(Direction); CalcState(Direction);
selector = new RgbPaletteMatcher(); selector = new RgbPaletteMatcher();
selector.SetPalette(Palette); CalcLayerColors();
using (PixelGetter getter = new PixelGetter(Source)) { using (PixelGetter getter = new PixelGetter(Source)) {
getter.Init(); getter.Init();
@ -58,6 +58,34 @@ namespace MCGalaxy.Drawing.Ops {
Player.Message(Player, "Finished printing image using {0} palette.", Palette.Name); 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<DrawOpBlock> output) { void OutputPixel(Pixel P, Action<DrawOpBlock> output) {
ushort x = (ushort)(Origin.X + dx.X * P.X + dy.X * P.Y); 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); 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) { void CalcState(int dir) {
dx = default(Vec3S32); dy = default(Vec3S32); adj = default(Vec3S32); dx = default(Vec3S32); dy = default(Vec3S32); adj = default(Vec3S32);
DualLayer = DualLayer && !LayerMode && Palette.BackLayer != null; DualLayer = DualLayer && !LayerMode;
// Calculate back layer offset // Calculate back layer offset
if (dir == 0) adj.Z = -1; if (dir == 0) adj.Z = -1;

View File

@ -34,7 +34,7 @@ namespace MCGalaxy {
return true; return true;
} }
static bool IsValidHex(string hex) { public static bool IsValidHex(string hex) {
for (int i = 0; i < hex.Length; i++) { for (int i = 0; i < hex.Length; i++) {
if (!Colors.IsStandardColor(hex[i])) return false; if (!Colors.IsStandardColor(hex[i])) return false;
} }