474 lines
18 KiB
C
474 lines
18 KiB
C
/*
|
|
* mtsedit/edit.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 The main edit area
|
|
*
|
|
*/
|
|
|
|
#include "main.h"
|
|
|
|
int dx = 0, dz = 0, cx = 0, cz = 0, ox = 0, oy = 0, up = 0, zoom = 128, zz = 0, zx = 0, zs = 0, grid = 1, curronly = 0;
|
|
char dstr[32];
|
|
|
|
/**
|
|
* Place a node
|
|
*/
|
|
void edit_placenode(int y, int z, int x, int i)
|
|
{
|
|
int j, k;
|
|
|
|
if(x >= 0 && x < 256 && y >= 0 && y < 256 && z >=0 && z < 256 && i != nodes[y][z][x].param0) {
|
|
mts_getbounds(0, NULL, NULL);
|
|
hist_add(y, z, x, nodes[y][z][x].param0, nodes[y][z][x].param2, i, nodes[y][z][x].param2);
|
|
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].param0) {
|
|
for(k = 0, j = 1; j < 15; j++)
|
|
if(palette[j] == nodes[y][z][x].param0) { k = j; break; }
|
|
if(!k) {
|
|
for(j = 15; j > activeblock + 1; j--) palette[j] = palette[j - 1];
|
|
palette[activeblock + 1] = nodes[y][z][x].param0;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Add node at cursor to palette
|
|
*/
|
|
void edit_pipette(int y, int z, int x)
|
|
{
|
|
int j, k;
|
|
if(x >= 0 && x < 256 && y >= 0 && y < 256 && z >=0 && z < 256 && nodes[y][z][x].param0) {
|
|
if(nodes[y][z][x].param0) {
|
|
for(k = 0, j = 1; j < 15; j++)
|
|
if(palette[j] == nodes[y][z][x].param0) { activeblock = k = j; break; }
|
|
if(!k) {
|
|
for(j = 15; j > 1; j--) palette[j] = palette[j - 1];
|
|
activeblock = 1;
|
|
palette[activeblock] = nodes[y][z][x].param0;
|
|
}
|
|
}
|
|
status = blocks[nodes[y][z][x].param0].name;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Zoom in
|
|
*/
|
|
int edit_zoomin()
|
|
{
|
|
if(zoom < 256) { zoom += 32; return 1; }
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Zoom out
|
|
*/
|
|
int edit_zoomout()
|
|
{
|
|
if(zoom > 32) { zoom -= 32; return 1; }
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Redraw the Edit Area
|
|
*/
|
|
void edit_redraw(int full)
|
|
{
|
|
int i, j, k = 160, l, X, Z, x, y, z, sx, sy, mx, zl, s;
|
|
unsigned char *b = (uint8_t*)&theme[THEME_TABBG];
|
|
SDL_Rect dst, src;
|
|
|
|
zz = dz * zoom / 128; zx = dx * zoom / 128; zs = 32 * zoom / 128;
|
|
if(zz < 1) zz = 1;
|
|
if(zx < 1) zx = 1;
|
|
if(zs < 1) zs = 1;
|
|
zl = zs - 2*(2 + zz);
|
|
|
|
mx = (((bg->w / 2 / zx) + (bg->h / 2 / zz)) / 2) + 1;
|
|
sx = bg->w / 2;
|
|
sy = bg->h / 2;
|
|
|
|
if(full) {
|
|
dst.x = dst.y = 0; dst.w = bg->w; dst.h = bg->h;
|
|
SDL_FillRect(bg, &dst, theme[THEME_TABBG]);
|
|
src.x = 0; src.y = 4 * 32; dst.x = bg->w - 32; dst.y = bg->h - 32;
|
|
src.w = src.h = dst.w = dst.h = 32;
|
|
SDL_BlitSurface(icons, &src, bg, &dst);
|
|
if(!curronly) {
|
|
src.x = src.y = 0;
|
|
/* background, layers below */
|
|
for(y = mx > currlayer ? 0 : currlayer - mx; y < currlayer; y++) {
|
|
for(z = -mx; z < mx; z++) {
|
|
for(x = -mx; x < mx; x++) {
|
|
dst.w = dst.h = zs;
|
|
dst.x = sx + zx * (x - z);
|
|
dst.y = sy + zz * (z + x) + zl * (currlayer - y);
|
|
X = 127 + x + oy + ox;
|
|
Z = 127 + z + oy - ox;
|
|
if(X < 0 || X > 255 || Z < 0 || Z > 255 || dst.x < 0 || dst.x > bg->w || dst.y < 0 || dst.y > bg->h)
|
|
continue;
|
|
i = nodes[y][Z][X].param0;
|
|
if(i) {
|
|
j = nodes[y][Z][X].param2;
|
|
if(blocks[i].numpar2) j %= (int)blocks[i].numpar2; else j = 0;
|
|
if(!blocks[i].dr) {
|
|
s = 32 * (blocks[i].numpar2 ? blocks[i].numpar2 : 1)*32 * 4;
|
|
blocks[i].dr = (unsigned char *)malloc(s);
|
|
if(!blocks[i].dr) error(lang[ERR_MEM]);
|
|
memset(blocks[i].dr, 0, s);
|
|
if(blocks[i].img)
|
|
memcpy(blocks[i].dr, blocks[i].img, s);
|
|
else {
|
|
j = 0;
|
|
s = 32 * 32 * 4;
|
|
blocks[i].numpar2 = 1;
|
|
if(!blocks[i].tr) {
|
|
blocks[i].tr = (unsigned char *)malloc(s);
|
|
if(!blocks[i].tr) error(lang[ERR_MEM]);
|
|
memset(blocks[i].tr, 0, s);
|
|
}
|
|
memcpy(blocks[i].tr, (uint8_t*)icons->pixels + 32 * icons->pitch, s);
|
|
}
|
|
for(l = 0; l < s; l += 4) {
|
|
blocks[i].dr[l+0] = (b[0]*k + (256 - k)*blocks[i].dr[l+0])>>8;
|
|
blocks[i].dr[l+1] = (b[1]*k + (256 - k)*blocks[i].dr[l+1])>>8;
|
|
blocks[i].dr[l+2] = (b[2]*k + (256 - k)*blocks[i].dr[l+2])>>8;
|
|
}
|
|
}
|
|
blk->pixels = blocks[i].dr + j * 32 * 32 * 4;
|
|
if(dst.w == src.w)
|
|
SDL_BlitSurface(blk, &src, bg, &dst);
|
|
else
|
|
SDL_BlitScaled(blk, &src, bg, &dst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* draw grid */
|
|
if(grid && zz > 4) {
|
|
k = (x0 * zoom / 128);
|
|
y = (y3 * zoom / 128);
|
|
for(z = -mx; z < mx; z++) {
|
|
for(x = -mx; x < mx; x++) {
|
|
dst.x = sx + zx * (x - z) + k;
|
|
dst.y = sy + zz * (z + x) + y;
|
|
for(i = 0; i < zx; i++) {
|
|
l = dst.y + ((i+1) * zz) / zx;
|
|
if(dst.x + i > 0 && dst.x + zl+zx < bg->w && l > 0 && l < bg->h) {
|
|
*((uint32_t*)((uint8_t*)bg->pixels + (dst.x + i)*4 + l * bg->pitch)) = theme[THEME_INPBG];
|
|
*((uint32_t*)((uint8_t*)bg->pixels + (dst.x + zl+zx-i+1)*4 + l * bg->pitch)) = theme[THEME_INPBG];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!curronly) {
|
|
/* foreground, layers above */
|
|
memset(fg->pixels, 0, fg->pitch * fg->h);
|
|
mts_getbounds(0, NULL, NULL);
|
|
k = ((max - mix) + (maz - miz) + 1) / 2;
|
|
if(up > k) up = k;
|
|
for(y = currlayer + 1; y < (currlayer + mx < 255 ? currlayer + mx : 255); y++) {
|
|
for(z = -mx; z < mx; z++) {
|
|
for(x = -mx; x < mx; x++) {
|
|
dst.w = dst.h = zs;
|
|
dst.x = sx + zx * (x - z);
|
|
dst.y = sy + zz * (z + x - k + up) + zl * ((currlayer - y));
|
|
X = 127 + x + oy + ox;
|
|
Z = 127 + z + oy - ox;
|
|
if(X < 0 || X > 255 || Z < 0 || Z > 255 || dst.x < 0 || dst.x > fg->w || dst.y < 0 || dst.y > fg->h)
|
|
continue;
|
|
i = nodes[y][Z][X].param0;
|
|
if(i) {
|
|
j = nodes[y][Z][X].param2;
|
|
if(blocks[i].numpar2) j %= (int)blocks[i].numpar2; else j = 0;
|
|
if(!blocks[i].tr) {
|
|
s = 32 * (blocks[i].numpar2 ? blocks[i].numpar2 : 1)*32 * 4;
|
|
blocks[i].tr = (unsigned char *)malloc(s);
|
|
if(!blocks[i].tr) error(lang[ERR_MEM]);
|
|
if(blocks[i].img)
|
|
memcpy(blocks[i].tr, blocks[i].img, s);
|
|
else {
|
|
j = 0;
|
|
s = 32 * 32 * 4;
|
|
blocks[i].numpar2 = 1;
|
|
memcpy(blocks[i].tr, (uint8_t*)icons->pixels + 32 * icons->pitch, s);
|
|
}
|
|
for(l = 0; l < s; l += 4) blocks[i].tr[l+3] >>= 3;
|
|
}
|
|
blk->pixels = blocks[i].tr + j * 32 * 32 * 4;
|
|
if(dst.w == src.w)
|
|
SDL_BlitSurface(blk, &src, fg, &dst);
|
|
else
|
|
SDL_BlitScaled(blk, &src, fg, &dst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* current layer */
|
|
memset(cl->pixels, 0, cl->pitch * cl->h);
|
|
for(z = -mx; z < mx; z++) {
|
|
for(x = -mx; x < mx; x++) {
|
|
src.w = src.h = 32; dst.w = dst.h = zs; src.x = src.y = 0;
|
|
dst.x = sx + zx * (x - z);
|
|
dst.y = sy + zz * (z + x);
|
|
X = 127 + x + oy + ox;
|
|
Z = 127 + z + oy - ox;
|
|
if(X < 0 || X > 255 || Z < 0 || Z > 255 || dst.x < 0 || dst.x > cl->w || dst.y < 0 || dst.y > cl->h) continue;
|
|
i = nodes[currlayer][Z][X].param0;
|
|
if((X == cx && Z == cz) || brush_selected(X, Z)) {
|
|
blk->pixels = (uint8_t*)icons->pixels + 64 * icons->pitch;
|
|
if(dst.w == src.w)
|
|
SDL_BlitSurface(blk, &src, cl, &dst);
|
|
else
|
|
SDL_BlitScaled(blk, &src, cl, &dst);
|
|
}
|
|
if(i) {
|
|
j = nodes[currlayer][Z][X].param2;
|
|
if(blocks[i].numpar2) j %= (int)blocks[i].numpar2; else j = 0;
|
|
s = 32 * 32 * 4;
|
|
if(nodes[currlayer][Z][X].param1 & 0x80) {
|
|
memcpy(tmpblk, blocks[i].img ? blocks[i].img + j * s : (uint8_t*)icons->pixels + 32 * icons->pitch, s);
|
|
for(k = 0; k < s; k += 4)
|
|
if(tmpblk[k + 3])
|
|
tmpblk[k] = (255*64 + (256 - 64)*tmpblk[k])>>8;
|
|
blk->pixels = tmpblk;
|
|
} else {
|
|
blk->pixels = blocks[i].img ? blocks[i].img + j * s : (uint8_t*)icons->pixels + 32 * icons->pitch;
|
|
}
|
|
if(dst.w == src.w)
|
|
SDL_BlitSurface(blk, &src, cl, &dst);
|
|
else
|
|
SDL_BlitScaled(blk, &src, cl, &dst);
|
|
}
|
|
if((X == cx && Z == cz) || brush_selected(X, Z)) {
|
|
blk->pixels = (uint8_t*)icons->pixels + 96 * icons->pitch;
|
|
if(dst.w == src.w)
|
|
SDL_BlitSurface(blk, &src, cl, &dst);
|
|
else
|
|
SDL_BlitScaled(blk, &src, cl, &dst);
|
|
}
|
|
}
|
|
}
|
|
src.x = src.y = 32; dst.y = 0; dst.x = 36; src.w = dst.w = bg->w; src.h = dst.h = bg->h;
|
|
SDL_BlitSurface(bg, &src, screen, &dst);
|
|
SDL_BlitSurface(cl, &src, screen, &dst);
|
|
if(!curronly) SDL_BlitSurface(fg, &src, screen, &dst);
|
|
}
|
|
|
|
/**
|
|
* Edit Area scrolling event handler
|
|
*/
|
|
int edit_scroll(SDL_Event *event)
|
|
{
|
|
int lu = up, lx = ox, ly = oy;
|
|
if(shift) {
|
|
if(event->wheel.y) {
|
|
up -= event->wheel.y;
|
|
if(up < -128) up = -128;
|
|
if(up > 127) up = 127;
|
|
} else {
|
|
edit_rotate(currlayer, cz, cx, event->wheel.x < 0 ? 1 : 0);
|
|
return 1;
|
|
}
|
|
} else if(ctrl) {
|
|
if(event->wheel.y > 0) return edit_zoomout();
|
|
if(event->wheel.y < 0) return edit_zoomin();
|
|
} else {
|
|
oy += event->wheel.y;
|
|
if(oy < -128) oy = -128;
|
|
if(oy > 127) oy = 127;
|
|
ox += event->wheel.x;
|
|
if(ox < -128) ox = -128;
|
|
if(ox > 127) ox = 127;
|
|
}
|
|
return (lu != up || lx != ox || ly != oy);
|
|
}
|
|
|
|
/**
|
|
* Edit Area mouse over event handler
|
|
*/
|
|
void edit_mouseover(SDL_Event *event)
|
|
{
|
|
int l, k, x, y, X = cx, Z = cz;
|
|
x = (event->type == SDL_MOUSEMOTION ? event->motion.x : event->button.x) + 32;
|
|
y = (event->type == SDL_MOUSEMOTION ? event->motion.y : event->button.y) + 32;
|
|
|
|
l = (int)(y - (bg->h / 2));
|
|
if(l < 0) l -= zz;
|
|
l /= zz; l--;
|
|
k = (int)(x - 36 - (bg-> w / 2) - zx/2);
|
|
if(k < 0) k -= zx;
|
|
k -= (l & 1 ? zx/2 : 0);
|
|
k /= zx;
|
|
cz = (l - k) / 2;
|
|
cx = l - cz;
|
|
cz += 127 + oy - ox;
|
|
cx += 127 + oy + ox;
|
|
if((cx != X || cz != Z) && event->type == SDL_MOUSEMOTION && event->motion.state)
|
|
brush_place(event->motion.state == 1 ? palette[activeblock] : 0);
|
|
status = nodes[currlayer][cz][cx].param0 ? blocks[nodes[currlayer][cz][cx].param0].name : NULL;
|
|
}
|
|
|
|
/**
|
|
* Edit Area mouse down event handler
|
|
*/
|
|
void edit_mousedown(SDL_Event *event)
|
|
{
|
|
if(event->button.button != 1)
|
|
edit_rotate(currlayer, cz, cx, 1 - shift);
|
|
else
|
|
brush_place(palette[activeblock]);
|
|
}
|
|
|
|
/**
|
|
* Edit Area key event handler
|
|
*/
|
|
void edit_key(SDL_Event *event)
|
|
{
|
|
switch (event->key.keysym.sym) {
|
|
case SDLK_ESCAPE:
|
|
case SDLK_q: quitting = 1; break;
|
|
case SDLK_l: sdldo(0); break;
|
|
case SDLK_s: if(!shift) sdldo(1); break;
|
|
case SDLK_p: sdldo(2); break;
|
|
case SDLK_r: sdldo(4 - shift); break;
|
|
case SDLK_e: sdldo(12); break;
|
|
case SDLK_g: gndlayer = currlayer; break;
|
|
case SDLK_d:
|
|
if(nodes[currlayer][cz][cx].param0) {
|
|
nodes[currlayer][cz][cx].param1 ^= 0x80;
|
|
status = blocks[nodes[currlayer][cz][cx].param0].name;
|
|
}
|
|
break;
|
|
case SDLK_SEMICOLON: grid ^= 1; break;
|
|
case SDLK_a: curronly ^= 1; 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_n: edit_pipette(currlayer, cz, cx); break;
|
|
case SDLK_x: sdldo(6 + ctrl); break;
|
|
case SDLK_c: sdldo(8 + ctrl); break;
|
|
case SDLK_v: sdldo(10 + ctrl); break;
|
|
case SDLK_h: dx--; sprintf(dstr, "dx %d dz %d", dx, dz); status = dstr; break;
|
|
case SDLK_k: dx++; sprintf(dstr, "dx %d dz %d", dx, dz); status = dstr; break;
|
|
case SDLK_u: dz--; sprintf(dstr, "dx %d dz %d", dx, dz); status = dstr; break;
|
|
case SDLK_j: dz++; sprintf(dstr, "dx %d dz %d", dx, dz); status = dstr; 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_COMMA: edit_zoomout(); break;
|
|
case SDLK_PERIOD: edit_zoomin(); break;
|
|
case SDLK_BACKSPACE:
|
|
case SDLK_DELETE:
|
|
case SDLK_SPACE: brush_place(event->key.keysym.sym == SDLK_SPACE && !shift ? palette[activeblock] : 0); break;
|
|
case SDLK_RETURN: brush_floodfill(!shift ? palette[activeblock] : 0); break;
|
|
case SDLK_z: hist_undo(); break;
|
|
case SDLK_y: hist_redo(); break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rotate a single block
|
|
*/
|
|
void edit_rotate(int y, int z, int x, int ccw)
|
|
{
|
|
unsigned char oldparam2 = nodes[y][z][x].param2;
|
|
|
|
if(!nodes[y][z][x].param0) return;
|
|
if(ccw) {
|
|
nodes[y][z][x].param2++;
|
|
} else {
|
|
nodes[y][z][x].param2--;
|
|
}
|
|
if(oldparam2 != nodes[y][z][x].param2) {
|
|
hist_prepare(HIST_NODE, 0);
|
|
hist_add(y, z, x, nodes[y][z][x].param0, oldparam2, nodes[y][z][x].param0, nodes[y][z][x].param2);
|
|
hist_commit();
|
|
}
|
|
}
|