Code cleanup

master
bzt 2019-11-30 20:19:10 +01:00
parent 94e9271337
commit 7f3383ee28
8 changed files with 971 additions and 841 deletions

322
src/blocks.c Normal file
View File

@ -0,0 +1,322 @@
/*
* mtsedit/blocks.c
*
* Copyright (C) 2019 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* @brief Dealing with the data directory and blocks.csv
*
*/
#include "main.h"
#include <dirent.h>
char *path = NULL, *fn = NULL;
int fncmp(const void *a, const void *b) { return strcmp(*((const char**)a), *((const char**)b)); }
/**
* Get blocks.csv's absolute path
*/
void getblocksdir(char **argv, char **envp)
{
FILE *f;
int i;
char **env = envp;
#ifndef __WIN32__
char *home = NULL;
#endif
/* find our data directory. Environment variable takes preference */
for(env = envp; env && *env; env++) {
if(!memcmp(*env, "MTSDATA=", 8)) {
path = (char*)malloc(strlen(*env)+256);
if(!path) error(lang[ERR_MEM]);
i = strlen(*env)-9;
memcpy(path, *env + 8, i+1);
if(path[i] != DIRSEP) { path[++i] = DIRSEP; i++; }
strcpy(path + i, "blocks.csv");
f = fopen(path, "r");
if(f) { path[i] = 0; fclose(f); }
else { free(path); path = NULL; }
}
#ifndef __WIN32__
if(!memcmp(*env, "HOME=", 5))
home = *env + 5;
#endif
}
#ifndef __WIN32__
/* in user's home */
if(!path && home) {
path = (char*)malloc(strlen(home)+256);
if(!path) error(lang[ERR_MEM]);
i = strlen(home)-1;
memcpy(path, home, i + 1);
if(path[i] != DIRSEP) { path[++i] = DIRSEP; i++; }
/* Linux and BSDs */
strcpy(path + i, ".config/mtsedit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else {
strcpy(path + i, "Library/Application Support/MTSEdit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else { free(path); path = NULL; }
}
}
/* system wide */
if(!path) {
path = (char*)malloc(26+256);
if(!path) error(lang[ERR_MEM]);
strcpy(path, "/usr/share/mtsedit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else {
strcpy(path, "/usr/local/share/mtsedit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else { free(path); path = NULL; }
}
}
#endif
/* same directory as the executable */
if(!path) {
path = (char*)malloc(strlen(argv[0])+256);
if(!path) error(lang[ERR_MEM]);
strcpy(path, argv[0]);
home = strrchr(path, DIRSEP);
if(home) home++; else { sprintf(path, ".%c", DIRSEP); home = path + 2; }
sprintf(home, "data%cblocks.csv", DIRSEP);
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else {
/* last resort, development repository or /opt/mtsedit/bin, data in parent directory */
sprintf(home, "..%cdata%cblocks.csv", DIRSEP, DIRSEP);
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else { free(path); path = NULL; }
}
}
if(!path) error(lang[ERR_DATADIR]);
fn = path + strlen(path);
}
/**
* Parse the blocks.csv
*/
void parseblocks()
{
stbi__context sc;
stbi__result_info ri;
int w, h, l;
unsigned int numfiles = 0, i, j, k;
char **files = NULL, c, *s, *e;
DIR *dir;
struct dirent *de;
unsigned int size;
unsigned char *img;
char *data = (char*)readfile("blocks.csv", &size);
if(!data || !size) error(lang[ERR_CSV]);
/* get block images */
*fn = 0;
dir = opendir(path);
if(dir) {
while((de = readdir(dir))) {
i = strlen(de->d_name);
if(i > 8 && !strcmp(de->d_name + i - 4, ".png") && de->d_name[i-7] == '_') {
j = numfiles++;
files = (char**)realloc(files, numfiles * sizeof(char*));
if(!files) error(lang[ERR_MEM]);
files[j] = (char*)malloc(i + 1);
if(!files[j]) error(lang[ERR_MEM]);
memcpy(files[j], de->d_name, i + 1);
}
}
closedir(dir);
}
qsort(files, numfiles, sizeof(char*), fncmp);
/* parse header */
for(e = data, i = j = 0; *e && *e != '\r' && *e != '\n' && i < 3; e++) {
if(*e == '\"') j ^= 1;
if(!j && (*e == ',' || *e == ';' || *e == '\t')) i++;
}
if(i != 3 || !*e || *e == '\r' || *e == '\n') errorcsv(1);
while(*e && *e != '\r' && *e != '\n') {
while(*e == ',' || *e == ';' || *e == '\t' || *e == ' ') e++;
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
while(*(e-1) <= ' ') e--;
j = numpalettes++;
palettes = (char**)realloc(palettes, numpalettes * sizeof(char*));
if(!palettes) error(lang[ERR_MEM]);
palettes[j] = (char*)malloc(e - s + 1);
if(!palettes[j]) error(lang[ERR_MEM]);
memcpy(palettes[j], s, e - s + 1);
palettes[j][e - s] = 0;
if((int)(e - s) > lenpalettes) lenpalettes = e - s;
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
}
/* add Air as first block */
numblocks++;
blocks = (mtsblock_t*)realloc(blocks, numblocks * sizeof(mtsblock_t));
if(!blocks) error(lang[ERR_MEM]);
memset(&blocks[0], 0, sizeof(mtsblock_t));
blocks[0].name = (char*)malloc(4);
if(!blocks[0].name) error(lang[ERR_MEM]);
memcpy(blocks[0].name, "Air", 4);
blocks[0].blocknames = (char**)malloc((numpalettes + 1) * sizeof(char*));
if(!blocks[0].blocknames) error(lang[ERR_MEM]);
blocks[0].blocknames[0] = NULL;
for(i = 1; i < (unsigned int)numpalettes + 1; i++) {
blocks[0].blocknames[i] = (char*)malloc(4);
if(!blocks[0].blocknames[i]) error(lang[ERR_MEM]);
memcpy(blocks[0].blocknames[i], "air", 4);
}
/* parse rows */
while(*e) {
if(*e == '\r' || *e == '\n') {
while(*e == '\r' || *e == '\n') e++;
if(!*e) break;
/* get canonical name */
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
while(*(e-1) <= ' ') e--;
j = numblocks++;
blocks = (mtsblock_t*)realloc(blocks, numblocks * sizeof(mtsblock_t));
if(!blocks) error(lang[ERR_MEM]);
memset(&blocks[j], 0, sizeof(mtsblock_t));
blocks[j].name = (char*)malloc(e - s + 1);
if(!blocks[j].name) error(lang[ERR_MEM]);
blocks[j].blocknames = (char**)malloc((numpalettes + 1) * sizeof(char*));
if(!blocks[j].blocknames) error(lang[ERR_MEM]);
memset(blocks[j].blocknames, 0, (numpalettes + 1) * sizeof(char*));
for(i = 0; s + i < e; i++) {
blocks[j].name[i] = s[i] == '_' ? ' ' : s[i];
if(s[i] == ' ') s[i] = '_';
}
blocks[j].name[i] = 0;
/* get block images and possible param2 values */
for(i = 0, l = 0; i < numfiles; i++) {
if((int)strlen(files[i]) == (int)(e - s + 7) && !memcmp(files[i], s, e - s)) {
img = readfile(files[i], &size);
if(img && size) {
k = ahtoi(strrchr(files[i], '_') + 1) & 0x1F;
sc.read_from_callbacks = 0;
sc.img_buffer = sc.img_buffer_original = img;
sc.img_buffer_end = sc.img_buffer_original_end = img + size;
ri.bits_per_channel = 8;
blocks[j].img[k] = (unsigned char*)stbi__png_load(&sc, &w, &h, &l, 0, &ri);
if(blocks[j].img[k]) {
l++;
if(!dx || !dz) {
detcube(32, 32, blocks[j].img[k]);
printf("x %d z %d\n",x1-x0,y1-y0);
dx = x1 - x0;
dz = y1 - y0;
}
}
free(img);
}
}
}
if(!l)
fprintf(stderr, "mtsedit: blocks.csv(%d): %s '%s'\r\n", j+1, lang[ERR_IMG], blocks[j].name);
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
while(*e == ' ') e++;
if(*e != ',' && *e != ';' && *e != '\t') errorcsv(j+1);
e++;
while(*e == ' ') e++;
/* get Block IDs */
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
for(i = 0; s < e && i < 8;) {
blocks[j].blockids[i] = atoi(s);
if(blocks[j].blockids[i]) i++;
while(*s >= '0' && *s <= '9') s++;
if(*s == '/') s++;
}
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
k = 0;
}
/* get palette specific names */
while(*e == ' ') e++;
if(*e != ',' && *e != ';' && *e != '\t') errorcsv(j+1);
e++;
while(*e == ' ') e++;
if(!*e) errorcsv(j+1);
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
while(*(e-1) <= ' ') e--;
if(e != s) {
blocks[j].blocknames[k] = (char*)malloc(e - s + 1);
if(!blocks[j].blocknames[k]) error(lang[ERR_MEM]);
memcpy(blocks[j].blocknames[k], s, e - s + 1);
blocks[j].blocknames[k][e - s] = 0;
}
k++; if(k > (unsigned int)numpalettes + 1) errorcsv(j+2);
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
}
if(!numblocks || numblocks > 65535) error(lang[ERR_CSV]);
/* free temp resources */
for(i = 0; i < numfiles; i++) free(files[i]);
free(files);
free(data);
}
/**
* Free resources
*/
void freeblocks()
{
int i, j;
for(i = 0; i < numpalettes; i++) free(palettes[i]);
free(palettes);
for(i = 0; i < numblocks; i++) {
free(blocks[i].name);
if(blocks[i].blocknames) {
for(j = 0; j < numpalettes; j++)
if(blocks[i].blocknames[j]) free(blocks[i].blocknames[j]);
free(blocks[i].blocknames);
}
for(j = 0; j < 32; j++) {
if(blocks[i].img[j]) free(blocks[i].img[j]);
if(blocks[i].dr[j]) free(blocks[i].dr[j]);
if(blocks[i].tr[j]) free(blocks[i].tr[j]);
}
}
free(results);
free(blocks);
}

View File

@ -29,7 +29,19 @@
#include "main.h"
int dx = 13, dz = 8, cx = 127, cz = 127, ox = 0, oy = 0, up = 0;
int dx = 0, dz = 0, cx = 0, cz = 0, ox = 0, oy = 0, up = 0;
/**
* Place a node
*/
void edit_placenode(int y, int z, int x, int i)
{
blocks[nodes[y][z][x].param0].numref--;
blocks[i].numref++;
nodes[y][z][x].param0 = i;
nodes[y][z][x].param1 = i ? 127 : 0;
status = i ? blocks[i].name : NULL;
}
/**
* Redraw the Edit Area
@ -325,6 +337,7 @@ void edit_mouseover(SDL_Event *event)
{
int l, k;
edit_hidecursor();
l = (int)(event->motion.y - (bg->h / 2));
if(l < 0) l -= dz;
l /= dz; l--;
@ -344,6 +357,7 @@ void edit_mouseover(SDL_Event *event)
nodes[currlayer][cz][cx].param1 = k ? 127 : 0;
}
status = nodes[currlayer][cz][cx].param0 ? blocks[nodes[currlayer][cz][cx].param0].name : NULL;
edit_showcursor(event->button.button == 1);
}
/**
@ -351,17 +365,91 @@ void edit_mouseover(SDL_Event *event)
*/
void edit_mousedown(_unused SDL_Event *event)
{
int i;
if(event->button.button != 1)
edit_rotate(currlayer, cz, cx, 1 - shift);
else {
blocks[nodes[currlayer][cz][cx].param0].numref--;
i = palette[activeblock];
blocks[i].numref++;
nodes[currlayer][cz][cx].param0 = i;
nodes[currlayer][cz][cx].param1 = i ? 127 : 0;
status = i ? blocks[i].name : NULL;
edit_placenode(currlayer, cz, cx, palette[activeblock]);
}
}
/**
* Edit Area key event handler
*/
void edit_key(SDL_Event *event)
{
char str[32];
switch (event->key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q: quitting = 1; break;
case SDLK_s: if(!shift) sdldosave(); break;
case SDLK_l: sdldoload(); break;
case SDLK_p: sdldopreview(); break;
case SDLK_r: sdldorotate(1 - shift); break;
case SDLK_g: gndlayer = currlayer; break;
case SDLK_PLUS: case SDLK_EQUALS: mts_layerprob(+1); break;
case SDLK_MINUS: mts_layerprob(-1); break;
case SDLK_PAGEUP: if(currlayer < 255) currlayer++; break;
case SDLK_PAGEDOWN: if(currlayer > 0) currlayer--; break;
case SDLK_BACKQUOTE: case SDLK_0: activeblock = 0; break;
case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: case SDLK_5:
case SDLK_6: case SDLK_7: case SDLK_8: case SDLK_9:
if(palette[event->key.keysym.sym - SDLK_0])
activeblock = event->key.keysym.sym - SDLK_0;
break;
case SDLK_h: dx--; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_k: dx++; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_u: dz--; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_j: dz++; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_UP:
if(ctrl) {
if(oy < 127) oy++;
} else if(shift) {
if(up > -128) up--;
} else {
if(cz > 0) cz--;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_DOWN:
if(ctrl) {
if(oy > -128) oy--;
} else if(shift) {
if(up < 127) up++;
} else {
if(cz < 255) cz++;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_LEFT:
if(ctrl) {
if(ox < 127) ox++;
} else if(shift) {
edit_rotate(currlayer, cz, cx, 1);
} else {
if(cx > 0) cx--;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_RIGHT:
if(ctrl) {
if(ox > -128) ox--;
} else if(shift) {
edit_rotate(currlayer, cz, cx, 0);
} else {
if(cx < 255) cx++;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_BACKSPACE:
case SDLK_DELETE:
case SDLK_SPACE:
edit_placenode(currlayer, cz, cx, event->key.keysym.sym == SDLK_SPACE && !shift ? palette[activeblock] : 0);
break;
}
}

View File

@ -157,30 +157,14 @@ int APIENTRY WinMain(__attribute__((unused)) HINSTANCE hInstance, __attribute__(
}
#endif
/**
* Common error handler
*/
void error(char *msg)
{
#ifdef __WIN32__
MessageBox(NULL, msg, "MTSEdit", MB_ICONEXCLAMATION | MB_OK);
#else
fprintf(stderr, "mtsedit: %s\r\n", msg);
#endif
exit(1);
}
/**
* The real main procedure
*/
int main(int argc, char** argv, char** envp)
{
FILE *f;
int i, j, opt = 0, ret = 0;
char **env = envp, *newmap = NULL;
#ifndef __WIN32__
char *home = NULL;
#endif
char **env, *newmap = NULL;
/* detect the language and load dictionary for it */
for(env = envp; env && *env; env++)
if(!memcmp(*env, "LANG=", 5)) {
@ -192,79 +176,9 @@ int main(int argc, char** argv, char** envp)
}
break;
}
/* get blocks data */
getblocksdir(argv, envp);
/* find our data directory. Environment variable takes preference */
for(env = envp; env && *env; env++) {
if(!memcmp(*env, "MTSDATA=", 8)) {
path = (char*)malloc(strlen(*env)+256);
if(!path) error(lang[ERR_MEM]);
i = strlen(*env)-9;
memcpy(path, *env + 8, i+1);
if(path[i] != DIRSEP) { path[++i] = DIRSEP; i++; }
strcpy(path + i, "blocks.csv");
f = fopen(path, "r");
if(f) { path[i] = 0; fclose(f); }
else { free(path); path = NULL; }
}
#ifndef __WIN32__
if(!memcmp(*env, "HOME=", 5))
home = *env + 5;
#endif
}
#ifndef __WIN32__
/* in user's home */
if(!path && home) {
path = (char*)malloc(strlen(home)+256);
if(!path) error(lang[ERR_MEM]);
i = strlen(home)-1;
memcpy(path, home, i + 1);
if(path[i] != DIRSEP) { path[++i] = DIRSEP; i++; }
/* Linux and BSDs */
strcpy(path + i, ".config/mtsedit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else {
strcpy(path + i, "Library/Application Support/MTSEdit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else { free(path); path = NULL; }
}
}
/* system wide */
if(!path) {
path = (char*)malloc(26+256);
if(!path) error(lang[ERR_MEM]);
strcpy(path, "/usr/share/mtsedit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else {
strcpy(path, "/usr/local/share/mtsedit/blocks.csv");
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else { free(path); path = NULL; }
}
}
#endif
/* same directory as the executable */
if(!path) {
path = (char*)malloc(strlen(argv[0])+256);
if(!path) error(lang[ERR_MEM]);
strcpy(path, argv[0]);
home = strrchr(path, DIRSEP);
if(home) home++; else { sprintf(path, ".%c", DIRSEP); home = path + 2; }
sprintf(home, "data%cblocks.csv", DIRSEP);
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else {
/* last resort, development repository or /opt/mtsedit/bin, data in parent directory */
sprintf(home, "..%cdata%cblocks.csv", DIRSEP, DIRSEP);
f = fopen(path, "r");
if(f) { path[strlen(path)-10] = 0; fclose(f); }
else { free(path); path = NULL; }
}
}
if(!path) error(lang[ERR_DATADIR]);
fn = path + strlen(path);
if(argc < 2) {
printf("MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license\r\n\r\n"
"./mtsedit [-d|-p|-P|-g] [-m map] <.mts|.schematic> [out.mts]\r\n\r\n -d: %s\r\n -p: %s\r\n -P: %s\r\n"
@ -294,7 +208,7 @@ int main(int argc, char** argv, char** envp)
if(argv[i+1] && !opt) opt = 5;
if(opt && opt != 4) {
parseblocks();
mts_load(mtsfile);
readschem();
if(newmap) {
j = atoi(newmap);
if(j) savepal = j - 1;
@ -312,7 +226,7 @@ int main(int argc, char** argv, char** envp)
case 1: ret = mts_dump(); break;
case 2:
case 3: ret = mts_view(opt-2); break;
case 4: ret = mts_stairgen(); break;
case 4: ret = stairgen(); break;
case 5: break;
default:
/* start the main user interface */

View File

@ -99,7 +99,7 @@ typedef struct {
extern int numpalettes, lenpalettes, palette[16], strmaxw, savelen, savepos, savepal, savebiome, numresults, *results;
extern int currlayer, gndlayer, mts_x, mts_y, mts_z, min_x, min_y, min_z, dx, dz, cx, cz, ox, oy, up;
extern int shift, ctrl, activeblock;
extern int shift, ctrl, activeblock, quitting, x0, x1, y0, y1;
extern char **palettes, layerprob[256];
extern int numblocks;
extern mtsblock_t *blocks;
@ -131,37 +131,57 @@ extern unsigned char *tmpblk;
extern SDL_Window *window;
extern SDL_Surface *screen, *icons, *blk, *fg, *bg, *cursor;
/* util.c */
unsigned char *readfile(char *file, unsigned int *size);
void readschem();
void error(char *msg);
void errorcsv(int line);
unsigned char ahtoi(char *s);
void detcube(int w, int h, unsigned char *block);
int stairgen();
void mts_load();
/* blocks.c */
void getblocksdir(char **argv, char **envp);
void parseblocks();
void freeblocks();
/* schem.c */
void schem_load(unsigned char *data, unsigned int size);
/* mts.c */
void mts_load(unsigned char *data, unsigned int size);
int mts_save();
int mts_view(int type);
int mts_dump();
void mts_layerprob(int diff);
void mts_rotate(int ccw);
int mts_stairgen();
void parseblocks();
void freeblocks();
/* sdl.c */
void sdlprint(int x, int y, int fg, int bg, char *s);
void sdldosave();
void sdlredraw();
void sdldosave();
void sdldoload();
void sdldopreview();
void sdldorotate(int ccw);
void sdlmain();
/* edit.c */
void edit_redraw();
void edit_hidecursor();
void edit_showcursor(int painting);
void edit_scroll(SDL_Event *event);
void edit_mouseover(SDL_Event *event);
void edit_mousedown(_unused SDL_Event *event);
void edit_key(SDL_Event *event);
void edit_rotate(int y, int z, int x, int ccw);
/* save.c */
void save_redraw();
void save_scroll(SDL_Event *event);
void save_mousedown(SDL_Event *event);
void save_key(SDL_Event *event);
/* search.c */
void search_redraw();
void search_scroll(SDL_Event *event);
void search_mousedown(SDL_Event *event);

570
src/mts.c
View File

@ -43,194 +43,132 @@ int currlayer = 127, gndlayer = 0;
char layerprob[256];
node_t nodes[256][256][256];
/**
* Load a Minecraft NBT Schematic file
*/
#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)
{
int i, j, k, x, y, z, min_x = 0, min_y = 0, min_z = 0;
unsigned char *d, *end = data + size;
/* generated properties */
int mix = 255, max = 0, miy = 255, may = 0, miz = 255, maz = 0;
/* 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++) {
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\005Width", 7)) { d += 7; SCHEM_GETINT(mts_x, d[-8]); d--; }
}
if(!mts_y || !mts_z || !mts_x || mts_y > 255 || mts_z > 255 || mts_x > 255) { mts_y = mts_z = mts_x = 0; return; }
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;
/* now that we know the dimensions, find the blocks data */
for(d = data; d < end; d++) {
if(!memcmp(d, "\007\000\006Blocks", 9)) {
d += 9;
SCHEM_GETINT(i, 3);
if(i != mts_y * mts_z * mts_x) return;
for(y = 0; y < mts_y; y++)
for(z = 0; z < mts_z; z++)
for(x = 0; x < mts_x; x++, d++) {
if(!*d) continue;
nodes[y+min_y][z+min_z][x+min_x].param1 = 127;
for(i = 1, k = 0; i < numblocks; i++)
for(j = 0; j < 8; j++)
if(blocks[i].blockids[j] == *d) { k = i; i = numblocks; break; }
if(k) {
nodes[y+min_y][z+min_z][x+min_x].param0 = k;
blocks[k].numref++;
} else
fprintf(stderr, "mtsedit: %s: %s %d\r\n", mtsfile, lang[ERR_NODE], *d);
/**
* Get schematic bounding cube and node id translation tables
*/
int mts_getbounds(int sanitize, unsigned short *tr, unsigned short *tr2)
{
int x, y, z, j, k;
/* get boundind box and block ID translation tables, sanitize probability values */
j = 1; mix = 255; max = 0; miy = 255; may = 0; miz = 255; maz = 0;
for(y = 0; y < 256; y++) {
for(z = k = 0; z < 256; z++)
for(x = 0; x < 256; x++) {
if(nodes[y][z][x].param0) {
if(tr && tr2 && !tr2[nodes[y][z][x].param0]) {
tr2[nodes[y][z][x].param0] = j;
tr[j++] = nodes[y][z][x].param0;
}
status = lang[LOADED];
break;
}
if(x < mix) mix = x;
if(x > max) max = x;
if(y < miy) miy = y;
if(y > may) may = y;
if(z < miz) miz = z;
if(z > maz) maz = z;
if(sanitize) {
if(!nodes[y][z][x].param1) nodes[y][z][x].param1 = 127;
if(!layerprob[y]) layerprob[y] = 127;
k = 1;
}
} else if(sanitize)
nodes[y][z][x].param1 = 0;
}
if(sanitize && !k) layerprob[y] = 0;
}
return j;
}
/**
* Load an MTS file
*/
void mts_load()
void mts_load(unsigned char *data, unsigned int size)
{
FILE *f;
unsigned char *data = NULL, *buff = NULL, *un = NULL, *b;
unsigned int size = 0, idx;
unsigned char *buff = NULL, *un = NULL, *b;
unsigned int idx;
int i, j, k, l, n, x, y, z, min_x = 0, min_y = 0, min_z = 0;
unsigned short *tr;
unsigned short *tr = NULL;
status = lang[ERR_LOAD];
mts_x = mts_y = mts_z = 0; currlayer = 127;
memset(layerprob, 127, sizeof(layerprob));
memset(nodes, 0, sizeof(nodes));
for(i = 0; i < numblocks; i++) {
blocks[i].dobiome = 0;
blocks[i].numref = 0;
}
blocks[0].numref = 256 * 256 * 256;
savepal = savebiome = 0;
f = fopen(mtsfile, "rb");
if(f) {
fseek(f, 0L, SEEK_END);
size = (unsigned int)ftell(f);
fseek(f, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
if(!data) error(lang[ERR_MEM]);
fread(data, size, 1, f);
fclose(f);
status = lang[ERR_BADFILE];
/* if it's an MTS file */
if(!memcmp(data, "MTSM", 4)) {
if(!data[4] && (data[5] == 3 || data[5] == 4) && !data[6] && data[7] && !data[8] && data[9] &&
!data[10] && data[11]) {
mts_x = data[7]; mts_y = data[9]; mts_z = data[11];
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;
buff = data + 12;
if(data[5] == 4) {
memcpy(layerprob + min_y, buff, mts_y);
buff += mts_y;
}
n = (buff[0] << 8) | buff[1];
if(n > 0 && n < 1024) {
buff += 2;
tr = (unsigned short*)malloc(n * sizeof(unsigned short));
if(!tr) error(lang[ERR_MEM]);
for(i = 0; i < n; i++) {
tr[i] = numblocks;
j = buff[1];
buff += 2;
for(k = 0; k < numblocks; k++)
for(l = 0; l < numpalettes + 1; l++)
if((!blocks[k].blocknames && l && (int)strlen(blocks[k].name) == j &&
!memcmp(blocks[k].name, buff, j)) || (blocks[k].blocknames && blocks[k].blocknames[l] &&
(int)strlen(blocks[k].blocknames[l]) == j && !memcmp(blocks[k].blocknames[l], buff, j))) {
if(!l && k) { blocks[k].dobiome = 1; savebiome = 1; }
if(l && l - 1 > savepal) savepal = l - 1;
tr[i] = k;
break;
}
if(tr[i] == numblocks) {
x = buff[j]; buff[j] = 0;
fprintf(stderr, "mtsedit: %s: %s %d '%s'\r\n", mtsfile, lang[ERR_NODE], i, buff);
buff[j] = x;
idx = numblocks++;
blocks = (mtsblock_t*)realloc(blocks, numblocks * sizeof(mtsblock_t));
if(!blocks) error(lang[ERR_MEM]);
memset(&blocks[idx], 0, sizeof(mtsblock_t));
blocks[idx].name = (char*)malloc(j + 1);
if(!blocks[idx].name) error(lang[ERR_MEM]);
memcpy(blocks[idx].name, buff, j);
blocks[idx].name[j] = 0;
}
buff += j;
}
size -= (int)(buff - data);
un = (uint8_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)buff, size, 4096, &i, 1);
if(un) { buff = un; size = (unsigned int)i; }
if(4 * mts_x * mts_y * mts_z <= (int)size) {
for(z = 0, b = buff; z < mts_z; z++)
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x; x++, b += 2) {
nodes[y+min_y][z+min_z][x+min_x].param0 = tr[(b[0] << 8) | b[1]];
blocks[nodes[y+min_y][z+min_z][x+min_x].param0].numref++;
}
for(z = 0; z < mts_z; z++)
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x; x++, b++)
nodes[y+min_y][z+min_z][x+min_x].param1 = data[5] == 3 ? b[0] >> 1 : b[0];
for(z = 0; z < mts_z; z++)
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x; x++, b++)
nodes[y+min_y][z+min_z][x+min_x].param2 = b[0];
gndlayer = currlayer = min_y;
for(y = 0; y < mts_y; y++)
for(z = 0; z < mts_z; z++)
for(x = 0; x < mts_x; x++)
if(nodes[y+min_y][z+min_z][x+min_x].param2 == 0x20) {
gndlayer = currlayer = y+min_y;
nodes[y+min_y][z+min_z][x+min_x].param2 = 0;
}
status = lang[LOADED];
} else mts_x = mts_y = mts_z = 0;
free(tr);
if(un) free(un);
} else mts_x = mts_y = mts_z = 0;
buff = NULL;
}
} else {
/* Could be a Minecraft NBT */
if(data[0] == 0x1f && data[1] == 0x8b) {
/* skip over gzip header */
buff = data + 3;
i = *buff++; buff += 6;
if(i & 4) { j = *buff++; j += (*buff++ << 8); buff += j; }
if(i & 8) { while(*buff++ != 0); }
if(i & 16) { while(*buff++ != 0); }
if(i & 2) buff += 2;
size -= (int)(buff - data);
} else buff = data;
buff = (uint8_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)buff, size, 4096, &i, 0);
if(buff) { free(data); data = buff; buff = NULL; size = (unsigned int)i; }
if(!memcmp(data + 3, "Schematic", 9)) schem_load(data, size);
if(!data[4] && (data[5] == 3 || data[5] == 4) && !data[6] && data[7] && !data[8] && data[9] && !data[10] && data[11]) {
mts_x = data[7]; mts_y = data[9]; mts_z = data[11];
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;
buff = data + 12;
if(data[5] == 4) {
memcpy(layerprob + min_y, buff, mts_y);
buff += mts_y;
}
if(!mts_y || !mts_y || !mts_x)
fprintf(stderr, "mtsedit: %s: %s\r\n", mtsfile, lang[ERR_LOAD]);
/* make sure that all non-air blocks have their probability set */
for(y = 0; y < mts_y; y++)
for(z = 0; z < mts_z; z++)
for(x = 0; x < mts_x; x++, b++)
if(nodes[y+min_y][z+min_z][x+min_x].param0 && !nodes[y+min_y][z+min_z][x+min_x].param1)
nodes[y+min_y][z+min_z][x+min_x].param1 = 127;
n = (buff[0] << 8) | buff[1];
if(n > 0 && n < 1024) {
buff += 2;
tr = (unsigned short*)malloc(n * sizeof(unsigned short));
if(!tr) error(lang[ERR_MEM]);
for(i = 0; i < n; i++) {
tr[i] = numblocks;
j = buff[1];
buff += 2;
for(k = 0; k < numblocks; k++)
for(l = 0; l < numpalettes + 1; l++)
if((!blocks[k].blocknames && l && (int)strlen(blocks[k].name) == j &&
!memcmp(blocks[k].name, buff, j)) || (blocks[k].blocknames && blocks[k].blocknames[l] &&
(int)strlen(blocks[k].blocknames[l]) == j && !memcmp(blocks[k].blocknames[l], buff, j))) {
if(!l && k) { blocks[k].dobiome = 1; savebiome = 1; }
if(l && l - 1 > savepal) savepal = l - 1;
tr[i] = k;
break;
}
if(tr[i] == numblocks) {
x = buff[j]; buff[j] = 0;
fprintf(stderr, "mtsedit: %s: %s %d '%s'\r\n", mtsfile, lang[ERR_NODE], i, buff);
buff[j] = x;
idx = numblocks++;
blocks = (mtsblock_t*)realloc(blocks, numblocks * sizeof(mtsblock_t));
if(!blocks) error(lang[ERR_MEM]);
memset(&blocks[idx], 0, sizeof(mtsblock_t));
blocks[idx].name = (char*)malloc(j + 1);
if(!blocks[idx].name) error(lang[ERR_MEM]);
memcpy(blocks[idx].name, buff, j);
blocks[idx].name[j] = 0;
}
buff += j;
}
size -= (int)(buff - data);
un = (uint8_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)buff, size, 4096, &i, 1);
if(un) { buff = un; size = (unsigned int)i; }
if(4 * mts_x * mts_y * mts_z <= (int)size) {
for(z = 0, b = buff; z < mts_z; z++)
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x; x++, b += 2) {
nodes[y+min_y][z+min_z][x+min_x].param0 = tr[(b[0] << 8) | b[1]];
blocks[nodes[y+min_y][z+min_z][x+min_x].param0].numref++;
}
for(z = 0; z < mts_z; z++)
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x; x++, b++)
nodes[y+min_y][z+min_z][x+min_x].param1 = data[5] == 3 ? b[0] >> 1 : b[0];
for(z = 0; z < mts_z; z++)
for(y = 0; y < mts_y; y++)
for(x = 0; x < mts_x; x++, b++)
nodes[y+min_y][z+min_z][x+min_x].param2 = b[0];
gndlayer = currlayer = min_y;
for(y = 0; y < mts_y; y++)
for(z = 0; z < mts_z; z++)
for(x = 0; x < mts_x; x++)
if(nodes[y+min_y][z+min_z][x+min_x].param2 == 0x20) {
gndlayer = currlayer = y+min_y;
nodes[y+min_y][z+min_z][x+min_x].param2 = 0;
}
status = lang[LOADED];
} else mts_x = mts_y = mts_z = 0;
free(tr);
if(un) free(un);
} else mts_x = mts_y = mts_z = 0;
}
if(data) free(data);
if(buff) free(buff);
}
/**
@ -241,7 +179,7 @@ int mts_save()
char outfile[MAXPATHLEN], *c;
unsigned short *tr, *tr2;
unsigned char *b, *b2, hdr[12];
int i, j, k, x, y, z, mix = 255, max = 0, miy = 255, may = 0, miz = 255, maz = 0;
int i, j, k, x, y, z;
FILE *f;
status = lang[ERR_SAVE];
@ -251,30 +189,8 @@ int mts_save()
tr2 = (unsigned short*)malloc(numblocks * sizeof(unsigned short));
if(!tr2) error(lang[ERR_MEM]);
memset(tr2, 0, numblocks * sizeof(unsigned short));
/* get boundind box and block ID translation tables, sanitize probability values */
j = 1;
for(y = 0; y < 256; y++) {
for(z = k = 0; z < 256; z++)
for(x = 0; x < 256; x++) {
if(nodes[y][z][x].param0) {
if(!tr2[nodes[y][z][x].param0]) {
tr2[nodes[y][z][x].param0] = j;
tr[j++] = nodes[y][z][x].param0;
}
if(x < mix) mix = x;
if(x > max) max = x;
if(y < miy) miy = y;
if(y > may) may = y;
if(z < miz) miz = z;
if(z > maz) maz = z;
if(!nodes[y][z][x].param1) nodes[y][z][x].param1 = 127;
if(!layerprob[y]) layerprob[y] = 127;
k = 1;
} else
nodes[y][z][x].param1 = 0;
}
if(!k) layerprob[y] = 0;
}
j = mts_getbounds(1, tr, tr2);
if(mix > max) { free(tr); free(tr2); return 1; }
for(y = miy; y <= may; y++) {
@ -386,7 +302,7 @@ int mts_save()
*/
int mts_view(int type)
{
int i, j, w, h, x, y, z, mix = 255, max = 0, miy = 255, may = 0, miz = 255, maz = 0, lh = 0;
int i, j, w, h, x, y, z, lh = 0;
int r = 0, k, n;
char pngfile[MAXPATHLEN], *c;
unsigned char *buff = NULL;
@ -395,19 +311,10 @@ int mts_view(int type)
FILE *f;
status = lang[ERR_PREVIEW];
for(y = 0; y < 256; y++)
for(z = 0; z < 256; z++)
for(x = 0; x < 256; x++) {
if(nodes[y][z][x].param0) {
if(x < mix) mix = x;
if(x > max) max = x;
if(y < miy) miy = y;
if(y > may) may = y;
if(z < miz) miz = z;
if(z > maz) maz = z;
}
}
mts_getbounds(0, NULL, NULL);
if(mix > max) return 1;
/* calculate dimensions and create images */
n = (max - mix) + (maz - miz) + 1;
w = n * dx + 16;
lh = n * dz + 32 - dz;
@ -416,6 +323,8 @@ int mts_view(int type)
preview = SDL_CreateRGBSurface(0, w, h, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
src.x = src.y = 0; src.w = src.h = dst.w = dst.h = 32;
n = ((max-mix)+(maz-miz))/2;
/* generate preview into surface */
for(y = miy; y <= may; y++)
for(z = miz; z <= maz; z++) {
if(type) r = ((z-miz+1)*(max-mix+1)*(y-miy)/(maz-miz+1))/(may-miy);
@ -443,6 +352,8 @@ int mts_view(int type)
}
}
SDL_FreeSurface(blk);
/* crop the result */
buff = preview->pixels;
for(i = miy = 0; i < preview->pitch * h; i += 4)
if(buff[i + 3]) { miy = i / preview->pitch; break; }
@ -463,6 +374,7 @@ int mts_view(int type)
SDL_BlitSurface(preview, &src, blk, &dst);
SDL_FreeSurface(preview);
/* write result to PNG file */
buff = (unsigned char *)stbi_write_png_to_mem(blk->pixels, blk->pitch, blk->w, blk->h, 4, &i);
SDL_FreeSurface(blk);
if(buff) {
@ -499,22 +411,12 @@ void mts_layerprob(int diff)
*/
void mts_rotate(int ccw)
{
int nx, nz, x, y, z, mix = 255, max = 0, miy = 255, may = 0, miz = 255, maz = 0;
int nx, nz, x, y, z;
node_t layer[256][256];
for(y = 0; y < 256; y++)
for(z = 0; z < 256; z++)
for(x = 0; x < 256; x++) {
if(nodes[y][z][x].param0 || nodes[y][z][x].param1) {
if(x < mix) mix = x;
if(x > max) max = x;
if(y < miy) miy = y;
if(y > may) may = y;
if(z < miz) miz = z;
if(z > maz) maz = z;
}
}
mts_getbounds(0, NULL, NULL);
if(mix > max) return;
for(y = miy; y <= may; y++) {
memcpy(layer, nodes[y], sizeof(node_t)*256*256);
memset(nodes[y], 0, sizeof(node_t)*256*256);
@ -534,7 +436,7 @@ void mts_rotate(int ccw)
int mts_dump()
{
unsigned short *tr, *tr2;
int i, j, x, y, z, mix = 255, max = 0, miy = 255, may = 0, miz = 255, maz = 0;
int i, j, x, y, z;
tr = (unsigned short*)malloc(numblocks * sizeof(unsigned short));
if(!tr) error(lang[ERR_MEM]);
@ -542,24 +444,10 @@ int mts_dump()
tr2 = (unsigned short*)malloc(numblocks * sizeof(unsigned short));
if(!tr2) error(lang[ERR_MEM]);
memset(tr2, 0, numblocks * sizeof(unsigned short));
j = 1;
for(y = 0; y < 256; y++)
for(z = 0; z < 256; z++)
for(x = 0; x < 256; x++) {
if(nodes[y][z][x].param0) {
if(!tr2[nodes[y][z][x].param0]) {
tr2[nodes[y][z][x].param0] = j;
tr[j++] = nodes[y][z][x].param0;
}
if(x < mix) mix = x;
if(x > max) max = x;
if(y < miy) miy = y;
if(y > may) may = y;
if(z < miz) miz = z;
if(z > maz) maz = z;
}
}
j = mts_getbounds(0, tr, tr2);
if(mix > max) { free(tr); free(tr2); return 1; }
printf("-------------------------------- %s --------------------------------\r\n", mtsfile);
printf("Map (x: %d y: %d z: %d):\r\n", max-mix+1, may-miy+1, maz-miz+1);
if(savepal < 0 || savepal >= numpalettes) savepal = 0;
@ -573,9 +461,9 @@ int mts_dump()
if(j < 15) printf(" ");
for(x = mix; x <= max; x++) {
if(nodes[y][z][x].param0) {
if(j < 15) printf("%x", tr2[nodes[y][z][x].param0]);
if(j < 16) printf("%x", tr2[nodes[y][z][x].param0]);
else printf(" %02x", tr2[nodes[y][z][x].param0]);
} else printf(j < 15 ? "." : " ..");
} else printf(j < 16 ? "." : " ..");
}
printf(" ");
for(x = mix; x <= max; x++)
@ -591,193 +479,3 @@ int mts_dump()
free(tr2);
return 0;
}
/**
* Generate slab and stair pictures from block image
*/
int mts_stairgen()
{
FILE *f;
stbi__context sc;
stbi__result_info ri;
int i, j, w, h, l, x0,x1,x2, y0,y1,y2,y3,y4;
unsigned int size;
unsigned char *d, *data, *block, *slab, *stair;
char *c;
f = fopen(mtsfile, "rb");
if(f) {
fseek(f, 0L, SEEK_END);
size = (unsigned int)ftell(f);
fseek(f, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
if(!data) error(lang[ERR_MEM]);
fread(data, size, 1, f);
fclose(f);
c = strrchr(mtsfile, '_');
if(!c) c = strrchr(mtsfile, '.');
if(!c) c = &mtsfile[strlen(mtsfile)];
sc.read_from_callbacks = 0;
sc.img_buffer = sc.img_buffer_original = data;
sc.img_buffer_end = sc.img_buffer_original_end = data + size;
ri.bits_per_channel = 8;
block = (unsigned char*)stbi__png_load(&sc, &w, &h, &l, 0, &ri);
free(data);
if(!block) return 1;
slab = (unsigned char *)malloc(w * h * 4);
if(!slab) error(lang[ERR_MEM]);
memset(slab, 0, w * h * 4);
stair = (unsigned char *)malloc(w * h * 4);
if(!stair) error(lang[ERR_MEM]);
/* detect cube edges */
for(d = block; d[3] < 128; d += 4);
x1 = ((int)(d - block) % (w * 4)) / 4;
y0 = (int)(d - block) / (w * 4);
for(i = 0, d = block; i < w/2 && d[3] < 128; i++)
for(j = 0, d = block + i*4; j < h/2 && d[3] < 128; j++, d += w*4);
x0 = ((int)(d - block) % (w * 4)) / 4 - 1;
y1 = (int)(d - block) / (w * 4);
x2 = x1 + (x1 - x0) + 1;
y2 = y1 + (y1 - y0);
for(; d[3] > 128; d += w*4);
d -= w*4;
y3 = (int)(d - block) / (w * 4);
y4 = y3 + (y1 - y0);
#if DEBUG
*((uint32_t*)(slab + y0*w*4 + x1*4)) = 0xFF0000FF;
*((uint32_t*)(slab + y1*w*4 + x0*4)) = 0xFF0000FF;
*((uint32_t*)(slab + y1*w*4 + x2*4)) = 0xFF00FF00;
*((uint32_t*)(slab + y2*w*4 + x1*4)) = 0xFF00FF00;
*((uint32_t*)(slab + y3*w*4 + x0*4)) = 0xFF0000FF;
*((uint32_t*)(slab + y3*w*4 + x2*4)) = 0xFF00FF00;
*((uint32_t*)(slab + y4*w*4 + x1*4)) = 0xFF00FF00;
#endif
/* rotated block */
for(i = x0; i <= x2+1; i++) {
for(j = y0; j <= y4; j++)
*((uint32_t*)(slab + j*w*4 + (x2 - i + x0 + (x0 & 1))*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(slab, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_01.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
/* slab */
memset(slab, 0, w * h * 4);
for(i = x0; i <= x1; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y0; j < y1 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(slab + (j+(y3 - y1)/2+1)*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
for(j = y3 + l; j < h; j++)
*((uint32_t*)(slab + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x1+1; i <= x2; i++) {
l = (y1 - y0) * ((x2-i+1) - x1) / (x2 - x1);
for(j = y0; j < y2 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(slab + (j+(y3 - y1)/2+1)*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
for(j = y4 + l; j < h; j++)
*((uint32_t*)(slab + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(slab, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Slab_00.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
/* rotated stairs */
memcpy(stair, slab, w * h * 4);
for(i = x0; i <= x1 + (x2 - x1)/2; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y0 + l; j < y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x1; i <= x2; i++) {
l = (y1 - y0) * (i - x1) / (x1 - x0);
for(j = y0 + l; j <= y0 + l + 1; j++)
*((uint32_t*)(stair + (j+(y1-y0)/2)*w*4 + (i - (x1 - x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_00.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
memcpy(stair, slab, w * h * 4);
for(i = x0 + (x1 - x0)/2; i <= x2; i++) {
l = (y1 - y0) * ((x2-i+1) - x1) / (x2 - x1);
for(j = y1 + l; j < y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x0; i <= x1; i++) {
l = (y1 - y0) * ((x1-i+1) - x1) / (x1 - x0);
for(j = y1 + l; j <= y2 + l; j++)
*((uint32_t*)(stair + (j+(y1-y0)/2)*w*4 + (i+(x1 - x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_01.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
memcpy(stair, slab, w * h * 4);
for(i = x0 + (x1 - x0)/2; i <= x1 + (x2 - x1)/2; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y0; j <= y0 + l; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(; i <= x2; i++) {
for(j = y0; j <= y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x0; i < x1; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y1 + l - 1; j <= y1 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(stair + (j-(y1-y0)/2)*w*4 + (i + (x1 - x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_02.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
memcpy(stair, slab, w * h * 4);
for(i = x0; i <= x0 + (x1 - x0)/2 +1; i++) {
for(j = y0; j <= y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(; i <= x2; i++) {
l = (y1 - y0) * (i - (x0 + (x1 - x0)/2)) / (x2 - x1);
for(j = y0; j <= y1 + (y2 - y1)/2 - l; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x1+1; i <= x2; i++) {
l = (y1 - y0) * ((x2-i+1) - x1) / (x2 - x1);
for(j = y2 + l - 1; j <= y2 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(stair + (j-(y1-y0)/2)*w*4 + (i-(x1-x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_03.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
fprintf(stderr, "mtsedit: %s\r\n", lang[IMGSGEN]);
return 0;
}
return 1;
}

81
src/schem.c Normal file
View File

@ -0,0 +1,81 @@
/*
* mtsedit/schem.c
*
* Copyright (C) 2019 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* @brief Import a Minecraft NBT .schematic file
*
*/
#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
*/
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;
unsigned char *d, *end = data + size;
/* 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++) {
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\005Width", 7)) { d += 7; SCHEM_GETINT(mts_x, d[-8]); d--; }
}
if(!mts_y || !mts_z || !mts_x || mts_y > 255 || mts_z > 255 || mts_x > 255) { mts_y = mts_z = mts_x = 0; return; }
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;
/* now that we know the dimensions, find the blocks data */
for(d = data; d < end; d++) {
/* it must be type of byte array */
if(!memcmp(d, "\007\000\006Blocks", 9)) {
d += 9;
SCHEM_GETINT(i, 3);
if(i != mts_y * mts_z * mts_x) return;
for(y = 0; y < mts_y; y++)
for(z = 0; z < mts_z; z++)
for(x = 0; x < mts_x; x++, d++) {
if(!*d) continue;
nodes[y+min_y][z+min_z][x+min_x].param1 = 127;
for(i = 1, k = 0; i < numblocks; i++)
for(j = 0; j < 8; j++)
if(blocks[i].blockids[j] == *d) { k = i; i = numblocks; break; }
if(k) {
nodes[y+min_y][z+min_z][x+min_x].param0 = k;
blocks[k].numref++;
} else
fprintf(stderr, "mtsedit: %s: %s %d\r\n", mtsfile, lang[ERR_NODE], *d);
}
status = lang[LOADED];
break;
}
}
}

155
src/sdl.c
View File

@ -154,9 +154,11 @@ void sdlredraw()
strmaxw = screen->w;
rect.x = 36; rect.y = 0; rect.w = screen->w - 36; rect.h = screen->h - font->height;
SDL_FillRect(screen, &rect, theme[activetool == 1 || activetool == 4 ? THEME_BG : THEME_TABBG]);
if(activetool == 1) save_redraw(); else
if(activetool == 4) search_redraw(); else
edit_redraw();
switch(activetool) {
case 1: save_redraw(); break;
case 4: search_redraw(); break;
default: if(dx && dz) edit_redraw(); break;
}
/* toolbar and status bar */
sdltoolbar();
@ -167,7 +169,8 @@ void sdlredraw()
/**
* UI for saving
*/
void sdldosave() {
void sdldosave()
{
SDL_SetCursor(working);
mts_save();
SDL_SetCursor(pointer);
@ -178,9 +181,10 @@ void sdldosave() {
/**
* UI for loading
*/
void sdldoload() {
void sdldoload()
{
SDL_SetCursor(working);
mts_load();
readschem();
SDL_SetCursor(pointer);
activetool = -1; activeblock = 0;
sdlredraw();
@ -189,7 +193,8 @@ void sdldoload() {
/**
* UI for preview
*/
void sdldopreview() {
void sdldopreview()
{
SDL_SetCursor(working);
mts_view(shift);
SDL_SetCursor(pointer);
@ -199,7 +204,8 @@ void sdldopreview() {
/**
* UI for rotating
*/
void sdldorotate(int ccw) {
void sdldorotate(int ccw)
{
int i;
SDL_SetCursor(working);
@ -217,7 +223,7 @@ void sdlmain()
stbi__context s;
stbi__result_info ri;
unsigned char *icondata;
char *fn, *title, str[32];
char *fn, *title;
int iw = 0, ih = 0, len, i, j, k;
SDL_Event event;
SDL_Rect dst;
@ -263,8 +269,8 @@ void sdlmain()
/* parse blocks.csv */
parseblocks();
/* load MTS */
mts_load(mtsfile);
/* load schematics from file */
readschem();
/* populate search window with default results (may include unknown blocks from the MTS) */
numresults = numblocks - 1;
@ -322,19 +328,13 @@ void sdlmain()
/* toolbar */
if(event.motion.y < 4 + 5 * 36) {
i = (event.motion.y > 3 ? event.motion.y - 4 : event.motion.y) / 36;
} else if(event.motion.y >= (int)(screen->h - font->height)) {
i = -3;
} else if(event.motion.y >= (int)(screen->h - 2*font->height)) {
i = -4;
} else if(event.motion.y >= (int)(screen->h - 3*font->height)) {
i = -2;
} else if(event.motion.y >= (int)(screen->h - 3*font->height - 36)) {
i = 6;
} else if(event.motion.y >= (int)(screen->h - 3*font->height - 2*36)) {
i = 5;
} else if(event.motion.y < (int)(screen->h - 3*font->height - 2*36)) {
j = (event.motion.y - (4 + 5 * 36)) / 32;
}
} else
if(event.motion.y >= (int)(screen->h - font->height)) i = -3; else
if(event.motion.y >= (int)(screen->h - 2*font->height)) i = -4; else
if(event.motion.y >= (int)(screen->h - 3*font->height)) i = -2; else
if(event.motion.y >= (int)(screen->h - 3*font->height - 36)) i = 6; else
if(event.motion.y >= (int)(screen->h - 3*font->height - 2*36)) i = 5; else
if(event.motion.y < (int)(screen->h - 3*font->height - 2*36)) j = (event.motion.y - (4 + 5 * 36)) / 32;
} else
if(activetool == 4) search_mouseover(&event); else
if(activetool == -1) {
@ -342,9 +342,7 @@ void sdlmain()
status = NULL;
dst.x = 36; dst.y = screen->h - font->height; dst.w = screen->w - 36; dst.h = font->height;
SDL_FillRect(screen, &dst, theme[THEME_BG]);
edit_hidecursor();
edit_mouseover(&event);
edit_showcursor(event.button.button == 1);
sdltoolbar();
SDL_UpdateWindowSurface(window);
}
@ -358,7 +356,7 @@ void sdlmain()
case SDL_MOUSEBUTTONDOWN:
if(activetool == -1 && overtool == -1 && event.motion.x > 36) edit_mousedown(&event); else
if(overtool == -3) mts_layerprob(event.button.button == 1 ? +1 : -1); else
if(overtool == -2) gndlayer = currlayer;
if(overtool == -2) gndlayer = currlayer; else
if(overtool >= 0 || overblock != -1) {
if(overtool >= 0 && activetool != overtool) activetool = overtool;
else { activetool = -1; if(overblock != -1) activeblock = overblock; }
@ -370,20 +368,24 @@ void sdlmain()
break;
case SDL_MOUSEBUTTONUP:
if(activetool != -1 && activetool == overtool) {
if(activetool == 0) sdldoload();
if(activetool == 2) sdldopreview();
if(activetool == 3) sdldorotate(shift || event.button.button != 1 ? 0 : 1);
if(activetool == 5 && currlayer < 255) currlayer++;
if(activetool == 6 && currlayer > 0) currlayer--;
if(activetool != 1 && activetool != 4) activetool = -1;
switch(activetool) {
case 0: sdldoload(); break;
case 2: sdldopreview(); break;
case 3: sdldorotate(shift || event.button.button != 1 ? 0 : 1); break;
case 5: if(currlayer < 255) currlayer++; break;
case 6: if(currlayer > 0) currlayer--; break;
default: if(activetool != 1 && activetool != 4) activetool = -1; break;
}
}
sdlredraw();
break;
case SDL_MOUSEWHEEL:
if(overtool == -3) mts_layerprob(event.wheel.y); else
if(activetool == 1) save_scroll(&event); else
if(activetool == 4) search_scroll(&event); else
if(activetool == -1) edit_scroll(&event);
switch(activetool) {
case 1: save_scroll(&event); break;
case 4: search_scroll(&event); break;
case -1: edit_scroll(&event); break;
}
sdlredraw();
break;
@ -396,85 +398,8 @@ void sdlmain()
SDL_ShowCursor(0);
systemcursor = 0;
activetool = -1;
} else if(activetool != 1 && activetool != 4) {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q: quitting = 1; break;
case SDLK_s: if(!shift) sdldosave(); break;
case SDLK_l: sdldoload(); break;
case SDLK_p: sdldopreview(); break;
case SDLK_r: sdldorotate(1 - shift); break;
case SDLK_g: gndlayer = currlayer; break;
case SDLK_PLUS: case SDLK_EQUALS: mts_layerprob(+1); break;
case SDLK_MINUS: mts_layerprob(-1); break;
case SDLK_PAGEUP: if(currlayer < 255) currlayer++; break;
case SDLK_PAGEDOWN: if(currlayer > 0) currlayer--; break;
case SDLK_BACKQUOTE: case SDLK_0: activeblock = 0; break;
case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: case SDLK_5:
case SDLK_6: case SDLK_7: case SDLK_8: case SDLK_9:
if(palette[event.key.keysym.sym - SDLK_0])
activeblock = event.key.keysym.sym - SDLK_0;
break;
case SDLK_h: dx--; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_k: dx++; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_u: dz--; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_j: dz++; sprintf(str, "dx %d dz %d", dx, dz); status = str; break;
case SDLK_UP:
if(ctrl) {
if(oy < 127) oy++;
} else if(shift) {
if(up > -128) up--;
} else {
if(cz > 0) cz--;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_DOWN:
if(ctrl) {
if(oy > -128) oy--;
} else if(shift) {
if(up < 127) up++;
} else {
if(cz < 255) cz++;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_LEFT:
if(ctrl) {
if(ox < 127) ox++;
} else if(shift) {
edit_rotate(currlayer, cz, cx, 1);
} else {
if(cx > 0) cx--;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_RIGHT:
if(ctrl) {
if(ox > -128) ox--;
} else if(shift) {
edit_rotate(currlayer, cz, cx, 0);
} else {
if(cx < 255) cx++;
status = nodes[currlayer][cz][cx].param0 ?
blocks[nodes[currlayer][cz][cx].param0].name : NULL;
}
break;
case SDLK_BACKSPACE:
case SDLK_DELETE:
case SDLK_SPACE:
blocks[nodes[currlayer][cz][cx].param0].numref--;
i = event.key.keysym.sym == SDLK_SPACE && !shift ? palette[activeblock] : 0;
blocks[i].numref++;
nodes[currlayer][cz][cx].param0 = i;
nodes[currlayer][cz][cx].param1 = i ? 127 : 0;
status = i ? blocks[i].name : NULL;
break;
}
}
} else
if(activetool != 1 && activetool != 4) edit_key(&event);
sdlredraw();
break;
case SDL_TEXTINPUT:

View File

@ -28,11 +28,9 @@
*/
#include "main.h"
#include <dirent.h>
char *path = NULL, *fn = NULL;
int fncmp(const void *a, const void *b) { return strcmp(*((const char**)a), *((const char**)b)); }
/* cube coordinates */
int x0,x1,x2, y0,y1,y2,y3,y4;
/**
* Read a file into memory from the data directory
@ -61,6 +59,83 @@ unsigned char *readfile(char *file, unsigned int *size)
return ret;
}
/**
* Read schematics from file
*/
void readschem()
{
FILE *f;
unsigned char *data = NULL, *buff = NULL;
unsigned int size = 0;
int x, y, z;
status = lang[ERR_LOAD];
mts_x = mts_y = mts_z = 0; currlayer = 127;
memset(layerprob, 127, sizeof(layerprob));
memset(nodes, 0, sizeof(nodes));
for(x = 0; x < numblocks; x++) {
blocks[x].dobiome = 0;
blocks[x].numref = 0;
}
blocks[0].numref = 256 * 256 * 256;
savepal = savebiome = 0;
currlayer = cx = cz = 127;
f = fopen(mtsfile, "rb");
if(f) {
fseek(f, 0L, SEEK_END);
size = (unsigned int)ftell(f);
fseek(f, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
if(!data) error(lang[ERR_MEM]);
fread(data, size, 1, f);
fclose(f);
status = lang[ERR_BADFILE];
/* if it's gzip compressed, uncompress it first */
if(data[0] == 0x1f && data[1] == 0x8b) {
/* skip over gzip header */
buff = data + 3;
x = *buff++; buff += 6;
if(x & 4) { y = *buff++; y += (*buff++ << 8); buff += y; }
if(x & 8) { while(*buff++ != 0); }
if(x & 16) { while(*buff++ != 0); }
if(x & 2) buff += 2;
size -= (int)(buff - data);
buff = (uint8_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)buff, size, 4096, &x, 0);
if(buff) { free(data); data = buff; buff = NULL; size = (unsigned int)x; }
} else buff = data;
/* if it's an MTS file */
if(!memcmp(data, "MTSM", 4)) mts_load(data, size); else
/* Could be a Minecraft NBT */
if(!memcmp(data + 3, "Schematic", 9)) schem_load(data, size);
/* make sure that all non-air blocks have their probability set */
if(!mts_y || !mts_y || !mts_x)
fprintf(stderr, "mtsedit: %s: %s\r\n", mtsfile, lang[ERR_LOAD]);
for(y = 0; y < 256; y++)
for(z = 0; z < 256; z++)
for(x = 0; x < 256; x++)
if(nodes[y][z][x].param0 && !nodes[y][z][x].param1)
nodes[y][z][x].param1 = 127;
}
if(data) free(data);
}
/**
* Common error handler
*/
void error(char *msg)
{
#ifdef __WIN32__
MessageBox(NULL, msg, "MTSEdit", MB_ICONEXCLAMATION | MB_OK);
#else
fprintf(stderr, "mtsedit: %s\r\n", msg);
#endif
exit(1);
}
/**
* CSV error
*/
@ -86,195 +161,202 @@ unsigned char ahtoi(char *s)
}
/**
* Parse the blocks.csv
* Deetect cube edges
*/
void parseblocks()
void detcube(int w, int h, unsigned char *block)
{
stbi__context sc;
stbi__result_info ri;
int w, h, l;
unsigned int numfiles = 0, i, j, k;
char **files = NULL, c, *s, *e;
DIR *dir;
struct dirent *de;
unsigned int size;
unsigned char *img;
char *data = (char*)readfile("blocks.csv", &size);
unsigned char *d;
int i, j;
if(!data || !size) error(lang[ERR_CSV]);
/* get block images */
*fn = 0;
dir = opendir(path);
if(dir) {
while((de = readdir(dir))) {
i = strlen(de->d_name);
if(i > 8 && !strcmp(de->d_name + i - 4, ".png") && de->d_name[i-7] == '_') {
j = numfiles++;
files = (char**)realloc(files, numfiles * sizeof(char*));
if(!files) error(lang[ERR_MEM]);
files[j] = (char*)malloc(i + 1);
if(!files[j]) error(lang[ERR_MEM]);
memcpy(files[j], de->d_name, i + 1);
}
}
closedir(dir);
}
qsort(files, numfiles, sizeof(char*), fncmp);
/* parse header */
for(e = data, i = j = 0; *e && *e != '\r' && *e != '\n' && i < 3; e++) {
if(*e == '\"') j ^= 1;
if(!j && (*e == ',' || *e == ';' || *e == '\t')) i++;
}
if(i != 3 || !*e || *e == '\r' || *e == '\n') errorcsv(1);
while(*e && *e != '\r' && *e != '\n') {
while(*e == ',' || *e == ';' || *e == '\t' || *e == ' ') e++;
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
while(*(e-1) <= ' ') e--;
j = numpalettes++;
palettes = (char**)realloc(palettes, numpalettes * sizeof(char*));
if(!palettes) error(lang[ERR_MEM]);
palettes[j] = (char*)malloc(e - s + 1);
if(!palettes[j]) error(lang[ERR_MEM]);
memcpy(palettes[j], s, e - s + 1);
palettes[j][e - s] = 0;
if((int)(e - s) > lenpalettes) lenpalettes = e - s;
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
}
/* add Air as first block */
numblocks++;
blocks = (mtsblock_t*)realloc(blocks, numblocks * sizeof(mtsblock_t));
if(!blocks) error(lang[ERR_MEM]);
memset(&blocks[0], 0, sizeof(mtsblock_t));
blocks[0].name = (char*)malloc(4);
if(!blocks[0].name) error(lang[ERR_MEM]);
memcpy(blocks[0].name, "Air", 4);
blocks[0].blocknames = (char**)malloc((numpalettes + 1) * sizeof(char*));
if(!blocks[0].blocknames) error(lang[ERR_MEM]);
blocks[0].blocknames[0] = NULL;
for(i = 1; i < (unsigned int)numpalettes + 1; i++) {
blocks[0].blocknames[i] = (char*)malloc(4);
if(!blocks[0].blocknames[i]) error(lang[ERR_MEM]);
memcpy(blocks[0].blocknames[i], "air", 4);
}
/* parse rows */
while(*e) {
if(*e == '\r' || *e == '\n') {
while(*e == '\r' || *e == '\n') e++;
if(!*e) break;
/* get canonical name */
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
while(*(e-1) <= ' ') e--;
j = numblocks++;
blocks = (mtsblock_t*)realloc(blocks, numblocks * sizeof(mtsblock_t));
if(!blocks) error(lang[ERR_MEM]);
memset(&blocks[j], 0, sizeof(mtsblock_t));
blocks[j].name = (char*)malloc(e - s + 1);
if(!blocks[j].name) error(lang[ERR_MEM]);
blocks[j].blocknames = (char**)malloc((numpalettes + 1) * sizeof(char*));
if(!blocks[j].blocknames) error(lang[ERR_MEM]);
memset(blocks[j].blocknames, 0, (numpalettes + 1) * sizeof(char*));
for(i = 0; s + i < e; i++) {
blocks[j].name[i] = s[i] == '_' ? ' ' : s[i];
if(s[i] == ' ') s[i] = '_';
}
blocks[j].name[i] = 0;
/* get block images and possible param2 values */
for(i = 0, l = 0; i < numfiles; i++) {
if((int)strlen(files[i]) == (int)(e - s + 7) && !memcmp(files[i], s, e - s)) {
img = readfile(files[i], &size);
if(img && size) {
k = ahtoi(strrchr(files[i], '_') + 1) & 0x1F;
sc.read_from_callbacks = 0;
sc.img_buffer = sc.img_buffer_original = img;
sc.img_buffer_end = sc.img_buffer_original_end = img + size;
ri.bits_per_channel = 8;
blocks[j].img[k] = (unsigned char*)stbi__png_load(&sc, &w, &h, &l, 0, &ri);
if(blocks[j].img[k]) l++;
free(img);
}
}
}
if(!l)
fprintf(stderr, "mtsedit: blocks.csv(%d): %s '%s'\r\n", j+1, lang[ERR_IMG], blocks[j].name);
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
while(*e == ' ') e++;
if(*e != ',' && *e != ';' && *e != '\t') errorcsv(j+1);
e++;
while(*e == ' ') e++;
/* get Block IDs */
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
for(i = 0; s < e && i < 8;) {
blocks[j].blockids[i] = atoi(s);
if(blocks[j].blockids[i]) i++;
while(*s >= '0' && *s <= '9') s++;
if(*s == '/') s++;
}
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
k = 0;
}
/* get palette specific names */
while(*e == ' ') e++;
if(*e != ',' && *e != ';' && *e != '\t') errorcsv(j+1);
e++;
while(*e == ' ') e++;
if(!*e) errorcsv(j+1);
if(*e == '\"') { e++; c = '\"'; } else c = ',';
for(s = e; *e && *e != '\r' && *e != '\n' && *e != c; e++)
if(*e == '\\' || (*e == '\"' && e[1] == '\"')) { e++; continue; }
while(*s <= ' ') s++;
while(*(e-1) <= ' ') e--;
if(e != s) {
blocks[j].blocknames[k] = (char*)malloc(e - s + 1);
if(!blocks[j].blocknames[k]) error(lang[ERR_MEM]);
memcpy(blocks[j].blocknames[k], s, e - s + 1);
blocks[j].blocknames[k][e - s] = 0;
}
k++; if(k > (unsigned int)numpalettes + 1) errorcsv(j+2);
while(*e && *e != ',' && *e != ';' && *e != '\t' && *e != '\r' && *e != '\n') e++;
}
if(!numblocks || numblocks > 65535) error(lang[ERR_CSV]);
/* free temp resources */
for(i = 0; i < numfiles; i++) free(files[i]);
free(files);
free(data);
for(d = block; d[3] < 128; d += 4);
x1 = ((int)(d - block) % (w * 4)) / 4;
y0 = (int)(d - block) / (w * 4);
for(i = 0, d = block; i < w/2 && d[3] < 128; i++)
for(j = 0, d = block + i*4; j < h/2 && d[3] < 128; j++, d += w*4);
x0 = ((int)(d - block) % (w * 4)) / 4 - 1;
y1 = (int)(d - block) / (w * 4);
x2 = x1 + (x1 - x0) + 1;
y2 = y1 + (y1 - y0);
for(; d[3] > 128; d += w*4);
d -= w*4;
y3 = (int)(d - block) / (w * 4);
y4 = y3 + (y1 - y0);
}
/**
* Free resources
* Generate slab and stair pictures from block image
*/
void freeblocks()
int stairgen()
{
int i, j;
FILE *f;
stbi__context sc;
stbi__result_info ri;
int i, j, w, h, l;
unsigned int size;
unsigned char *data, *block, *slab, *stair;
char *c;
for(i = 0; i < numpalettes; i++) free(palettes[i]);
free(palettes);
f = fopen(mtsfile, "rb");
if(f) {
fseek(f, 0L, SEEK_END);
size = (unsigned int)ftell(f);
fseek(f, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
if(!data) error(lang[ERR_MEM]);
fread(data, size, 1, f);
fclose(f);
c = strrchr(mtsfile, '_');
if(!c) c = strrchr(mtsfile, '.');
if(!c) c = &mtsfile[strlen(mtsfile)];
sc.read_from_callbacks = 0;
sc.img_buffer = sc.img_buffer_original = data;
sc.img_buffer_end = sc.img_buffer_original_end = data + size;
ri.bits_per_channel = 8;
block = (unsigned char*)stbi__png_load(&sc, &w, &h, &l, 0, &ri);
free(data);
if(!block) return 1;
slab = (unsigned char *)malloc(w * h * 4);
if(!slab) error(lang[ERR_MEM]);
memset(slab, 0, w * h * 4);
stair = (unsigned char *)malloc(w * h * 4);
if(!stair) error(lang[ERR_MEM]);
/* detect cube edges */
detcube(w, h, block);
#if DEBUG
*((uint32_t*)(slab + y0*w*4 + x1*4)) = 0xFF0000FF;
*((uint32_t*)(slab + y1*w*4 + x0*4)) = 0xFF0000FF;
*((uint32_t*)(slab + y1*w*4 + x2*4)) = 0xFF00FF00;
*((uint32_t*)(slab + y2*w*4 + x1*4)) = 0xFF00FF00;
*((uint32_t*)(slab + y3*w*4 + x0*4)) = 0xFF0000FF;
*((uint32_t*)(slab + y3*w*4 + x2*4)) = 0xFF00FF00;
*((uint32_t*)(slab + y4*w*4 + x1*4)) = 0xFF00FF00;
#endif
for(i = 0; i < numblocks; i++) {
free(blocks[i].name);
if(blocks[i].blocknames) {
for(j = 0; j < numpalettes; j++)
if(blocks[i].blocknames[j]) free(blocks[i].blocknames[j]);
free(blocks[i].blocknames);
/* rotated block */
for(i = x0; i <= x2+1; i++) {
for(j = y0; j <= y4; j++)
*((uint32_t*)(slab + j*w*4 + (x2 - i + x0 + (x0 & 1))*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(j = 0; j < 32; j++) {
if(blocks[i].img[j]) free(blocks[i].img[j]);
if(blocks[i].dr[j]) free(blocks[i].dr[j]);
if(blocks[i].tr[j]) free(blocks[i].tr[j]);
data = (unsigned char *)stbi_write_png_to_mem(slab, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_01.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
/* slab */
memset(slab, 0, w * h * 4);
for(i = x0; i <= x1; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y0; j < y1 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(slab + (j+(y3 - y1)/2+1)*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
for(j = y3 + l; j < h; j++)
*((uint32_t*)(slab + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x1+1; i <= x2; i++) {
l = (y1 - y0) * ((x2-i+1) - x1) / (x2 - x1);
for(j = y0; j < y2 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(slab + (j+(y3 - y1)/2+1)*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
for(j = y4 + l; j < h; j++)
*((uint32_t*)(slab + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(slab, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Slab_00.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
/* rotated stairs */
memcpy(stair, slab, w * h * 4);
for(i = x0; i <= x1 + (x2 - x1)/2; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y0 + l; j < y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x1; i <= x2; i++) {
l = (y1 - y0) * (i - x1) / (x1 - x0);
for(j = y0 + l; j <= y0 + l + 1; j++)
*((uint32_t*)(stair + (j+(y1-y0)/2)*w*4 + (i - (x1 - x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_00.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
memcpy(stair, slab, w * h * 4);
for(i = x0 + (x1 - x0)/2; i <= x2; i++) {
l = (y1 - y0) * ((x2-i+1) - x1) / (x2 - x1);
for(j = y1 + l; j < y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x0; i <= x1; i++) {
l = (y1 - y0) * ((x1-i+1) - x1) / (x1 - x0);
for(j = y1 + l; j <= y2 + l; j++)
*((uint32_t*)(stair + (j+(y1-y0)/2)*w*4 + (i+(x1 - x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_01.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
memcpy(stair, slab, w * h * 4);
for(i = x0 + (x1 - x0)/2; i <= x1 + (x2 - x1)/2; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y0; j <= y0 + l; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(; i <= x2; i++) {
for(j = y0; j <= y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x0; i < x1; i++) {
l = (y1 - y0) * (i - x0) / (x1 - x0);
for(j = y1 + l - 1; j <= y1 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(stair + (j-(y1-y0)/2)*w*4 + (i + (x1 - x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_02.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
memcpy(stair, slab, w * h * 4);
for(i = x0; i <= x0 + (x1 - x0)/2 +1; i++) {
for(j = y0; j <= y4; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(; i <= x2; i++) {
l = (y1 - y0) * (i - (x0 + (x1 - x0)/2)) / (x2 - x1);
for(j = y0; j <= y1 + (y2 - y1)/2 - l; j++)
*((uint32_t*)(stair + j*w*4 + i*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
for(i = x1+1; i <= x2; i++) {
l = (y1 - y0) * ((x2-i+1) - x1) / (x2 - x1);
for(j = y2 + l - 1; j <= y2 + (y3 - y1)/2 + l; j++)
*((uint32_t*)(stair + (j-(y1-y0)/2)*w*4 + (i-(x1-x0)/2)*4)) = *((uint32_t*)(block + j*w*4 + i*4));
}
data = (unsigned char *)stbi_write_png_to_mem(stair, w*4, w, h, 4, &l);
if(data) {
strcpy(c, "_Stair_03.png");
f = fopen(mtsfile,"wb");
if(f) { fwrite(data, l, 1, f); fclose(f); }
free(data);
}
fprintf(stderr, "mtsedit: %s\r\n", lang[IMGSGEN]);
return 0;
}
free(results);
free(blocks);
return 1;
}