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;
}
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;
}
}

View File

@ -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<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) {
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] <back>");
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));
}
}

View File

@ -23,7 +23,7 @@ namespace MCGalaxy.Drawing {
public interface IPaletteMatcher {
/// <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,
/// based on this palette's colourspace. </summary>
@ -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) {

View File

@ -29,16 +29,12 @@ namespace MCGalaxy.Drawing {
/// <summary> Relative file path on disc. </summary>
public string FileName { get { return "extra/palettes/" + Name + ".pal"; } }
/// <summary> Blocks in the front, used in vertical and layer mode. </summary>
public PaletteEntry[] FrontLayer;
/// <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;
}
/// <summary> Block mapping in this paleete. </summary>
public PaletteEntry[] Entries;
public ImagePalette(string name, PaletteEntry[] entries) {
Name = name; Entries = entries;
}
/// <summary> All supported palettes. </summary>
public static List<ImagePalette> Palettes = new List<ImagePalette>();
@ -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<PaletteEntry> front = new List<PaletteEntry>();
List<PaletteEntry> back = new List<PaletteEntry>();
List<PaletteEntry> entries = new List<PaletteEntry>();
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),
};

View File

@ -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<DrawOpBlock> 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;

View File

@ -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;
}