Read back blueprint images

This commit is contained in:
bzt 2019-12-15 17:58:16 +01:00
parent a4f3ec14b7
commit c36e2ea891
16 changed files with 231 additions and 56 deletions

View File

@ -8,7 +8,7 @@ See also the [GUI usage](https://gitlab.com/bztsrc/mtsedit/blob/master/docs/usag
``` ```
MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license
./mtsedit [-h] [-v] [-l lang] [-d|-p|-P|-b] [-m map] <.mts|.schematic> [out.mts] ./mtsedit [-h] [-v] [-l lang] [-d|-p|-P|-b|-B] [-m map] <.mts|.schematic> [out.mts]
./mtsedit -g <block.png> ./mtsedit -g <block.png>
./mtsedit -t <blockimgs.csv> [blockid] ./mtsedit -t <blockimgs.csv> [blockid]
./mtsedit -i [Minetest mods dir] ./mtsedit -i [Minetest mods dir]
@ -18,7 +18,7 @@ MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license
-d: dump layers to output -d: dump layers to output
-p: save preview -p: save preview
-P: save preview, cut structure in half -P: save preview, cut structure in half
-b: save blueprint -b, -B: save blueprint
-m map: replace block type mapping -m map: replace block type mapping
-g: generate slab and stairs from block image -g: generate slab and stairs from block image
-t: generate block images from texture data -t: generate block images from texture data
@ -38,15 +38,17 @@ This will print out mapping and each block as hex values layer by layer.
./mtsedit -d structure.mts ./mtsedit -d structure.mts
``` ```
### Generate blueprint ### Generate Blueprint
Pretty much the same as dump, but instead of dumping the MTS to the console, it saves "structure_bp.png". Pretty much the same as dump, but instead of dumping the MTS to the console, it saves "structure_bp.png".
``` ```
./mtsedit -b structure.mts ./mtsedit -b structure.mts
``` ```
Each layer will be padded by 1 x 1 pixels of transparency. On the left, there's a black pixel after each layer so Each layer will be padded by 1 x 1 pixels of transparency. On the left, there's a black pixel at each layer start so
that programs can detect the dimensions from the image. On the right, there's a red line for the ground layer. that programs can detect the dimensions from the image. On the right, there's a red line for the ground layer.
The `-b` flag will also save a blue background and block legend on the image. `-B` only saves the raw blueprint.
### Conversion (or Remap) ### Conversion (or Remap)
You can convert Minecraft NBT Schematics with this tool. You can convert Minecraft NBT Schematics with this tool.

23
docs/import.md Normal file
View File

@ -0,0 +1,23 @@
Import File Formats
===================
This document describes the format that MTSEdit can import schematics from. For the native format, that can be written too, see
the [MTS format](https://gitlab.com/bztsrc/mtsedit/blob/master/docs/mts_format.md).
Schematic
---------
These are [Minecraft NBT](https://minecraft.gamepedia.com/Schematic_file_format) files, used by many Minecraft-compatible
editors. Only the [blocks](https://minecraft.gamepedia.com/Java_Edition_data_values/Pre-flattening/Block_IDs) section is parsed,
and only used to import schematics. MTSEdit does not save .schematic files.
Limitations: rotation info are not imported properly, but works for basic nodes most of the time.
Blueprint PNG
-------------
MTSEdit is capable to save schematic blueprints to PNG files using the `-b` or `-B` flags. These can be imported too.
If blueprint is not detected on the image, then the entire image is read as a one layer blueprint finding the blocks that
are closest match in color to each pixel.
Limitations: rotation info is not stored in blueprint images at all.

View File

@ -1,12 +1,8 @@
File Formats MTS File Format
============ ===============
Schematic This document describes the MTS format native to MTSEdit and the Minetest Engine. For other formats that are supported
--------- by MTSEdit to import schematics, see [import formats](https://gitlab.com/bztsrc/mtsedit/blob/master/docs/import.md).
These are [Minecraft NBT](https://minecraft.gamepedia.com/Schematic_file_format) files, used by many Minecraft-compatible
editors. Only the [blocks](https://minecraft.gamepedia.com/Java_Edition_data_values/Pre-flattening/Block_IDs) section is parsed,
and only used to import schematics. MTSEdit does not save .schematic files.
MTS MTS
--- ---

View File

@ -117,6 +117,7 @@ Main editor window:
| <kbd>P</kbd> | save preview PNG | | <kbd>P</kbd> | save preview PNG |
| <kbd>Shift</kbd> + <kbd>P</kbd> | save preview with structure cut in half | | <kbd>Shift</kbd> + <kbd>P</kbd> | save preview with structure cut in half |
| <kbd>E</kbd> | export blueprint PNG | | <kbd>E</kbd> | export blueprint PNG |
| <kbd>Shift</kbd> + <kbd>E</kbd> | export plain blueprint without legend |
| <kbd>R</kbd> | change orientation, rotate entire structure CCW | | <kbd>R</kbd> | change orientation, rotate entire structure CCW |
| <kbd>Shift</kbd> + <kbd>R</kbd> | change orientation, rotate entire structure CW | | <kbd>Shift</kbd> + <kbd>R</kbd> | change orientation, rotate entire structure CW |
| <kbd>F</kbd> | flip the entire structure along the Z axis | | <kbd>F</kbd> | flip the entire structure along the Z axis |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -41,7 +41,7 @@ endif
endif endif
endif endif
CFLAGS += -Wall -Wextra -ansi -pedantic -D_$(PACKAGE)_=1 CFLAGS += -Wall -Wextra -ansi -pedantic -D_$(PACKAGE)_=1 -g
all: configure data.h $(OBJS) $(TARGET) all: configure data.h $(OBJS) $(TARGET)

View File

@ -244,6 +244,7 @@ void blocks_parse()
sc.img_buffer_end = sc.img_buffer_original_end = img + size; sc.img_buffer_end = sc.img_buffer_original_end = img + size;
ri.bits_per_channel = 8; ri.bits_per_channel = 8;
blocks[j].img = (unsigned char*)stbi__png_load(&sc, &w, &h, &r, 0, &ri); blocks[j].img = (unsigned char*)stbi__png_load(&sc, &w, &h, &r, 0, &ri);
free(img);
if(blocks[j].img) { if(blocks[j].img) {
blocks[j].numpar2 = (h >> 5) & PARAM2_MAX; blocks[j].numpar2 = (h >> 5) & PARAM2_MAX;
if(r != 4) { if(r != 4) {
@ -275,8 +276,16 @@ void blocks_parse()
n++; n++;
} }
} }
if(n) blocks[j].color = 0xFF000000 | (((b/n) & 0xFF) << 16) | (((g/n) & 0xFF) << 8) | ((r/n) & 0xFF); if(n) {
else blocks[j].color = 0xFFFF0000; blocks[j].color = 0xFF000000 | (((b/n) & 0xFF) << 16) | (((g/n) & 0xFF) << 8) | ((r/n) & 0xFF);
while(!is_color_unique(blocks[j].color)) {
img = (unsigned char*)&blocks[j].color;
if(img[1] < 255) img[1]++; /* increase green channel first if we can */
else if(img[0] < 255) img[0]++;
else if(img[2] < 255) img[2]++;
else img[3]--; /* for full white, decrease opacity as last resort */
}
} else blocks[j].color = 0xFFFF0000;
l++; l++;
if(!dx || !dz || (!memcmp(s, "Cobblestone", 11) && s[11] != '_' && s[11] != ' ')) { if(!dx || !dz || (!memcmp(s, "Cobblestone", 11) && s[11] != '_' && s[11] != ' ')) {
detcube(32, 32, blocks[j].img); detcube(32, 32, blocks[j].img);
@ -284,7 +293,6 @@ void blocks_parse()
dz = _y1 - _y0; dz = _y1 - _y0;
} }
} }
free(img);
} }
} }
} }

