mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-23 04:32:50 -04:00
Now /imgprint auto calculates shading of layers
This commit is contained in:
parent
d325a7c087
commit
9595629d0a
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user