View File

@ -173,11 +173,11 @@ int main(int argc, char** argv, char** envp)
if(argc < 2) { if(argc < 2) {
usage: printf("MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license\r\n\r\n" usage: printf("MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license\r\n\r\n"
"./mtsedit [-h] [-v] [-l lang] [-d|-p|-P|-b] [-m map] <.mts|.schematic> [out.mts]\r\n" "./mtsedit [-h] [-v] [-l lang] [-d|-p|-P|-b|-B] [-m map] <.mts|.schematic> [out.mts]\r\n"
"./mtsedit -g <block.png>\r\n" "./mtsedit -g <block.png>\r\n"
"./mtsedit -t <blockimgs.csv> [blockid]\r\n" "./mtsedit -t <blockimgs.csv> [blockid]\r\n"
"./mtsedit -i [Minetest mods dir]\r\n" "./mtsedit -i [Minetest mods dir]\r\n"
"\r\n -v: %s\r\n -l lang: %s\r\n -d: %s\r\n -p: %s\r\n -P: %s\r\n -b: %s\r\n -m map: %s\r\n -g: %s\r\n" "\r\n -v: %s\r\n -l lang: %s\r\n -d: %s\r\n -p: %s\r\n -P: %s\r\n -b, -B: %s\r\n -m map: %s\r\n -g: %s\r\n"
" -t: %s\r\n -i: %s\r\n out.mts: %s\r\n", " -t: %s\r\n -i: %s\r\n out.mts: %s\r\n",
lang[INF_VERB], lang[INF_LANG], lang[INF_DUMP], lang[INF_PRE1], lang[INF_PRE2], lang[INF_BPRINT], lang[INF_MAP], lang[INF_VERB], lang[INF_LANG], lang[INF_DUMP], lang[INF_PRE1], lang[INF_PRE2], lang[INF_BPRINT], lang[INF_MAP],
lang[INF_GEN], lang[INF_BLK], lang[INF_MOD], lang[INF_OUT]); lang[INF_GEN], lang[INF_BLK], lang[INF_MOD], lang[INF_OUT]);
@ -192,6 +192,7 @@ usage: printf("MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license
case 'p': opt = 2; break; case 'p': opt = 2; break;
case 'P': opt = 3; break; case 'P': opt = 3; break;
case 'b': opt = 4; break; case 'b': opt = 4; break;
case 'B': opt = 4; shift = 1; break;
case 'g': opt = 5; break; case 'g': opt = 5; break;
case 't': opt = 6; break; case 't': opt = 6; break;
case 'i': opt = 7; break; case 'i': opt = 7; break;
@ -246,10 +247,10 @@ usage: printf("MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license
case 1: ret = mts_dump(); break; case 1: ret = mts_dump(); break;
case 2: case 2:
case 3: ret = mts_view(opt-2); break; case 3: ret = mts_view(opt-2); break;
case 4: ret = mts_blueprint(); break;
case 5: ret = stairgen(); break; case 5: ret = stairgen(); break;
case 6: ret = blockgen(argv[i+1]); break; case 6: ret = blockgen(argv[i+1]); break;
case 7: /* handle this in sdl.c, because extern does not know sizeof() */ case 4: /* handle these in sdl.c, because extern does not know sizeof() */
case 7:
case 0: case 0:
/* start the main user interface */ /* start the main user interface */
ret = sdlmain(opt); ret = sdlmain(opt);

View File

@ -55,6 +55,8 @@
#define THEME_TABBG 8 #define THEME_TABBG 8
#define THEME_SAVEACT 9 #define THEME_SAVEACT 9
#define THEME_SAVEINACT 10 #define THEME_SAVEINACT 10
#define THEME_BP_FG 11
#define THEME_BP_BG 12
#define HIST_EMPTY 0 #define HIST_EMPTY 0
#define HIST_NODE 1 #define HIST_NODE 1
@ -193,20 +195,23 @@ void detcube(int w, int h, unsigned char *block);
int instmod(unsigned char *data, int size); int instmod(unsigned char *data, int size);
int stairgen(); int stairgen();
int blockgen(char *blockid); int blockgen(char *blockid);
int is_color_unique(uint32_t color);
int color2blockid(uint32_t color);
/* blocks.c */ /* blocks.c */
void blocks_getdir(char **argv, char **envp); void blocks_getdir(char **argv, char **envp);
void blocks_parse(); void blocks_parse();
void blocks_free(); void blocks_free();
/* schem.c */ /* schemimp.c */
void schem_load(unsigned char *data, unsigned int size); void schem_load(unsigned char *data, unsigned int size);
void bprint_load(unsigned char *data, unsigned int size);
/* mts.c */ /* mts.c */
void mts_load(unsigned char *data, unsigned int size); void mts_load(unsigned char *data, unsigned int size);
int mts_save(); int mts_save();
int mts_view(int type); int mts_view(int type);
int mts_blueprint(); int mts_blueprint(int type);
int mts_dump(); int mts_dump();
int mts_getbounds(int sanitize, unsigned short *tr, unsigned short *tr2); int mts_getbounds(int sanitize, unsigned short *tr, unsigned short *tr2);
void mts_layerprob(int diff); void mts_layerprob(int diff);

View File

@ -173,7 +173,7 @@ void mts_load(unsigned char *data, unsigned int size)
for(z = 0; z < mts_z; z++) for(z = 0; z < mts_z; z++)
for(x = 0; x < mts_x; x++) for(x = 0; x < mts_x; x++)
if(nodes[y+min_y][z+min_z][x+min_x].param2 == 0x20) { if(nodes[y+min_y][z+min_z][x+min_x].param2 == 0x20) {
gndlayer = currlayer = y+min_y; gndlayer = y+min_y;
nodes[y+min_y][z+min_z][x+min_x].param2 = 0; nodes[y+min_y][z+min_z][x+min_x].param2 = 0;
} }
status = lang[LOADED]; status = lang[LOADED];
@ -414,13 +414,14 @@ int mts_view(int type)
/** /**
* Export a PNG blueprint file * Export a PNG blueprint file
*/ */
int mts_blueprint() int mts_blueprint(int type)
{ {
int i, w, h, x, y, z; int oldsmax = strmaxw, i, j, k, l, bw, w, h, x, y, z;
char pngfile[MAXPATHLEN], *c; char pngfile[MAXPATHLEN], *s, *e, *c;
unsigned char *buff = NULL; unsigned char *buff = NULL;
uint32_t *dst; uint32_t *dst;
SDL_Surface *bprint; SDL_Surface *oldscr = screen;
SDL_Rect rect;
FILE *f; FILE *f;
status = lang[ERR_PREVIEW]; status = lang[ERR_PREVIEW];
@ -428,35 +429,72 @@ int mts_blueprint()
if(mix > max) return 1; if(mix > max) return 1;
bound_valid = 0; bound_valid = 0;
/* calculate dimensions and create images */ strcpy(pngfile, mtsfile);
w = maz - miz + 3; s = strrchr(pngfile, DIRSEP);
h = (may - miy + 1) * (max - mix + 2) + 3; if(!s) s = pngfile; else s++;
bprint = SDL_CreateRGBSurface(0, w, h, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000); e = strrchr(pngfile, '.');
memset(bprint->pixels, 0, w * h * 4); if(!e) e = &pngfile[strlen(pngfile)];
dst = (uint32_t*)bprint->pixels;
/* calculate dimensions and create image */
bw = maz - miz;
h = (may - miy + 1) * (max - mix + 2) + 3;
if(!type) {
for(i = 1, j = l = 0; i < numblocks; i++)
if(blocks[i].numref) {
l += font->height;
k = mbstrlen(blocks[i].name);
if(k > j) j = k;
}
w = bw + 8 + (4 + j) * (font->width + 1);
if(l > h) h = l;
h += font->height + 5;
} else
w = bw + 3;
screen = SDL_CreateRGBSurface(0, w, h, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
memset(screen->pixels, 0, w * h * 4);
dst = (uint32_t*)screen->pixels;
if(!type) {
for(i = 0; i < w * h; i++) dst[i] = theme[THEME_BP_BG];
/* print title */
for(c = s; c < e; c++)
if(*c == '_') *c = ' ';
*e = 0; strmaxw = screen->w - 1;
i = mbstrlen(s) * (font->width+1);
sdlprint((screen->w - (i < screen->w ? i : screen->w)) / 2, 0, THEME_BP_FG, THEME_BP_BG, s);
/* print legend */
rect.x = bw + font->height; rect.y = font->height + 4; rect.w = rect.h = font->height - 2;
for(i = 1; i < numblocks; i++)
if(blocks[i].numref) {
SDL_FillRect(screen, &rect, blocks[i].color);
sdlprint(rect.x + 4 + font->height, rect.y, THEME_BP_FG, THEME_BP_BG, blocks[i].name);
rect.y += font->height;
}
i = w * (font->height + 5);
} else
i = w;
/* generate blueprint into surface */ /* generate blueprint into surface */
for(i = w, y = may; y >= miy; y--, i += w) { for(y = may; y >= miy; y--, i += w) {
dst[i] = (y == gndlayer ? 0xFF0000FF : 0xFF000000);
for(x = mix; x <= max; x++) { for(x = mix; x <= max; x++) {
i++; i++;
for(z = maz; z >= miz; z--, i++) for(z = maz; z >= miz; z--, i++)
if(nodes[y][z][x].param0) dst[i] = (nodes[y][z][x].param0 ? blocks[nodes[y][z][x].param0].color : 0);
dst[i] = blocks[nodes[y][z][x].param0].color;
if(y == gndlayer) if(y == gndlayer)
dst[i] = 0xFF0000FF; dst[i] = 0xFF0000FF;
i++; i += w - bw - 2;
} }
dst[i] = y == gndlayer ? 0xFF0000FF : 0xFF000000;
} }
/* write result to PNG file */ /* write result to PNG file */
buff = (unsigned char *)stbi_write_png_to_mem(bprint->pixels, bprint->pitch, bprint->w, bprint->h, 4, &i); buff = (unsigned char *)stbi_write_png_to_mem(screen->pixels, screen->pitch, screen->w, screen->h, 4, &i);
SDL_FreeSurface(bprint); SDL_FreeSurface(screen);
screen = oldscr;
strmaxw = oldsmax;
if(buff) { if(buff) {
strcpy(pngfile, mtsfile); strcpy(pngfile, mtsfile);
c = strrchr(pngfile, '.'); strcpy(e, "_bp.png");
if(!c) c = &pngfile[strlen(pngfile)];
strcpy(c, "_bp.png");
f = fopen(pngfile,"wb"); f = fopen(pngfile,"wb");
if(f) { if(f) {
fwrite(buff, i, 1, f); fwrite(buff, i, 1, f);

View File

@ -1,5 +1,5 @@
/* /*
* mtsedit/schem.c * mtsedit/schemimp.c
* *
* Copyright (C) 2019 bzt (bztsrc@gitlab) * Copyright (C) 2019 bzt (bztsrc@gitlab)
* *
@ -23,26 +23,24 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
* @brief Import a Minecraft NBT .schematic file * @brief Import various non-MTS formats
* *
*/ */
#include "main.h" #include "main.h"
/* parse an integer, the only type we are interested */
#define SCHEM_GETINT(v,t) do{switch(t){case 1:v=d[0];d++;break;case 2:v=(d[0]<<8)|d[1];d+=2;break; \
case 3:v=(d[0]<<24)|(d[1]<<16)|(d[2]<<8)|d[3];d+=4;break;}}while(0)
/** /**
* Load a Minecraft NBT Schematic file * Load a Minecraft NBT Schematic file
*/ */
/* parse an integer, the only dynamic type we are interested in. */
#define SCHEM_GETINT(v,t) do{switch(t){case 1:v=d[0];d++;break;case 2:v=(d[0]<<8)|d[1];d+=2;break; \
case 3:v=(d[0]<<24)|(d[1]<<16)|(d[2]<<8)|d[3];d+=4;break;}}while(0)
void schem_load(unsigned char *data, unsigned int size) void schem_load(unsigned char *data, unsigned int size)
{ {
int i, j, k, x, y, z, min_x = 0, min_y = 0, min_z = 0; int i, j, k, x, y, z, min_x = 0, min_y = 0, min_z = 0;
unsigned char *d, *blk, *blkd = NULL, *end = data + size; unsigned char *d, *blk, *blkd = NULL, *end = data + size;
/* we don't care about that overcomplicated NBT mess */ /* we don't care about that overcomplicated NBT mess */
mts_y = mts_z = mts_x = 0;
for(d = data; d < end && (!mts_y || !mts_z || !mts_x); d++) { for(d = data; d < end && (!mts_y || !mts_z || !mts_x); d++) {
if(!memcmp(d, "\000\006Height", 8)) { d += 8; SCHEM_GETINT(mts_y, d[-9]); d--; } else if(!memcmp(d, "\000\006Height", 8)) { d += 8; SCHEM_GETINT(mts_y, d[-9]); d--; } else
if(!memcmp(d, "\000\006Length", 8)) { d += 8; SCHEM_GETINT(mts_z, d[-9]); d--; } else if(!memcmp(d, "\000\006Length", 8)) { d += 8; SCHEM_GETINT(mts_z, d[-9]); d--; } else
@ -54,6 +52,7 @@ void schem_load(unsigned char *data, unsigned int size)
min_x = 127 - mts_x / 2; min_x = 127 - mts_x / 2;
min_y = 127 - mts_y / 2; min_y = 127 - mts_y / 2;
min_z = 127 - mts_z / 2; min_z = 127 - mts_z / 2;
gndlayer = min_y;
/* now that we know the dimensions, find the blocks data */ /* now that we know the dimensions, find the blocks data */
for(d = data; d < end; d++) { for(d = data; d < end; d++) {
/* it must be type of byte array */ /* it must be type of byte array */
@ -70,6 +69,7 @@ void schem_load(unsigned char *data, unsigned int size)
for(j = 0; j < 4; j++) for(j = 0; j < 4; j++)
if(blocks[i].blockids[j] == *d) { k = i; i = numblocks; break; } if(blocks[i].blockids[j] == *d) { k = i; i = numblocks; break; }
if(k) { if(k) {
layerprob[y+min_y] = 127;
nodes[y+min_y][z+min_z][x+min_x].param0 = k; nodes[y+min_y][z+min_z][x+min_x].param0 = k;
nodes[y+min_y][z+min_z][x+min_x].param1 = 127; nodes[y+min_y][z+min_z][x+min_x].param1 = 127;
if(blkd) if(blkd)
@ -83,3 +83,62 @@ void schem_load(unsigned char *data, unsigned int size)
} }
} }
} }
/**
* Load a blueprint from a PNG file (or voxelize any other PNG image)
*/
void bprint_load(unsigned char *data, unsigned int size)
{
stbi__context s;
stbi__result_info ri;
int w = 0, h = 0, xs = 1, ys = 0, yg = 0, min_x = 0, min_y = 0, min_z = 0, len, x, y, z;
uint32_t *d;
mts_y = mts_z = mts_x = gndlayer = 0;
s.read_from_callbacks = 0;
s.img_buffer = s.img_buffer_original = data;
s.img_buffer_end = s.img_buffer_original_end = data + size;
ri.bits_per_channel = 8;
d = (uint32_t*)stbi__png_load(&s, &w, &h, &len, 0, &ri);
if(!d || len != 4) return;
/* detect dimensions */
for(y = 0; y < h; y++) {
if(d[y*w] == 0xFF000000 || d[y*w] == 0xFF0000FF) {
if(!mts_y) {
ys = y;
for(mts_z = 1; mts_z + 1 < w - 1 && d[y*w+mts_z+1] != theme[THEME_BP_BG]; mts_z++);
} else if(mts_y == 1) mts_x = y - ys - 1;
if(d[y*w] == 0xFF0000FF) yg = mts_y;
mts_y++;
}
}
if(!mts_x) mts_x = h - ys - 2;
if(!mts_y) { ys = yg = xs = 0; mts_y = 1; mts_z = w; mts_x = h; }
if(mts_x < 1 || mts_y < 1 || mts_z < 1) {
mts_y = mts_z = mts_x = 0;
return;
}
if(mts_y > 255) mts_y = 255;
if(mts_z > 255) mts_z = 255;
if(mts_x > 255) mts_x = 255;
blocks[0].numref -= mts_y * mts_z * mts_x;
min_x = 127 - mts_x / 2;
min_y = 127 + mts_y / 2;
min_z = 127 - mts_z / 2;
gndlayer = min_y - yg;
/* read in the layers */
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x && (y*(mts_x+1)+ys+x) < h; x++)
for(z = 0; z < mts_z; z++) {
nodes[min_y-y][mts_z+min_z-z][x+min_x].param0 = color2blockid(d[(y*(mts_x+1)+ys+x)*w + z + xs]);
if(nodes[min_y-y][mts_z+min_z-z][x+min_x].param0) {
layerprob[min_y-y] = 127;
nodes[min_y-y][mts_z+min_z-z][x+min_x].param1 = 127;
blocks[nodes[min_y-z][mts_z+min_z-z][x+min_x].param0].numref++;
blocks[0].numref--;
}
}
status = lang[LOADED];
}

View File

@ -31,7 +31,7 @@
#include "data.h" #include "data.h"
uint32_t theme[] = { 0xFFF0F0F0, 0xFFF4F4F4, 0xFFBEBEBE, 0xFF808080, 0xFF5C5C5C, 0xFF4C4C4C, 0xFF454545, 0xFF383838, 0xFF303030, uint32_t theme[] = { 0xFFF0F0F0, 0xFFF4F4F4, 0xFFBEBEBE, 0xFF808080, 0xFF5C5C5C, 0xFF4C4C4C, 0xFF454545, 0xFF383838, 0xFF303030,
0xFFC00000, 0xFF800000 }; 0xFFC00000, 0xFF800000, 0xFF7F7F7F, 0xFF3F0000 };
int quitting = 0, activetool = -1, overtool = -1, activeblock = 0, overblock = -1, palette[16], strmaxw, strsepar = 1; int quitting = 0, activetool = -1, overtool = -1, activeblock = 0, overblock = -1, palette[16], strmaxw, strsepar = 1;
int shift = 0, ctrl = 0, help = 0, systemcursor = 0; int shift = 0, ctrl = 0, help = 0, systemcursor = 0;
@ -325,7 +325,7 @@ void sdldo(int opt)
case 9: hist_prepare(HIST_DELZ, cz); mts_delz(cz); hist_commit(); break; case 9: hist_prepare(HIST_DELZ, cz); mts_delz(cz); hist_commit(); break;
case 10: hist_prepare(HIST_ADDX, cx); mts_addx(cx, shift); hist_commit(); break; case 10: hist_prepare(HIST_ADDX, cx); mts_addx(cx, shift); hist_commit(); break;
case 11: hist_prepare(HIST_DELX, cx); mts_delx(cx); hist_commit(); break; case 11: hist_prepare(HIST_DELX, cx); mts_delx(cx); hist_commit(); break;
case 12: mts_blueprint(); break; case 12: mts_blueprint(shift); break;
} }
SDL_SetCursor(pointer); SDL_SetCursor(pointer);
SDL_ShowCursor(0); systemcursor = 0; SDL_ShowCursor(0); systemcursor = 0;
@ -345,13 +345,16 @@ int sdlmain(int opt)
SDL_Event event, lookahead; SDL_Event event, lookahead;
/* this is tricky, because extern wouldn't know sizeof() */ /* this is tricky, because extern wouldn't know sizeof() */
if(opt) return instmod(binary_mtsedit, sizeof(binary_mtsedit)); if(opt == 7) return instmod(binary_mtsedit, sizeof(binary_mtsedit));
/* get our font */ /* get our font */
font = (psf_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)binary_font_psf_gz + 10, font = (psf_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)binary_font_psf_gz + 10,
sizeof(binary_font_psf_gz) - 10, 32768, &len, 0); sizeof(binary_font_psf_gz) - 10, 32768, &len, 0);
if(!font) error(lang[ERR_MEM]); if(!font) error(lang[ERR_MEM]);
/* as an additional dependency, blueprint needs the font */
if(opt) return mts_blueprint(shift);
/* initialize SDL */ /* initialize SDL */
SDL_Init(SDL_INIT_VIDEO); SDL_Init(SDL_INIT_VIDEO);
fn = strrchr(mtsfile, DIRSEP); fn = strrchr(mtsfile, DIRSEP);

View File

@ -81,7 +81,7 @@ void readschem()
if(isdir(mtsfile)) return; if(isdir(mtsfile)) return;
bound_valid = 0; bound_valid = 0;
mts_x = mts_y = mts_z = 0; currlayer = 127; mts_x = mts_y = mts_z = 0;
memset(layerprob, 127, sizeof(layerprob)); memset(layerprob, 127, sizeof(layerprob));
memset(nodes, 0, sizeof(nodes)); memset(nodes, 0, sizeof(nodes));
for(x = 0; x < numblocks; x++) { for(x = 0; x < numblocks; x++) {
@ -90,7 +90,7 @@ void readschem()
} }
blocks[0].numref = 256 * 256 * 256; blocks[0].numref = 256 * 256 * 256;
savepal = savemapgen = savebiome = 0; savepal = savemapgen = savebiome = 0;
currlayer = cx = cz = 127; currlayer = gndlayer = cx = cz = 127;
status = lang[ERR_LOAD]; status = lang[ERR_LOAD];
f = fopen(mtsfile, "rb"); f = fopen(mtsfile, "rb");
@ -121,7 +121,9 @@ void readschem()
/* if it's an MTS file */ /* if it's an MTS file */
if(!memcmp(data, "MTSM", 4)) mts_load(data, size); else if(!memcmp(data, "MTSM", 4)) mts_load(data, size); else
/* Could be a Minecraft NBT */ /* Could be a Minecraft NBT */
if(!memcmp(data + 3, "Schematic", 9)) schem_load(data, size); if(!memcmp(data + 3, "Schematic", 9)) schem_load(data, size); else
/* Blueprint PNG */
if(!memcmp(data, "\x89PNG", 4)) bprint_load(data, size);
/* make sure that all non-air blocks have their probability set */ /* make sure that all non-air blocks have their probability set */
for(y = 0; y < 256; y++) for(y = 0; y < 256; y++)
@ -131,6 +133,7 @@ void readschem()
if(!(nodes[y][z][x].param1 & 0x7F)) nodes[y][z][x].param1 |= 127; if(!(nodes[y][z][x].param1 & 0x7F)) nodes[y][z][x].param1 |= 127;
nodes[y][z][x].param2 &= PARAM2_MAX; nodes[y][z][x].param2 &= PARAM2_MAX;
} }
currlayer = gndlayer;
} }
if(data) free(data); if(data) free(data);
} }
@ -1254,3 +1257,39 @@ int blockgen(char *blockid)
printf("mtsedit: %d PNGs, OK. \r\n", o); printf("mtsedit: %d PNGs, OK. \r\n", o);
return 0; return 0;
} }
/**
* Returns true if color is not used by any blocks
*/
int is_color_unique(uint32_t color)
{
int i;
if(color == 0xFF000000 || color == 0xFFFF0000 || color == theme[THEME_BP_BG]) return 0;
for(i = 1; i < numblocks - 1; i++)
if(blocks[i].color == color) return 0;
return 1;
}
/**
* Returns block id for the closest color match
*/
int color2blockid(uint32_t color)
{
unsigned char *c = (unsigned char*)&color, *d;
int i, j, k, ld, diff = 255;
/* unknown and air blocks */
if(color == 0xFFFF0000 || color == theme[THEME_BP_BG] || c[3] < 128 || (!c[0] && !c[1] && !c[2])) return 0;
for(i = 1, j = 0; i < numblocks; i++) {
/* get local maximum */
ld = 0; d = (unsigned char*)&blocks[i].color;
k = d[0] > c[0] ? d[0] - c[0] : c[0] - d[0]; if(k > ld) ld = k;
k = d[1] > c[1] ? d[1] - c[1] : c[1] - d[1]; if(k > ld) ld = k;
k = d[2] > c[2] ? d[2] - c[2] : c[2] - d[2]; if(k > ld) ld = k;
k = d[3] > c[3] ? d[3] - c[3] : c[3] - d[3]; if(k > ld) ld = k;
/* is it smaller than global minimum? */
if(ld < diff) { diff = ld; j = i; }
}
return j;
}