diff options
Diffstat (limited to 'src/engine/octaedit.cpp')
| -rw-r--r-- | src/engine/octaedit.cpp | 4221 |
1 files changed, 2110 insertions, 2111 deletions
diff --git a/src/engine/octaedit.cpp b/src/engine/octaedit.cpp index af69db9..fa987d0 100644 --- a/src/engine/octaedit.cpp +++ b/src/engine/octaedit.cpp @@ -6,88 +6,88 @@ bool boxoutline = false; void boxs(int orient, vec o, const vec &s, float size) { - int d = dimension(orient), dc = dimcoord(orient); - float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0; - o[D[d]] += dc * s[D[d]] + f; - - vec r(0, 0, 0), c(0, 0, 0); - r[R[d]] = s[R[d]]; - c[C[d]] = s[C[d]]; - - vec v1 = o, v2 = vec(o).add(r), v3 = vec(o).add(r).add(c), v4 = vec(o).add(c); - - r[R[d]] = 0.5f*size; - c[C[d]] = 0.5f*size; - - gle::defvertex(); - gle::begin(GL_TRIANGLE_STRIP); - gle::attrib(vec(v1).sub(r).sub(c)); - gle::attrib(vec(v1).add(r).add(c)); - gle::attrib(vec(v2).add(r).sub(c)); - gle::attrib(vec(v2).sub(r).add(c)); - gle::attrib(vec(v3).add(r).add(c)); - gle::attrib(vec(v3).sub(r).sub(c)); - gle::attrib(vec(v4).sub(r).add(c)); - gle::attrib(vec(v4).add(r).sub(c)); - gle::attrib(vec(v1).sub(r).sub(c)); - gle::attrib(vec(v1).add(r).add(c)); - xtraverts += gle::end(); + int d = dimension(orient), dc = dimcoord(orient); + float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0; + o[D[d]] += dc * s[D[d]] + f; + + vec r(0, 0, 0), c(0, 0, 0); + r[R[d]] = s[R[d]]; + c[C[d]] = s[C[d]]; + + vec v1 = o, v2 = vec(o).add(r), v3 = vec(o).add(r).add(c), v4 = vec(o).add(c); + + r[R[d]] = 0.5f*size; + c[C[d]] = 0.5f*size; + + gle::defvertex(); + gle::begin(GL_TRIANGLE_STRIP); + gle::attrib(vec(v1).sub(r).sub(c)); + gle::attrib(vec(v1).add(r).add(c)); + gle::attrib(vec(v2).add(r).sub(c)); + gle::attrib(vec(v2).sub(r).add(c)); + gle::attrib(vec(v3).add(r).add(c)); + gle::attrib(vec(v3).sub(r).sub(c)); + gle::attrib(vec(v4).sub(r).add(c)); + gle::attrib(vec(v4).add(r).sub(c)); + gle::attrib(vec(v1).sub(r).sub(c)); + gle::attrib(vec(v1).add(r).add(c)); + xtraverts += gle::end(); } void boxs(int orient, vec o, const vec &s) { - int d = dimension(orient), dc = dimcoord(orient); - float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0; - o[D[d]] += dc * s[D[d]] + f; + int d = dimension(orient), dc = dimcoord(orient); + float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0; + o[D[d]] += dc * s[D[d]] + f; - gle::defvertex(); - gle::begin(GL_LINE_LOOP); + gle::defvertex(); + gle::begin(GL_LINE_LOOP); - gle::attrib(o); o[R[d]] += s[R[d]]; - gle::attrib(o); o[C[d]] += s[C[d]]; - gle::attrib(o); o[R[d]] -= s[R[d]]; - gle::attrib(o); + gle::attrib(o); o[R[d]] += s[R[d]]; + gle::attrib(o); o[C[d]] += s[C[d]]; + gle::attrib(o); o[R[d]] -= s[R[d]]; + gle::attrib(o); - xtraverts += gle::end(); + xtraverts += gle::end(); } void boxs3D(const vec &o, vec s, int g) { - s.mul(g); - loopi(6) - boxs(i, o, s); + s.mul(g); + loopi(6) + boxs(i, o, s); } void boxsgrid(int orient, vec o, vec s, int g) { - int d = dimension(orient), dc = dimcoord(orient); - float ox = o[R[d]], - oy = o[C[d]], - xs = s[R[d]], - ys = s[C[d]], - f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0; - - o[D[d]] += dc * s[D[d]]*g + f; - - gle::defvertex(); - gle::begin(GL_LINES); - loop(x, xs) - { - o[R[d]] += g; - gle::attrib(o); - o[C[d]] += ys*g; - gle::attrib(o); - o[C[d]] = oy; - } - loop(y, ys) - { - o[C[d]] += g; - o[R[d]] = ox; - gle::attrib(o); - o[R[d]] += xs*g; - gle::attrib(o); - } - xtraverts += gle::end(); + int d = dimension(orient), dc = dimcoord(orient); + float ox = o[R[d]], + oy = o[C[d]], + xs = s[R[d]], + ys = s[C[d]], + f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0; + + o[D[d]] += dc * s[D[d]]*g + f; + + gle::defvertex(); + gle::begin(GL_LINES); + loop(x, xs) + { + o[R[d]] += g; + gle::attrib(o); + o[C[d]] += ys*g; + gle::attrib(o); + o[C[d]] = oy; + } + loop(y, ys) + { + o[C[d]] += g; + o[R[d]] = ox; + gle::attrib(o); + o[R[d]] += xs*g; + gle::attrib(o); + } + xtraverts += gle::end(); } selinfo sel, lastsel, savedsel; @@ -106,30 +106,30 @@ int horient = 0; extern int entmoving; VARF(dragging, 0, 0, 1, - if(!dragging || cor[0]<0) return; - lastcur = cur; - lastcor = cor; - sel.grid = gridsize; - sel.orient = orient; + if(!dragging || cor[0]<0) return; + lastcur = cur; + lastcor = cor; + sel.grid = gridsize; + sel.orient = orient; ); int moving = 0; ICOMMAND(moving, "b", (int *n), { - if(*n >= 0) - { - if(!*n || (moving<=1 && !pointinsel(sel, vec(cur).add(1)))) moving = 0; - else if(!moving) moving = 1; - } - intret(moving); + if(*n >= 0) + { + if(!*n || (moving<=1 && !pointinsel(sel, vec(cur).add(1)))) moving = 0; + else if(!moving) moving = 1; + } + intret(moving); }); VARF(gridpower, 0, 3, 12, { - if(dragging) return; - gridsize = 1<<gridpower; - if(gridsize>=worldsize) gridsize = worldsize/2; - cancelsel(); + if(dragging) return; + gridsize = 1<<gridpower; + if(gridsize>=worldsize) gridsize = worldsize/2; + cancelsel(); }); VAR(passthroughsel, 0, 0, 1); @@ -143,88 +143,88 @@ extern void hmapcancel(); void cubecancel() { - havesel = false; - moving = dragging = hmapedit = passthroughsel = 0; - forcenextundo(); - hmapcancel(); + havesel = false; + moving = dragging = hmapedit = passthroughsel = 0; + forcenextundo(); + hmapcancel(); } void cancelsel() { - cubecancel(); - entcancel(); + cubecancel(); + entcancel(); } void toggleedit(bool force) { - if(!force) - { - if(!isconnected()) return; - if(player->state!=CS_ALIVE && player->state!=CS_DEAD && player->state!=CS_EDITING) return; // do not allow dead players to edit to avoid state confusion - if(!game::allowedittoggle()) return; // not in most multiplayer modes - } - if(!(editmode = !editmode)) - { - player->state = player->editstate; - player->o.z -= player->eyeheight; // entinmap wants feet pos - entinmap(player); // find spawn closest to current floating pos - } - else - { - game::resetgamestate(); - player->editstate = player->state; - player->state = CS_EDITING; - } - cancelsel(); - stoppaintblendmap(); - keyrepeat(editmode); - editing = entediting = editmode; - extern int fullbright; - if(fullbright) { initlights(); lightents(); } - if(!force) game::edittoggled(editmode); + if(!force) + { + if(!isconnected()) return; + if(player->state!=CS_ALIVE && player->state!=CS_DEAD && player->state!=CS_EDITING) return; // do not allow dead players to edit to avoid state confusion + if(!game::allowedittoggle()) return; // not in most multiplayer modes + } + if(!(editmode = !editmode)) + { + player->state = player->editstate; + player->o.z -= player->eyeheight; // entinmap wants feet pos + entinmap(player); // find spawn closest to current floating pos + } + else + { + game::resetgamestate(); + player->editstate = player->state; + player->state = CS_EDITING; + } + cancelsel(); + stoppaintblendmap(); + keyrepeat(editmode); + editing = entediting = editmode; + extern int fullbright; + if(fullbright) { initlights(); lightents(); } + if(!force) game::edittoggled(editmode); } VARP(editinview, 0, 1, 1); bool noedit(bool view, bool msg) { - if(!editmode) { if(msg) conoutf(CON_ERROR, "operation only allowed in edit mode"); return true; } - if(view || haveselent()) return false; - float r = 1.0f; - vec o(sel.o), s(sel.s); - s.mul(float(sel.grid) / 2.0f); - o.add(s); - r = float(max(s.x, max(s.y, s.z))); - bool viewable = (isvisiblesphere(r, o) != VFC_NOT_VISIBLE); - if(viewable || !editinview) return false; - if(msg) conoutf(CON_ERROR, "selection not in view"); - return true; + if(!editmode) { if(msg) conoutf(CON_ERROR, "operation only allowed in edit mode"); return true; } + if(view || haveselent()) return false; + float r = 1.0f; + vec o(sel.o), s(sel.s); + s.mul(float(sel.grid) / 2.0f); + o.add(s); + r = float(max(s.x, max(s.y, s.z))); + bool viewable = (isvisiblesphere(r, o) != VFC_NOT_VISIBLE); + if(viewable || !editinview) return false; + if(msg) conoutf(CON_ERROR, "selection not in view"); + return true; } void reorient() { - sel.cx = 0; - sel.cy = 0; - sel.cxs = sel.s[R[dimension(orient)]]*2; - sel.cys = sel.s[C[dimension(orient)]]*2; - sel.orient = orient; + sel.cx = 0; + sel.cy = 0; + sel.cxs = sel.s[R[dimension(orient)]]*2; + sel.cys = sel.s[C[dimension(orient)]]*2; + sel.orient = orient; } void selextend() { - if(noedit(true)) return; - loopi(3) - { - if(cur[i]<sel.o[i]) - { - sel.s[i] += (sel.o[i]-cur[i])/sel.grid; - sel.o[i] = cur[i]; - } - else if(cur[i]>=sel.o[i]+sel.s[i]*sel.grid) - { - sel.s[i] = (cur[i]-sel.o[i])/sel.grid+1; - } - } + if(noedit(true)) return; + loopi(3) + { + if(cur[i]<sel.o[i]) + { + sel.s[i] += (sel.o[i]-cur[i])/sel.grid; + sel.o[i] = cur[i]; + } + else if(cur[i]>=sel.o[i]+sel.s[i]*sel.grid) + { + sel.s[i] = (cur[i]-sel.o[i])/sel.grid+1; + } + } } ICOMMAND(edittoggle, "", (), toggleedit(false)); @@ -241,24 +241,24 @@ ICOMMAND(selswap, "", (), { if(noedit(true)) return; swap(sel, savedsel); }); ICOMMAND(getselpos, "", (), { - if(noedit(true)) return; - defformatstring(pos, "%s %s %s", floatstr(sel.o.x), floatstr(sel.o.y), floatstr(sel.o.z)); - result(pos); + if(noedit(true)) return; + defformatstring(pos, "%s %s %s", floatstr(sel.o.x), floatstr(sel.o.y), floatstr(sel.o.z)); + result(pos); }); void setselpos(int *x, int *y, int *z) { - if(noedit(moving!=0)) return; - havesel = true; - sel.o = ivec(*x, *y, *z).mask(~(gridsize-1)); + if(noedit(moving!=0)) return; + havesel = true; + sel.o = ivec(*x, *y, *z).mask(~(gridsize-1)); } COMMAND(setselpos, "iii"); void movesel(int *dir, int *dim) { - if(noedit(moving!=0)) return; - if(*dim < 0 || *dim > 2) return; - sel.o[*dim] += *dir * sel.grid; + if(noedit(moving!=0)) return; + if(*dim < 0 || *dim > 2) return; + sel.o[*dim] += *dir * sel.grid; } COMMAND(movesel, "ii"); @@ -266,16 +266,16 @@ COMMAND(movesel, "ii"); cube &blockcube(int x, int y, int z, const block3 &b, int rgrid) // looks up a world cube, based on coordinates mapped by the block { - int dim = dimension(b.orient), dc = dimcoord(b.orient); - ivec s(dim, x*b.grid, y*b.grid, dc*(b.s[dim]-1)*b.grid); - s.add(b.o); - if(dc) s[dim] -= z*b.grid; else s[dim] += z*b.grid; - return lookupcube(s, rgrid); + int dim = dimension(b.orient), dc = dimcoord(b.orient); + ivec s(dim, x*b.grid, y*b.grid, dc*(b.s[dim]-1)*b.grid); + s.add(b.o); + if(dc) s[dim] -= z*b.grid; else s[dim] += z*b.grid; + return lookupcube(s, rgrid); } -#define loopxy(b) loop(y,(b).s[C[dimension((b).orient)]]) loop(x,(b).s[R[dimension((b).orient)]]) +#define loopxy(b) loop(y,(b).s[C[dimension((b).orient)]]) loop(x,(b).s[R[dimension((b).orient)]]) #define loopxyz(b, r, f) { loop(z,(b).s[D[dimension((b).orient)]]) loopxy((b)) { cube &c = blockcube(x,y,z,b,r); f; } } -#define loopselxyz(f) { if(local) makeundo(); loopxyz(sel, sel.grid, f); changed(sel); } +#define loopselxyz(f) { if(local) makeundo(); loopxyz(sel, sel.grid, f); changed(sel); } #define selcube(x, y, z) blockcube(x, y, z, sel, sel.grid) ////////////// cursor /////////////// @@ -286,61 +286,61 @@ ICOMMAND(havesel, "", (), intret(havesel ? selchildcount : 0)); void countselchild(cube *c, const ivec &cor, int size) { - ivec ss = ivec(sel.s).mul(sel.grid); - loopoctaboxsize(cor, size, sel.o, ss) - { - ivec o(i, cor, size); - if(c[i].children) countselchild(c[i].children, o, size/2); - else - { - selchildcount++; - if(c[i].material != MAT_AIR && selchildmat != MAT_AIR) - { - if(selchildmat < 0) selchildmat = c[i].material; - else if(selchildmat != c[i].material) selchildmat = MAT_AIR; - } - } - } + ivec ss = ivec(sel.s).mul(sel.grid); + loopoctaboxsize(cor, size, sel.o, ss) + { + ivec o(i, cor, size); + if(c[i].children) countselchild(c[i].children, o, size/2); + else + { + selchildcount++; + if(c[i].material != MAT_AIR && selchildmat != MAT_AIR) + { + if(selchildmat < 0) selchildmat = c[i].material; + else if(selchildmat != c[i].material) selchildmat = MAT_AIR; + } + } + } } void normalizelookupcube(const ivec &o) { - if(lusize>gridsize) - { - lu.x += (o.x-lu.x)/gridsize*gridsize; - lu.y += (o.y-lu.y)/gridsize*gridsize; - lu.z += (o.z-lu.z)/gridsize*gridsize; - } - else if(gridsize>lusize) - { - lu.x &= ~(gridsize-1); - lu.y &= ~(gridsize-1); - lu.z &= ~(gridsize-1); - } - lusize = gridsize; + if(lusize>gridsize) + { + lu.x += (o.x-lu.x)/gridsize*gridsize; + lu.y += (o.y-lu.y)/gridsize*gridsize; + lu.z += (o.z-lu.z)/gridsize*gridsize; + } + else if(gridsize>lusize) + { + lu.x &= ~(gridsize-1); + lu.y &= ~(gridsize-1); + lu.z &= ~(gridsize-1); + } + lusize = gridsize; } void updateselection() { - sel.o.x = min(lastcur.x, cur.x); - sel.o.y = min(lastcur.y, cur.y); - sel.o.z = min(lastcur.z, cur.z); - sel.s.x = abs(lastcur.x-cur.x)/sel.grid+1; - sel.s.y = abs(lastcur.y-cur.y)/sel.grid+1; - sel.s.z = abs(lastcur.z-cur.z)/sel.grid+1; + sel.o.x = min(lastcur.x, cur.x); + sel.o.y = min(lastcur.y, cur.y); + sel.o.z = min(lastcur.z, cur.z); + sel.s.x = abs(lastcur.x-cur.x)/sel.grid+1; + sel.s.y = abs(lastcur.y-cur.y)/sel.grid+1; + sel.s.z = abs(lastcur.z-cur.z)/sel.grid+1; } bool editmoveplane(const vec &o, const vec &ray, int d, float off, vec &handle, vec &dest, bool first) { - plane pl(d, off); - float dist = 0.0f; - if(!pl.rayintersect(player->o, ray, dist)) - return false; + plane pl(d, off); + float dist = 0.0f; + if(!pl.rayintersect(player->o, ray, dist)) + return false; - dest = vec(ray).mul(dist).add(player->o); - if(first) handle = vec(dest).sub(o); - dest.sub(handle); - return true; + dest = vec(ray).mul(dist).add(player->o); + if(first) handle = vec(dest).sub(o); + dest.sub(handle); + return true; } inline bool isheightmap(int orient, int d, bool empty, cube *c); @@ -356,203 +356,203 @@ VARF(passthrough, 0, 0, 1, { passthroughsel = passthrough; entcancel(); }); void rendereditcursor() { - int d = dimension(sel.orient), - od = dimension(orient), - odc = dimcoord(orient); - - bool hidecursor = g3d_windowhit(true, false) || blendpaintmode, hovering = false; - hmapsel = false; - - if(moving) - { - static vec dest, handle; - if(editmoveplane(vec(sel.o), camdir, od, sel.o[D[od]]+odc*sel.grid*sel.s[D[od]], handle, dest, moving==1)) - { - if(moving==1) - { - dest.add(handle); - handle = vec(ivec(handle).mask(~(sel.grid-1))); - dest.sub(handle); - moving = 2; - } - ivec o = ivec(dest).mask(~(sel.grid-1)); - sel.o[R[od]] = o[R[od]]; - sel.o[C[od]] = o[C[od]]; - } - } - else - if(entmoving) - { - entdrag(camdir); - } - else - { - ivec w; - float sdist = 0, wdist = 0, t; - int entorient = 0, ent = -1; - - wdist = rayent(player->o, camdir, 1e16f, - (editmode && showmat ? RAY_EDITMAT : 0) // select cubes first - | (!dragging && entediting && (!passthrough || !passthroughent) ? RAY_ENTS : 0) - | RAY_SKIPFIRST - | (passthroughcube || passthrough ? RAY_PASS : 0), gridsize, entorient, ent); - - if((havesel || dragging) && !passthroughsel && !hmapedit) // now try selecting the selection - if(rayboxintersect(vec(sel.o), vec(sel.s).mul(sel.grid), player->o, camdir, sdist, orient)) - { // and choose the nearest of the two - if(sdist < wdist) - { - wdist = sdist; - ent = -1; - } - } - - if((hovering = hoveringonent(hidecursor ? -1 : ent, entorient))) - { - if(!havesel) - { - selchildcount = 0; - selchildmat = -1; - sel.s = ivec(0, 0, 0); - } - } - else - { - vec w = vec(camdir).mul(wdist+0.05f).add(player->o); - if(!insideworld(w)) - { - loopi(3) wdist = min(wdist, ((camdir[i] > 0 ? worldsize : 0) - player->o[i]) / camdir[i]); - w = vec(camdir).mul(wdist-0.05f).add(player->o); - if(!insideworld(w)) - { - wdist = 0; - loopi(3) w[i] = clamp(player->o[i], 0.0f, float(worldsize)); - } - } - cube *c = &lookupcube(ivec(w)); - if(gridlookup && !dragging && !moving && !havesel && hmapedit!=1) gridsize = lusize; - int mag = lusize / gridsize; - normalizelookupcube(ivec(w)); - if(sdist == 0 || sdist > wdist) rayboxintersect(vec(lu), vec(gridsize), player->o, camdir, t=0, orient); // just getting orient - cur = lu; - cor = ivec(vec(w).mul(2).div(gridsize)); - od = dimension(orient); - d = dimension(sel.orient); - - if(hmapedit==1 && dimcoord(horient) == (camdir[dimension(horient)]<0)) - { - hmapsel = isheightmap(horient, dimension(horient), false, c); - if(hmapsel) - od = dimension(orient = horient); - } - - if(dragging) - { - updateselection(); - sel.cx = min(cor[R[d]], lastcor[R[d]]); - sel.cy = min(cor[C[d]], lastcor[C[d]]); - sel.cxs = max(cor[R[d]], lastcor[R[d]]); - sel.cys = max(cor[C[d]], lastcor[C[d]]); - - if(!selectcorners) - { - sel.cx &= ~1; - sel.cy &= ~1; - sel.cxs &= ~1; - sel.cys &= ~1; - sel.cxs -= sel.cx-2; - sel.cys -= sel.cy-2; - } - else - { - sel.cxs -= sel.cx-1; - sel.cys -= sel.cy-1; - } - - sel.cx &= 1; - sel.cy &= 1; - havesel = true; - } - else if(!havesel) - { - sel.o = lu; - sel.s.x = sel.s.y = sel.s.z = 1; - sel.cx = sel.cy = 0; - sel.cxs = sel.cys = 2; - sel.grid = gridsize; - sel.orient = orient; - d = od; - } - - sel.corner = (cor[R[d]]-(lu[R[d]]*2)/gridsize)+(cor[C[d]]-(lu[C[d]]*2)/gridsize)*2; - selchildcount = 0; - selchildmat = -1; - countselchild(worldroot, ivec(0, 0, 0), worldsize/2); - if(mag>=1 && selchildcount==1) - { - selchildmat = c->material; - if(mag>1) selchildcount = -mag; - } - } - } - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - - // cursors - - notextureshader->set(); - - renderentselection(player->o, camdir, entmoving!=0); - - boxoutline = outline!=0; - - enablepolygonoffset(GL_POLYGON_OFFSET_LINE); - - if(!moving && !hovering && !hidecursor) - { - if(hmapedit==1) - gle::colorub(0, hmapsel ? 255 : 40, 0); - else - gle::colorub(120,120,120); - boxs(orient, vec(lu), vec(lusize)); - } - - // selections - if(havesel || moving) - { - d = dimension(sel.orient); - gle::colorub(50,50,50); // grid - boxsgrid(sel.orient, vec(sel.o), vec(sel.s), sel.grid); - gle::colorub(200,0,0); // 0 reference - boxs3D(vec(sel.o).sub(0.5f*min(gridsize*0.25f, 2.0f)), vec(min(gridsize*0.25f, 2.0f)), 1); - gle::colorub(200,200,200);// 2D selection box - vec co(sel.o.v), cs(sel.s.v); - co[R[d]] += 0.5f*(sel.cx*gridsize); - co[C[d]] += 0.5f*(sel.cy*gridsize); - cs[R[d]] = 0.5f*(sel.cxs*gridsize); - cs[C[d]] = 0.5f*(sel.cys*gridsize); - cs[D[d]] *= gridsize; - boxs(sel.orient, co, cs); - if(hmapedit==1) // 3D selection box - gle::colorub(0,120,0); - else - gle::colorub(0,0,120); - boxs3D(vec(sel.o), vec(sel.s), sel.grid); - } - - disablepolygonoffset(GL_POLYGON_OFFSET_LINE); - - boxoutline = false; - - glDisable(GL_BLEND); + int d = dimension(sel.orient), + od = dimension(orient), + odc = dimcoord(orient); + + bool hidecursor = g3d_windowhit(true, false) || blendpaintmode, hovering = false; + hmapsel = false; + + if(moving) + { + static vec dest, handle; + if(editmoveplane(vec(sel.o), camdir, od, sel.o[D[od]]+odc*sel.grid*sel.s[D[od]], handle, dest, moving==1)) + { + if(moving==1) + { + dest.add(handle); + handle = vec(ivec(handle).mask(~(sel.grid-1))); + dest.sub(handle); + moving = 2; + } + ivec o = ivec(dest).mask(~(sel.grid-1)); + sel.o[R[od]] = o[R[od]]; + sel.o[C[od]] = o[C[od]]; + } + } + else + if(entmoving) + { + entdrag(camdir); + } + else + { + ivec w; + float sdist = 0, wdist = 0, t; + int entorient = 0, ent = -1; + + wdist = rayent(player->o, camdir, 1e16f, + (editmode && showmat ? RAY_EDITMAT : 0) // select cubes first + | (!dragging && entediting && (!passthrough || !passthroughent) ? RAY_ENTS : 0) + | RAY_SKIPFIRST + | (passthroughcube || passthrough ? RAY_PASS : 0), gridsize, entorient, ent); + + if((havesel || dragging) && !passthroughsel && !hmapedit) // now try selecting the selection + if(rayboxintersect(vec(sel.o), vec(sel.s).mul(sel.grid), player->o, camdir, sdist, orient)) + { // and choose the nearest of the two + if(sdist < wdist) + { + wdist = sdist; + ent = -1; + } + } + + if((hovering = hoveringonent(hidecursor ? -1 : ent, entorient))) + { + if(!havesel) + { + selchildcount = 0; + selchildmat = -1; + sel.s = ivec(0, 0, 0); + } + } + else + { + vec w = vec(camdir).mul(wdist+0.05f).add(player->o); + if(!insideworld(w)) + { + loopi(3) wdist = min(wdist, ((camdir[i] > 0 ? worldsize : 0) - player->o[i]) / camdir[i]); + w = vec(camdir).mul(wdist-0.05f).add(player->o); + if(!insideworld(w)) + { + wdist = 0; + loopi(3) w[i] = clamp(player->o[i], 0.0f, float(worldsize)); + } + } + cube *c = &lookupcube(ivec(w)); + if(gridlookup && !dragging && !moving && !havesel && hmapedit!=1) gridsize = lusize; + int mag = lusize / gridsize; + normalizelookupcube(ivec(w)); + if(sdist == 0 || sdist > wdist) rayboxintersect(vec(lu), vec(gridsize), player->o, camdir, t=0, orient); // just getting orient + cur = lu; + cor = ivec(vec(w).mul(2).div(gridsize)); + od = dimension(orient); + d = dimension(sel.orient); + + if(hmapedit==1 && dimcoord(horient) == (camdir[dimension(horient)]<0)) + { + hmapsel = isheightmap(horient, dimension(horient), false, c); + if(hmapsel) + od = dimension(orient = horient); + } + + if(dragging) + { + updateselection(); + sel.cx = min(cor[R[d]], lastcor[R[d]]); + sel.cy = min(cor[C[d]], lastcor[C[d]]); + sel.cxs = max(cor[R[d]], lastcor[R[d]]); + sel.cys = max(cor[C[d]], lastcor[C[d]]); + + if(!selectcorners) + { + sel.cx &= ~1; + sel.cy &= ~1; + sel.cxs &= ~1; + sel.cys &= ~1; + sel.cxs -= sel.cx-2; + sel.cys -= sel.cy-2; + } + else + { + sel.cxs -= sel.cx-1; + sel.cys -= sel.cy-1; + } + + sel.cx &= 1; + sel.cy &= 1; + havesel = true; + } + else if(!havesel) + { + sel.o = lu; + sel.s.x = sel.s.y = sel.s.z = 1; + sel.cx = sel.cy = 0; + sel.cxs = sel.cys = 2; + sel.grid = gridsize; + sel.orient = orient; + d = od; + } + + sel.corner = (cor[R[d]]-(lu[R[d]]*2)/gridsize)+(cor[C[d]]-(lu[C[d]]*2)/gridsize)*2; + selchildcount = 0; + selchildmat = -1; + countselchild(worldroot, ivec(0, 0, 0), worldsize/2); + if(mag>=1 && selchildcount==1) + { + selchildmat = c->material; + if(mag>1) selchildcount = -mag; + } + } + } + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + + // cursors + + notextureshader->set(); + + renderentselection(player->o, camdir, entmoving!=0); + + boxoutline = outline!=0; + + enablepolygonoffset(GL_POLYGON_OFFSET_LINE); + + if(!moving && !hovering && !hidecursor) + { + if(hmapedit==1) + gle::colorub(0, hmapsel ? 255 : 40, 0); + else + gle::colorub(120,120,120); + boxs(orient, vec(lu), vec(lusize)); + } + + // selections + if(havesel || moving) + { + d = dimension(sel.orient); + gle::colorub(50,50,50); // grid + boxsgrid(sel.orient, vec(sel.o), vec(sel.s), sel.grid); + gle::colorub(200,0,0); // 0 reference + boxs3D(vec(sel.o).sub(0.5f*min(gridsize*0.25f, 2.0f)), vec(min(gridsize*0.25f, 2.0f)), 1); + gle::colorub(200,200,200);// 2D selection box + vec co(sel.o.v), cs(sel.s.v); + co[R[d]] += 0.5f*(sel.cx*gridsize); + co[C[d]] += 0.5f*(sel.cy*gridsize); + cs[R[d]] = 0.5f*(sel.cxs*gridsize); + cs[C[d]] = 0.5f*(sel.cys*gridsize); + cs[D[d]] *= gridsize; + boxs(sel.orient, co, cs); + if(hmapedit==1) // 3D selection box + gle::colorub(0,120,0); + else + gle::colorub(0,0,120); + boxs3D(vec(sel.o), vec(sel.s), sel.grid); + } + + disablepolygonoffset(GL_POLYGON_OFFSET_LINE); + + boxoutline = false; + + glDisable(GL_BLEND); } void tryedit() { - extern int hidehud; - if(!editmode || hidehud || mainmenu) return; - if(blendpaintmode) trypaintblendmap(); + extern int hidehud; + if(!editmode || hidehud || mainmenu) return; + if(blendpaintmode) trypaintblendmap(); } //////////// ready changes to vertex arrays //////////// @@ -561,197 +561,196 @@ static bool haschanged = false; void readychanges(const ivec &bbmin, const ivec &bbmax, cube *c, const ivec &cor, int size) { - loopoctabox(cor, size, bbmin, bbmax) - { - ivec o(i, cor, size); - if(c[i].ext) - { - if(c[i].ext->va) // removes va s so that octarender will recreate - { - int hasmerges = c[i].ext->va->hasmerges; - destroyva(c[i].ext->va); - c[i].ext->va = NULL; - if(hasmerges) invalidatemerges(c[i], o, size, true); - } - freeoctaentities(c[i]); - c[i].ext->tjoints = -1; - } - if(c[i].children) - { - if(size<=1) - { - solidfaces(c[i]); - discardchildren(c[i], true); - brightencube(c[i]); - } - else readychanges(bbmin, bbmax, c[i].children, o, size/2); - } - else brightencube(c[i]); - } + loopoctabox(cor, size, bbmin, bbmax) + { + ivec o(i, cor, size); + if(c[i].ext) + { + if(c[i].ext->va) // removes va s so that octarender will recreate + { + int hasmerges = c[i].ext->va->hasmerges; + destroyva(c[i].ext->va); + c[i].ext->va = NULL; + if(hasmerges) invalidatemerges(c[i], o, size, true); + } + freeoctaentities(c[i]); + c[i].ext->tjoints = -1; + } + if(c[i].children) + { + if(size<=1) + { + solidfaces(c[i]); + discardchildren(c[i], true); + brightencube(c[i]); + } + else readychanges(bbmin, bbmax, c[i].children, o, size/2); + } + else brightencube(c[i]); + } } void commitchanges(bool force) { - if(!force && !haschanged) return; - haschanged = false; + if(!force && !haschanged) return; + haschanged = false; - int oldlen = valist.length(); - resetclipplanes(); - entitiesinoctanodes(); - inbetweenframes = false; - octarender(); - inbetweenframes = true; - setupmaterials(oldlen); - invalidatepostfx(); - updatevabbs(); + int oldlen = valist.length(); + resetclipplanes(); + entitiesinoctanodes(); + inbetweenframes = false; + octarender(); + inbetweenframes = true; + setupmaterials(oldlen); + updatevabbs(); } void changed(const block3 &sel, bool commit = true) { - if(sel.s.iszero()) return; - readychanges(ivec(sel.o).sub(1), ivec(sel.s).mul(sel.grid).add(sel.o).add(1), worldroot, ivec(0, 0, 0), worldsize/2); - haschanged = true; + if(sel.s.iszero()) return; + readychanges(ivec(sel.o).sub(1), ivec(sel.s).mul(sel.grid).add(sel.o).add(1), worldroot, ivec(0, 0, 0), worldsize/2); + haschanged = true; - if(commit) commitchanges(); + if(commit) commitchanges(); } //////////// copy and undo ///////////// static inline void copycube(const cube &src, cube &dst) { - dst = src; - dst.visible = 0; - dst.merged = 0; - dst.ext = NULL; // src cube is responsible for va destruction - if(src.children) - { - dst.children = newcubes(F_EMPTY); - loopi(8) copycube(src.children[i], dst.children[i]); - } + dst = src; + dst.visible = 0; + dst.merged = 0; + dst.ext = NULL; // src cube is responsible for va destruction + if(src.children) + { + dst.children = newcubes(F_EMPTY); + loopi(8) copycube(src.children[i], dst.children[i]); + } } static inline void pastecube(const cube &src, cube &dst) { - discardchildren(dst); - copycube(src, dst); + discardchildren(dst); + copycube(src, dst); } void blockcopy(const block3 &s, int rgrid, block3 *b) { - *b = s; - cube *q = b->c(); - loopxyz(s, rgrid, copycube(c, *q++)); + *b = s; + cube *q = b->c(); + loopxyz(s, rgrid, copycube(c, *q++)); } block3 *blockcopy(const block3 &s, int rgrid) { - int bsize = sizeof(block3)+sizeof(cube)*s.size(); - if(bsize <= 0 || bsize > (100<<20)) return NULL; - block3 *b = (block3 *)new (false) uchar[bsize]; - if(b) blockcopy(s, rgrid, b); - return b; + int bsize = sizeof(block3)+sizeof(cube)*s.size(); + if(bsize <= 0 || bsize > (100<<20)) return NULL; + block3 *b = (block3 *)new (false) uchar[bsize]; + if(b) blockcopy(s, rgrid, b); + return b; } void freeblock(block3 *b, bool alloced = true) { - cube *q = b->c(); - loopi(b->size()) discardchildren(*q++); - if(alloced) delete[] b; + cube *q = b->c(); + loopi(b->size()) discardchildren(*q++); + if(alloced) delete[] b; } -void selgridmap(selinfo &sel, uchar *g) // generates a map of the cube sizes at each grid point +void selgridmap(selinfo &sel, uchar *g) // generates a map of the cube sizes at each grid point { - loopxyz(sel, -sel.grid, (*g++ = bitscan(lusize), (void)c)); + loopxyz(sel, -sel.grid, (*g++ = bitscan(lusize), (void)c)); } void freeundo(undoblock *u) { - if(!u->numents) freeblock(u->block(), false); - delete[] (uchar *)u; + if(!u->numents) freeblock(u->block(), false); + delete[] (uchar *)u; } void pasteundoblock(block3 *b, uchar *g) { - cube *s = b->c(); - loopxyz(*b, 1<<min(int(*g++), worldscale-1), pastecube(*s++, c)); + cube *s = b->c(); + loopxyz(*b, 1<<min(int(*g++), worldscale-1), pastecube(*s++, c)); } void pasteundo(undoblock *u) { - if(u->numents) pasteundoents(u); - else pasteundoblock(u->block(), u->gridmap()); + if(u->numents) pasteundoents(u); + else pasteundoblock(u->block(), u->gridmap()); } static inline int undosize(undoblock *u) { - if(u->numents) return u->numents*sizeof(undoent); - else - { - block3 *b = u->block(); - cube *q = b->c(); - int size = b->size(), total = size; - loopj(size) total += familysize(*q++)*sizeof(cube); - return total; - } + if(u->numents) return u->numents*sizeof(undoent); + else + { + block3 *b = u->block(); + cube *q = b->c(); + int size = b->size(), total = size; + loopj(size) total += familysize(*q++)*sizeof(cube); + return total; + } } struct undolist { - undoblock *first, *last; - - undolist() : first(NULL), last(NULL) {} - - bool empty() { return !first; } - - void add(undoblock *u) - { - u->next = NULL; - u->prev = last; - if(!first) first = last = u; - else - { - last->next = u; - last = u; - } - } - - undoblock *popfirst() - { - undoblock *u = first; - first = first->next; - if(first) first->prev = NULL; - else last = NULL; - return u; - } - - undoblock *poplast() - { - undoblock *u = last; - last = last->prev; - if(last) last->next = NULL; - else first = NULL; - return u; - } + undoblock *first, *last; + + undolist() : first(NULL), last(NULL) {} + + bool empty() { return !first; } + + void add(undoblock *u) + { + u->next = NULL; + u->prev = last; + if(!first) first = last = u; + else + { + last->next = u; + last = u; + } + } + + undoblock *popfirst() + { + undoblock *u = first; + first = first->next; + if(first) first->prev = NULL; + else last = NULL; + return u; + } + + undoblock *poplast() + { + undoblock *u = last; + last = last->prev; + if(last) last->next = NULL; + else first = NULL; + return u; + } }; undolist undos, redos; -VARP(undomegs, 0, 8, 100); // bounded by n megs +VARP(undomegs, 0, 8, 100); // bounded by n megs int totalundos = 0; -void pruneundos(int maxremain) // bound memory +void pruneundos(int maxremain) // bound memory { - while(totalundos > maxremain && !undos.empty()) - { - undoblock *u = undos.popfirst(); - totalundos -= u->size; - freeundo(u); - } - //conoutf(CON_DEBUG, "undo: %d of %d(%%%d)", totalundos, undomegs<<20, totalundos*100/(undomegs<<20)); - while(!redos.empty()) - { - undoblock *u = redos.popfirst(); - totalundos -= u->size; - freeundo(u); - } + while(totalundos > maxremain && !undos.empty()) + { + undoblock *u = undos.popfirst(); + totalundos -= u->size; + freeundo(u); + } + //conoutf(CON_DEBUG, "undo: %d of %d(%%%d)", totalundos, undomegs<<20, totalundos*100/(undomegs<<20)); + while(!redos.empty()) + { + undoblock *u = redos.popfirst(); + totalundos -= u->size; + freeundo(u); + } } void clearundos() { pruneundos(0); } @@ -760,106 +759,106 @@ COMMAND(clearundos, ""); undoblock *newundocube(selinfo &s) { - int ssize = s.size(), - selgridsize = ssize, - blocksize = sizeof(block3)+ssize*sizeof(cube); - if(blocksize <= 0 || blocksize > (undomegs<<20)) return NULL; - undoblock *u = (undoblock *)new (false) uchar[sizeof(undoblock) + blocksize + selgridsize]; - if(!u) return NULL; - u->numents = 0; - block3 *b = u->block(); - blockcopy(s, -s.grid, b); - uchar *g = u->gridmap(); - selgridmap(s, g); - return u; + int ssize = s.size(), + selgridsize = ssize, + blocksize = sizeof(block3)+ssize*sizeof(cube); + if(blocksize <= 0 || blocksize > (undomegs<<20)) return NULL; + undoblock *u = (undoblock *)new (false) uchar[sizeof(undoblock) + blocksize + selgridsize]; + if(!u) return NULL; + u->numents = 0; + block3 *b = u->block(); + blockcopy(s, -s.grid, b); + uchar *g = u->gridmap(); + selgridmap(s, g); + return u; } void addundo(undoblock *u) { - u->size = undosize(u); - u->timestamp = totalmillis; - undos.add(u); - totalundos += u->size; - pruneundos(undomegs<<20); + u->size = undosize(u); + u->timestamp = totalmillis; + undos.add(u); + totalundos += u->size; + pruneundos(undomegs<<20); } VARP(nompedit, 0, 1, 1); void makeundo(selinfo &s) { - undoblock *u = newundocube(s); - if(u) addundo(u); + undoblock *u = newundocube(s); + if(u) addundo(u); } -void makeundo() // stores state of selected cubes before editing +void makeundo() // stores state of selected cubes before editing { - if(lastsel==sel || sel.s.iszero()) return; - lastsel=sel; - makeundo(sel); + if(lastsel==sel || sel.s.iszero()) return; + lastsel=sel; + makeundo(sel); } static inline int countblock(cube *c, int n = 8) { - int r = 0; - loopi(n) if(c[i].children) r += countblock(c[i].children); else ++r; - return r; + int r = 0; + loopi(n) if(c[i].children) r += countblock(c[i].children); else ++r; + return r; } static int countblock(block3 *b) { return countblock(b->c(), b->size()); } void swapundo(undolist &a, undolist &b, int op) { - if(noedit()) return; - if(a.empty()) { conoutf(CON_WARN, "nothing more to %s", op == EDIT_REDO ? "redo" : "undo"); return; } - int ts = a.last->timestamp; - if(multiplayer(false)) - { - int n = 0, ops = 0; - for(undoblock *u = a.last; u && ts==u->timestamp; u = u->prev) - { - ++ops; - n += u->numents ? u->numents : countblock(u->block()); - if(ops > 10 || n > 2500) - { - conoutf(CON_WARN, "undo too big for multiplayer"); - if(nompedit) { multiplayer(); return; } - op = -1; - break; - } - } - } - selinfo l = sel; - while(!a.empty() && ts==a.last->timestamp) - { - if(op >= 0) game::edittrigger(sel, op); - undoblock *u = a.poplast(), *r; - if(u->numents) r = copyundoents(u); - else - { - block3 *ub = u->block(); - l.o = ub->o; - l.s = ub->s; - l.grid = ub->grid; - l.orient = ub->orient; - r = newundocube(l); - } - if(r) - { - r->size = u->size; - r->timestamp = totalmillis; - b.add(r); - } - pasteundo(u); - if(!u->numents) changed(*u->block(), false); - freeundo(u); - } - commitchanges(); - if(!hmapsel) - { - sel = l; - reorient(); - } - forcenextundo(); + if(noedit()) return; + if(a.empty()) { conoutf(CON_WARN, "nothing more to %s", op == EDIT_REDO ? "redo" : "undo"); return; } + int ts = a.last->timestamp; + if(multiplayer(false)) + { + int n = 0, ops = 0; + for(undoblock *u = a.last; u && ts==u->timestamp; u = u->prev) + { + ++ops; + n += u->numents ? u->numents : countblock(u->block()); + if(ops > 10 || n > 2500) + { + conoutf(CON_WARN, "undo too big for multiplayer"); + if(nompedit) { multiplayer(); return; } + op = -1; + break; + } + } + } + selinfo l = sel; + while(!a.empty() && ts==a.last->timestamp) + { + if(op >= 0) game::edittrigger(sel, op); + undoblock *u = a.poplast(), *r; + if(u->numents) r = copyundoents(u); + else + { + block3 *ub = u->block(); + l.o = ub->o; + l.s = ub->s; + l.grid = ub->grid; + l.orient = ub->orient; + r = newundocube(l); + } + if(r) + { + r->size = u->size; + r->timestamp = totalmillis; + b.add(r); + } + pasteundo(u); + if(!u->numents) changed(*u->block(), false); + freeundo(u); + } + commitchanges(); + if(!hmapsel) + { + sel = l; + reorient(); + } + forcenextundo(); } void editundo() { swapundo(undos, redos, EDIT_UNDO); } @@ -874,388 +873,388 @@ editinfo *localedit = NULL; template<class B> static void packcube(cube &c, B &buf) { - if(c.children) - { - buf.put(0xFF); - loopi(8) packcube(c.children[i], buf); - } - else - { - cube data = c; - lilswap(data.texture, 6); - buf.put(c.material&0xFF); - buf.put(c.material>>8); - buf.put(data.edges, sizeof(data.edges)); - buf.put((uchar *)data.texture, sizeof(data.texture)); - } + if(c.children) + { + buf.put(0xFF); + loopi(8) packcube(c.children[i], buf); + } + else + { + cube data = c; + lilswap(data.texture, 6); + buf.put(c.material&0xFF); + buf.put(c.material>>8); + buf.put(data.edges, sizeof(data.edges)); + buf.put((uchar *)data.texture, sizeof(data.texture)); + } } template<class B> static bool packblock(block3 &b, B &buf) { - if(b.size() <= 0 || b.size() > (1<<20)) return false; - block3 hdr = b; - lilswap(hdr.o.v, 3); - lilswap(hdr.s.v, 3); - lilswap(&hdr.grid, 1); - lilswap(&hdr.orient, 1); - buf.put((const uchar *)&hdr, sizeof(hdr)); - cube *c = b.c(); - loopi(b.size()) packcube(c[i], buf); - return true; + if(b.size() <= 0 || b.size() > (1<<20)) return false; + block3 hdr = b; + lilswap(hdr.o.v, 3); + lilswap(hdr.s.v, 3); + lilswap(&hdr.grid, 1); + lilswap(&hdr.orient, 1); + buf.put((const uchar *)&hdr, sizeof(hdr)); + cube *c = b.c(); + loopi(b.size()) packcube(c[i], buf); + return true; } struct vslothdr { - ushort index; - ushort slot; + ushort index; + ushort slot; }; static void packvslots(cube &c, vector<uchar> &buf, vector<ushort> &used) { - if(c.children) - { - loopi(8) packvslots(c.children[i], buf, used); - } - else loopi(6) - { - ushort index = c.texture[i]; - if(vslots.inrange(index) && vslots[index]->changed && used.find(index) < 0) - { - used.add(index); - VSlot &vs = *vslots[index]; - vslothdr &hdr = *(vslothdr *)buf.pad(sizeof(vslothdr)); - hdr.index = index; - hdr.slot = vs.slot->index; - lilswap(&hdr.index, 2); - packvslot(buf, vs); - } - } + if(c.children) + { + loopi(8) packvslots(c.children[i], buf, used); + } + else loopi(6) + { + ushort index = c.texture[i]; + if(vslots.inrange(index) && vslots[index]->changed && used.find(index) < 0) + { + used.add(index); + VSlot &vs = *vslots[index]; + vslothdr &hdr = *(vslothdr *)buf.pad(sizeof(vslothdr)); + hdr.index = index; + hdr.slot = vs.slot->index; + lilswap(&hdr.index, 2); + packvslot(buf, vs); + } + } } static void packvslots(block3 &b, vector<uchar> &buf) { - vector<ushort> used; - cube *c = b.c(); - loopi(b.size()) packvslots(c[i], buf, used); - memset(buf.pad(sizeof(vslothdr)), 0, sizeof(vslothdr)); + vector<ushort> used; + cube *c = b.c(); + loopi(b.size()) packvslots(c[i], buf, used); + memset(buf.pad(sizeof(vslothdr)), 0, sizeof(vslothdr)); } template<class B> static void unpackcube(cube &c, B &buf) { - int mat = buf.get(); - if(mat == 0xFF) - { - c.children = newcubes(F_EMPTY); - loopi(8) unpackcube(c.children[i], buf); - } - else - { - c.material = mat | (buf.get()<<8); - buf.get(c.edges, sizeof(c.edges)); - buf.get((uchar *)c.texture, sizeof(c.texture)); - lilswap(c.texture, 6); - } + int mat = buf.get(); + if(mat == 0xFF) + { + c.children = newcubes(F_EMPTY); + loopi(8) unpackcube(c.children[i], buf); + } + else + { + c.material = mat | (buf.get()<<8); + buf.get(c.edges, sizeof(c.edges)); + buf.get((uchar *)c.texture, sizeof(c.texture)); + lilswap(c.texture, 6); + } } template<class B> static bool unpackblock(block3 *&b, B &buf) { - if(b) { freeblock(b); b = NULL; } - block3 hdr; - if(buf.get((uchar *)&hdr, sizeof(hdr)) < int(sizeof(hdr))) return false; - lilswap(hdr.o.v, 3); - lilswap(hdr.s.v, 3); - lilswap(&hdr.grid, 1); - lilswap(&hdr.orient, 1); - if(hdr.size() > (1<<20) || hdr.grid <= 0 || hdr.grid > (1<<12)) return false; - b = (block3 *)new (false) uchar[sizeof(block3)+hdr.size()*sizeof(cube)]; - if(!b) return false; - *b = hdr; - cube *c = b->c(); - memset(c, 0, b->size()*sizeof(cube)); - loopi(b->size()) unpackcube(c[i], buf); - return true; + if(b) { freeblock(b); b = NULL; } + block3 hdr; + if(buf.get((uchar *)&hdr, sizeof(hdr)) < int(sizeof(hdr))) return false; + lilswap(hdr.o.v, 3); + lilswap(hdr.s.v, 3); + lilswap(&hdr.grid, 1); + lilswap(&hdr.orient, 1); + if(hdr.size() > (1<<20) || hdr.grid <= 0 || hdr.grid > (1<<12)) return false; + b = (block3 *)new (false) uchar[sizeof(block3)+hdr.size()*sizeof(cube)]; + if(!b) return false; + *b = hdr; + cube *c = b->c(); + memset(c, 0, b->size()*sizeof(cube)); + loopi(b->size()) unpackcube(c[i], buf); + return true; } struct vslotmap { - int index; - VSlot *vslot; + int index; + VSlot *vslot; - vslotmap() {} - vslotmap(int index, VSlot *vslot) : index(index), vslot(vslot) {} + vslotmap() {} + vslotmap(int index, VSlot *vslot) : index(index), vslot(vslot) {} }; static vector<vslotmap> unpackingvslots; static void unpackvslots(cube &c, ucharbuf &buf) { - if(c.children) - { - loopi(8) unpackvslots(c.children[i], buf); - } - else loopi(6) - { - ushort tex = c.texture[i]; - loopvj(unpackingvslots) if(unpackingvslots[j].index == tex) { c.texture[i] = unpackingvslots[j].vslot->index; break; } - } + if(c.children) + { + loopi(8) unpackvslots(c.children[i], buf); + } + else loopi(6) + { + ushort tex = c.texture[i]; + loopvj(unpackingvslots) if(unpackingvslots[j].index == tex) { c.texture[i] = unpackingvslots[j].vslot->index; break; } + } } static void unpackvslots(block3 &b, ucharbuf &buf) { - while(buf.remaining() >= int(sizeof(vslothdr))) - { - vslothdr &hdr = *(vslothdr *)buf.pad(sizeof(vslothdr)); - lilswap(&hdr.index, 2); - if(!hdr.index) break; - VSlot &vs = *lookupslot(hdr.slot, false).variants; - VSlot ds; - if(!unpackvslot(buf, ds, false)) break; - if(vs.index < 0 || vs.index == DEFAULT_SKY) continue; - VSlot *edit = editvslot(vs, ds); - unpackingvslots.add(vslotmap(hdr.index, edit ? edit : &vs)); - } + while(buf.remaining() >= int(sizeof(vslothdr))) + { + vslothdr &hdr = *(vslothdr *)buf.pad(sizeof(vslothdr)); + lilswap(&hdr.index, 2); + if(!hdr.index) break; + VSlot &vs = *lookupslot(hdr.slot, false).variants; + VSlot ds; + if(!unpackvslot(buf, ds, false)) break; + if(vs.index < 0 || vs.index == DEFAULT_SKY) continue; + VSlot *edit = editvslot(vs, ds); + unpackingvslots.add(vslotmap(hdr.index, edit ? edit : &vs)); + } - cube *c = b.c(); - loopi(b.size()) unpackvslots(c[i], buf); + cube *c = b.c(); + loopi(b.size()) unpackvslots(c[i], buf); - unpackingvslots.setsize(0); + unpackingvslots.setsize(0); } static bool compresseditinfo(const uchar *inbuf, int inlen, uchar *&outbuf, int &outlen) { - uLongf len = compressBound(inlen); - if(len > (1<<20)) return false; - outbuf = new (false) uchar[len]; - if(!outbuf || compress2((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen, Z_BEST_COMPRESSION) != Z_OK || len > (1<<16)) - { - delete[] outbuf; - outbuf = NULL; - return false; - } - outlen = len; - return true; + uLongf len = compressBound(inlen); + if(len > (1<<20)) return false; + outbuf = new (false) uchar[len]; + if(!outbuf || compress2((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen, Z_BEST_COMPRESSION) != Z_OK || len > (1<<16)) + { + delete[] outbuf; + outbuf = NULL; + return false; + } + outlen = len; + return true; } static bool uncompresseditinfo(const uchar *inbuf, int inlen, uchar *&outbuf, int &outlen) { - if(compressBound(outlen) > (1<<20)) return false; - uLongf len = outlen; - outbuf = new (false) uchar[len]; - if(!outbuf || uncompress((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen) != Z_OK) - { - delete[] outbuf; - outbuf = NULL; - return false; - } - outlen = len; - return true; + if(compressBound(outlen) > (1<<20)) return false; + uLongf len = outlen; + outbuf = new (false) uchar[len]; + if(!outbuf || uncompress((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen) != Z_OK) + { + delete[] outbuf; + outbuf = NULL; + return false; + } + outlen = len; + return true; } bool packeditinfo(editinfo *e, int &inlen, uchar *&outbuf, int &outlen) { - vector<uchar> buf; - if(!e || !e->copy || !packblock(*e->copy, buf)) return false; - packvslots(*e->copy, buf); - inlen = buf.length(); - return compresseditinfo(buf.getbuf(), buf.length(), outbuf, outlen); + vector<uchar> buf; + if(!e || !e->copy || !packblock(*e->copy, buf)) return false; + packvslots(*e->copy, buf); + inlen = buf.length(); + return compresseditinfo(buf.getbuf(), buf.length(), outbuf, outlen); } bool unpackeditinfo(editinfo *&e, const uchar *inbuf, int inlen, int outlen) { - if(e && e->copy) { freeblock(e->copy); e->copy = NULL; } - uchar *outbuf = NULL; - if(!uncompresseditinfo(inbuf, inlen, outbuf, outlen)) return false; - ucharbuf buf(outbuf, outlen); - if(!e) e = editinfos.add(new editinfo); - if(!unpackblock(e->copy, buf)) - { - delete[] outbuf; - return false; - } - unpackvslots(*e->copy, buf); - delete[] outbuf; - return true; + if(e && e->copy) { freeblock(e->copy); e->copy = NULL; } + uchar *outbuf = NULL; + if(!uncompresseditinfo(inbuf, inlen, outbuf, outlen)) return false; + ucharbuf buf(outbuf, outlen); + if(!e) e = editinfos.add(new editinfo); + if(!unpackblock(e->copy, buf)) + { + delete[] outbuf; + return false; + } + unpackvslots(*e->copy, buf); + delete[] outbuf; + return true; } void freeeditinfo(editinfo *&e) { - if(!e) return; - editinfos.removeobj(e); - if(e->copy) freeblock(e->copy); - delete e; - e = NULL; + if(!e) return; + editinfos.removeobj(e); + if(e->copy) freeblock(e->copy); + delete e; + e = NULL; } bool packundo(undoblock *u, int &inlen, uchar *&outbuf, int &outlen) { - vector<uchar> buf; - buf.reserve(512); - *(ushort *)buf.pad(2) = lilswap(ushort(u->numents)); - if(u->numents) - { - undoent *ue = u->ents(); - loopi(u->numents) - { - *(ushort *)buf.pad(2) = lilswap(ushort(ue[i].i)); - entity &e = *(entity *)buf.pad(sizeof(entity)); - e = ue[i].e; - lilswap(&e.o.x, 3); - lilswap(&e.attr1, 5); - } - } - else - { - block3 &b = *u->block(); - if(!packblock(b, buf)) return false; - buf.put(u->gridmap(), b.size()); - packvslots(b, buf); - } - inlen = buf.length(); - return compresseditinfo(buf.getbuf(), buf.length(), outbuf, outlen); + vector<uchar> buf; + buf.reserve(512); + *(ushort *)buf.pad(2) = lilswap(ushort(u->numents)); + if(u->numents) + { + undoent *ue = u->ents(); + loopi(u->numents) + { + *(ushort *)buf.pad(2) = lilswap(ushort(ue[i].i)); + entity &e = *(entity *)buf.pad(sizeof(entity)); + e = ue[i].e; + lilswap(&e.o.x, 3); + lilswap(&e.attr1, 5); + } + } + else + { + block3 &b = *u->block(); + if(!packblock(b, buf)) return false; + buf.put(u->gridmap(), b.size()); + packvslots(b, buf); + } + inlen = buf.length(); + return compresseditinfo(buf.getbuf(), buf.length(), outbuf, outlen); } bool unpackundo(const uchar *inbuf, int inlen, int outlen) { - uchar *outbuf = NULL; - if(!uncompresseditinfo(inbuf, inlen, outbuf, outlen)) return false; - ucharbuf buf(outbuf, outlen); - if(buf.remaining() < 2) - { - delete[] outbuf; - return false; - } - int numents = lilswap(*(const ushort *)buf.pad(2)); - if(numents) - { - if(buf.remaining() < numents*int(2 + sizeof(entity))) - { - delete[] outbuf; - return false; - } - loopi(numents) - { - int idx = lilswap(*(const ushort *)buf.pad(2)); - entity &e = *(entity *)buf.pad(sizeof(entity)); - lilswap(&e.o.x, 3); - lilswap(&e.attr1, 5); - pasteundoent(idx, e); - } - } - else - { - block3 *b = NULL; - if(!unpackblock(b, buf) || b->grid >= worldsize || buf.remaining() < b->size()) - { - freeblock(b); - delete[] outbuf; - return false; - } - uchar *g = buf.pad(b->size()); - unpackvslots(*b, buf); - pasteundoblock(b, g); - changed(*b, false); - freeblock(b); - } - delete[] outbuf; - commitchanges(); - return true; + uchar *outbuf = NULL; + if(!uncompresseditinfo(inbuf, inlen, outbuf, outlen)) return false; + ucharbuf buf(outbuf, outlen); + if(buf.remaining() < 2) + { + delete[] outbuf; + return false; + } + int numents = lilswap(*(const ushort *)buf.pad(2)); + if(numents) + { + if(buf.remaining() < numents*int(2 + sizeof(entity))) + { + delete[] outbuf; + return false; + } + loopi(numents) + { + int idx = lilswap(*(const ushort *)buf.pad(2)); + entity &e = *(entity *)buf.pad(sizeof(entity)); + lilswap(&e.o.x, 3); + lilswap(&e.attr1, 5); + pasteundoent(idx, e); + } + } + else + { + block3 *b = NULL; + if(!unpackblock(b, buf) || b->grid >= worldsize || buf.remaining() < b->size()) + { + freeblock(b); + delete[] outbuf; + return false; + } + uchar *g = buf.pad(b->size()); + unpackvslots(*b, buf); + pasteundoblock(b, g); + changed(*b, false); + freeblock(b); + } + delete[] outbuf; + commitchanges(); + return true; } bool packundo(int op, int &inlen, uchar *&outbuf, int &outlen) { - switch(op) - { - case EDIT_UNDO: return !undos.empty() && packundo(undos.last, inlen, outbuf, outlen); - case EDIT_REDO: return !redos.empty() && packundo(redos.last, inlen, outbuf, outlen); - default: return false; - } + switch(op) + { + case EDIT_UNDO: return !undos.empty() && packundo(undos.last, inlen, outbuf, outlen); + case EDIT_REDO: return !redos.empty() && packundo(redos.last, inlen, outbuf, outlen); + default: return false; + } } struct prefabheader { - char magic[4]; - int version; + char magic[4]; + int version; }; struct prefab : editinfo { - char *name; - GLuint ebo, vbo; - int numtris, numverts; + char *name; + GLuint ebo, vbo; + int numtris, numverts; - prefab() : name(NULL), ebo(0), vbo(0), numtris(0), numverts(0) {} - ~prefab() { DELETEA(name); if(copy) freeblock(copy); } + prefab() : name(NULL), ebo(0), vbo(0), numtris(0), numverts(0) {} + ~prefab() { DELETEA(name); if(copy) freeblock(copy); } - void cleanup() - { - if(ebo) { glDeleteBuffers_(1, &ebo); ebo = 0; } - if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; } - numtris = numverts = 0; - } + void cleanup() + { + if(ebo) { glDeleteBuffers_(1, &ebo); ebo = 0; } + if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; } + numtris = numverts = 0; + } }; static hashnameset<prefab> prefabs; void cleanupprefabs() { - enumerate(prefabs, prefab, p, p.cleanup()); + enumerate(prefabs, prefab, p, p.cleanup()); } void delprefab(char *name) { - prefab *p = prefabs.access(name); - if(p) - { - p->cleanup(); - prefabs.remove(name); - conoutf("deleted prefab %s", name); - } + prefab *p = prefabs.access(name); + if(p) + { + p->cleanup(); + prefabs.remove(name); + conoutf("deleted prefab %s", name); + } } COMMAND(delprefab, "s"); void saveprefab(char *name) { - if(!name[0] || noedit(true) || (nompedit && multiplayer())) return; - prefab *b = prefabs.access(name); - if(!b) - { - b = &prefabs[name]; - b->name = newstring(name); - } - if(b->copy) freeblock(b->copy); - protectsel(b->copy = blockcopy(block3(sel), sel.grid)); - changed(sel); - defformatstring(filename, strpbrk(name, "/\\") ? "packages/%s.obr" : "packages/prefab/%s.obr", name); - path(filename); - stream *f = opengzfile(filename, "wb"); - if(!f) { conoutf(CON_ERROR, "could not write prefab to %s", filename); return; } - prefabheader hdr; - memcpy(hdr.magic, "OEBR", 4); - hdr.version = 0; - lilswap(&hdr.version, 1); - f->write(&hdr, sizeof(hdr)); - streambuf<uchar> s(f); - if(!packblock(*b->copy, s)) { delete f; conoutf(CON_ERROR, "could not pack prefab %s", filename); return; } - delete f; - conoutf("wrote prefab file %s", filename); + if(!name[0] || noedit(true) || (nompedit && multiplayer())) return; + prefab *b = prefabs.access(name); + if(!b) + { + b = &prefabs[name]; + b->name = newstring(name); + } + if(b->copy) freeblock(b->copy); + protectsel(b->copy = blockcopy(block3(sel), sel.grid)); + changed(sel); + defformatstring(filename, strpbrk(name, "/\\") ? "packages/%s.obr" : "packages/prefab/%s.obr", name); + path(filename); + stream *f = opengzfile(filename, "wb"); + if(!f) { conoutf(CON_ERROR, "could not write prefab to %s", filename); return; } + prefabheader hdr; + memcpy(hdr.magic, "OEBR", 4); + hdr.version = 0; + lilswap(&hdr.version, 1); + f->write(&hdr, sizeof(hdr)); + streambuf<uchar> s(f); + if(!packblock(*b->copy, s)) { delete f; conoutf(CON_ERROR, "could not pack prefab %s", filename); return; } + delete f; + conoutf("wrote prefab file %s", filename); } COMMAND(saveprefab, "s"); void pasteblock(block3 &b, selinfo &sel, bool local) { - sel.s = b.s; - int o = sel.orient; - sel.orient = b.orient; - cube *s = b.c(); - loopselxyz(if(!isempty(*s) || s->children || s->material != MAT_AIR) pastecube(*s, c); s++); // 'transparent'. old opaque by 'delcube; paste' - sel.orient = o; + sel.s = b.s; + int o = sel.orient; + sel.orient = b.orient; + cube *s = b.c(); + loopselxyz(if(!isempty(*s) || s->children || s->material != MAT_AIR) pastecube(*s, c); s++); // 'transparent'. old opaque by 'delcube; paste' + sel.orient = o; } bool prefabloaded(const char *name) { - return prefabs.access(name) != NULL; + return prefabs.access(name) != NULL; } prefab *loadprefab(const char *name, bool msg = true) @@ -1285,252 +1284,252 @@ prefab *loadprefab(const char *name, bool msg = true) void pasteprefab(char *name) { - if(!name[0] || noedit() || (nompedit && multiplayer())) return; - prefab *b = loadprefab(name, true); - if(b) pasteblock(*b->copy, sel, true); + if(!name[0] || noedit() || (nompedit && multiplayer())) return; + prefab *b = loadprefab(name, true); + if(b) pasteblock(*b->copy, sel, true); } COMMAND(pasteprefab, "s"); struct prefabmesh { - struct vertex { vec pos; bvec4 norm; }; - - static const int SIZE = 1<<9; - int table[SIZE]; - vector<vertex> verts; - vector<int> chain; - vector<ushort> tris; - - prefabmesh() { memset(table, -1, sizeof(table)); } - - int addvert(const vertex &v) - { - uint h = hthash(v.pos)&(SIZE-1); - for(int i = table[h]; i>=0; i = chain[i]) - { - const vertex &c = verts[i]; - if(c.pos==v.pos && c.norm==v.norm) return i; - } - if(verts.length() >= USHRT_MAX) return -1; - verts.add(v); - chain.add(table[h]); - return table[h] = verts.length()-1; - } - - int addvert(const vec &pos, const bvec &norm) - { - vertex vtx; - vtx.pos = pos; - vtx.norm = norm; - return addvert(vtx); + struct vertex { vec pos; bvec4 norm; }; + + static const int SIZE = 1<<9; + int table[SIZE]; + vector<vertex> verts; + vector<int> chain; + vector<ushort> tris; + + prefabmesh() { memset(table, -1, sizeof(table)); } + + int addvert(const vertex &v) + { + uint h = hthash(v.pos)&(SIZE-1); + for(int i = table[h]; i>=0; i = chain[i]) + { + const vertex &c = verts[i]; + if(c.pos==v.pos && c.norm==v.norm) return i; + } + if(verts.length() >= USHRT_MAX) return -1; + verts.add(v); + chain.add(table[h]); + return table[h] = verts.length()-1; + } + + int addvert(const vec &pos, const bvec &norm) + { + vertex vtx; + vtx.pos = pos; + vtx.norm = norm; + return addvert(vtx); } - void setup(prefab &p) - { - if(tris.empty()) return; + void setup(prefab &p) + { + if(tris.empty()) return; - p.cleanup(); + p.cleanup(); - loopv(verts) verts[i].norm.flip(); - if(!p.vbo) glGenBuffers_(1, &p.vbo); - gle::bindvbo(p.vbo); - glBufferData_(GL_ARRAY_BUFFER, verts.length()*sizeof(vertex), verts.getbuf(), GL_STATIC_DRAW); - gle::clearvbo(); - p.numverts = verts.length(); + loopv(verts) verts[i].norm.flip(); + if(!p.vbo) glGenBuffers_(1, &p.vbo); + gle::bindvbo(p.vbo); + glBufferData_(GL_ARRAY_BUFFER, verts.length()*sizeof(vertex), verts.getbuf(), GL_STATIC_DRAW); + gle::clearvbo(); + p.numverts = verts.length(); - if(!p.ebo) glGenBuffers_(1, &p.ebo); - gle::bindebo(p.ebo); - glBufferData_(GL_ELEMENT_ARRAY_BUFFER, tris.length()*sizeof(ushort), tris.getbuf(), GL_STATIC_DRAW); - gle::clearebo(); - p.numtris = tris.length()/3; - } + if(!p.ebo) glGenBuffers_(1, &p.ebo); + gle::bindebo(p.ebo); + glBufferData_(GL_ELEMENT_ARRAY_BUFFER, tris.length()*sizeof(ushort), tris.getbuf(), GL_STATIC_DRAW); + gle::clearebo(); + p.numtris = tris.length()/3; + } }; static void genprefabmesh(prefabmesh &r, cube &c, const ivec &co, int size) { - if(c.children) - { - neighbourstack[++neighbourdepth] = c.children; - loopi(8) - { - ivec o(i, co, size/2); - genprefabmesh(r, c.children[i], o, size/2); - } - --neighbourdepth; - } - else if(!isempty(c)) - { - int vis; - loopi(6) if((vis = visibletris(c, i, co, size))) - { - ivec v[4]; - genfaceverts(c, i, v); - int convex = 0; - if(!flataxisface(c, i)) convex = faceconvexity(v); - int order = vis&4 || convex < 0 ? 1 : 0, numverts = 0; - vec vo(co), pos[4], norm[4]; - pos[numverts++] = vec(v[order]).mul(size/8.0f).add(vo); - if(vis&1) pos[numverts++] = vec(v[order+1]).mul(size/8.0f).add(vo); - pos[numverts++] = vec(v[order+2]).mul(size/8.0f).add(vo); - if(vis&2) pos[numverts++] = vec(v[(order+3)&3]).mul(size/8.0f).add(vo); - guessnormals(pos, numverts, norm); - int index[4]; - loopj(numverts) index[j] = r.addvert(pos[j], bvec(norm[j])); - loopj(numverts-2) if(index[0]!=index[j+1] && index[j+1]!=index[j+2] && index[j+2]!=index[0]) - { - r.tris.add(index[0]); - r.tris.add(index[j+1]); - r.tris.add(index[j+2]); - } - } - } + if(c.children) + { + neighbourstack[++neighbourdepth] = c.children; + loopi(8) + { + ivec o(i, co, size/2); + genprefabmesh(r, c.children[i], o, size/2); + } + --neighbourdepth; + } + else if(!isempty(c)) + { + int vis; + loopi(6) if((vis = visibletris(c, i, co, size))) + { + ivec v[4]; + genfaceverts(c, i, v); + int convex = 0; + if(!flataxisface(c, i)) convex = faceconvexity(v); + int order = vis&4 || convex < 0 ? 1 : 0, numverts = 0; + vec vo(co), pos[4], norm[4]; + pos[numverts++] = vec(v[order]).mul(size/8.0f).add(vo); + if(vis&1) pos[numverts++] = vec(v[order+1]).mul(size/8.0f).add(vo); + pos[numverts++] = vec(v[order+2]).mul(size/8.0f).add(vo); + if(vis&2) pos[numverts++] = vec(v[(order+3)&3]).mul(size/8.0f).add(vo); + guessnormals(pos, numverts, norm); + int index[4]; + loopj(numverts) index[j] = r.addvert(pos[j], bvec(norm[j])); + loopj(numverts-2) if(index[0]!=index[j+1] && index[j+1]!=index[j+2] && index[j+2]!=index[0]) + { + r.tris.add(index[0]); + r.tris.add(index[j+1]); + r.tris.add(index[j+2]); + } + } + } } void genprefabmesh(prefab &p) { - block3 b = *p.copy; - b.o = ivec(0, 0, 0); + block3 b = *p.copy; + b.o = ivec(0, 0, 0); - cube *oldworldroot = worldroot; - int oldworldscale = worldscale, oldworldsize = worldsize; + cube *oldworldroot = worldroot; + int oldworldscale = worldscale, oldworldsize = worldsize; - worldroot = newcubes(); - worldscale = 1; - worldsize = 2; - while(worldsize < max(max(b.s.x, b.s.y), b.s.z)*b.grid) - { - worldscale++; - worldsize *= 2; - } + worldroot = newcubes(); + worldscale = 1; + worldsize = 2; + while(worldsize < max(max(b.s.x, b.s.y), b.s.z)*b.grid) + { + worldscale++; + worldsize *= 2; + } - cube *s = p.copy->c(); - loopxyz(b, b.grid, if(!isempty(*s) || s->children) pastecube(*s, c); s++); + cube *s = p.copy->c(); + loopxyz(b, b.grid, if(!isempty(*s) || s->children) pastecube(*s, c); s++); - prefabmesh r; - neighbourstack[++neighbourdepth] = worldroot; - loopi(8) genprefabmesh(r, worldroot[i], ivec(i, ivec(0, 0, 0), worldsize/2), worldsize/2); - --neighbourdepth; - r.setup(p); + prefabmesh r; + neighbourstack[++neighbourdepth] = worldroot; + loopi(8) genprefabmesh(r, worldroot[i], ivec(i, ivec(0, 0, 0), worldsize/2), worldsize/2); + --neighbourdepth; + r.setup(p); - freeocta(worldroot); + freeocta(worldroot); - worldroot = oldworldroot; - worldscale = oldworldscale; - worldsize = oldworldsize; + worldroot = oldworldroot; + worldscale = oldworldscale; + worldsize = oldworldsize; - useshaderbyname("prefab"); + useshaderbyname("prefab"); } extern int outlinecolour; static void renderprefab(prefab &p, const vec &o, float yaw, float pitch, float roll, float size, const vec &color) { - if(!p.numtris) - { - genprefabmesh(p); - if(!p.numtris) return; - } - - block3 &b = *p.copy; - - matrix4 m; - m.identity(); - m.settranslation(o); - if(yaw) m.rotate_around_z(yaw*RAD); - if(pitch) m.rotate_around_x(pitch*RAD); - if(roll) m.rotate_around_y(-roll*RAD); - matrix3 w(m); - if(size > 0 && size != 1) m.scale(size); - m.translate(vec(b.s).mul(-b.grid*0.5f)); - - gle::bindvbo(p.vbo); - gle::bindebo(p.ebo); - gle::enablevertex(); - gle::enablenormal(); - prefabmesh::vertex *v = (prefabmesh::vertex *)0; - gle::vertexpointer(sizeof(prefabmesh::vertex), v->pos.v); - gle::normalpointer(sizeof(prefabmesh::vertex), v->norm.v, GL_BYTE); - - matrix4 pm; - pm.mul(camprojmatrix, m); - GLOBALPARAM(prefabmatrix, pm); - GLOBALPARAM(prefabworld, w); - SETSHADER(prefab); - gle::color(color); - glDrawRangeElements_(GL_TRIANGLES, 0, p.numverts-1, p.numtris*3, GL_UNSIGNED_SHORT, (ushort *)0); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - enablepolygonoffset(GL_POLYGON_OFFSET_LINE); - - pm.mul(camprojmatrix, m); - GLOBALPARAM(prefabmatrix, pm); - SETSHADER(prefab); - gle::color(vec::hexcolor(outlinecolour)); - glDrawRangeElements_(GL_TRIANGLES, 0, p.numverts-1, p.numtris*3, GL_UNSIGNED_SHORT, (ushort *)0); - - disablepolygonoffset(GL_POLYGON_OFFSET_LINE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - gle::disablevertex(); - gle::disablenormal(); - gle::clearebo(); - gle::clearvbo(); + if(!p.numtris) + { + genprefabmesh(p); + if(!p.numtris) return; + } + + block3 &b = *p.copy; + + matrix4 m; + m.identity(); + m.settranslation(o); + if(yaw) m.rotate_around_z(yaw*RAD); + if(pitch) m.rotate_around_x(pitch*RAD); + if(roll) m.rotate_around_y(-roll*RAD); + matrix3 w(m); + if(size > 0 && size != 1) m.scale(size); + m.translate(vec(b.s).mul(-b.grid*0.5f)); + + gle::bindvbo(p.vbo); + gle::bindebo(p.ebo); + gle::enablevertex(); + gle::enablenormal(); + prefabmesh::vertex *v = (prefabmesh::vertex *)0; + gle::vertexpointer(sizeof(prefabmesh::vertex), v->pos.v); + gle::normalpointer(sizeof(prefabmesh::vertex), v->norm.v, GL_BYTE); + + matrix4 pm; + pm.mul(camprojmatrix, m); + GLOBALPARAM(prefabmatrix, pm); + GLOBALPARAM(prefabworld, w); + SETSHADER(prefab); + gle::color(color); + glDrawRangeElements_(GL_TRIANGLES, 0, p.numverts-1, p.numtris*3, GL_UNSIGNED_SHORT, (ushort *)0); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + enablepolygonoffset(GL_POLYGON_OFFSET_LINE); + + pm.mul(camprojmatrix, m); + GLOBALPARAM(prefabmatrix, pm); + SETSHADER(prefab); + gle::color(vec::hexcolor(outlinecolour)); + glDrawRangeElements_(GL_TRIANGLES, 0, p.numverts-1, p.numtris*3, GL_UNSIGNED_SHORT, (ushort *)0); + + disablepolygonoffset(GL_POLYGON_OFFSET_LINE); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + gle::disablevertex(); + gle::disablenormal(); + gle::clearebo(); + gle::clearvbo(); } void renderprefab(const char *name, const vec &o, float yaw, float pitch, float roll, float size, const vec &color) { - prefab *p = loadprefab(name, false); - if(p) renderprefab(*p, o, yaw, pitch, roll, size, color); + prefab *p = loadprefab(name, false); + if(p) renderprefab(*p, o, yaw, pitch, roll, size, color); } void previewprefab(const char *name, const vec &color) { - prefab *p = loadprefab(name, false); - if(p) - { - block3 &b = *p->copy; - float yaw; - vec o = calcmodelpreviewpos(vec(b.s).mul(b.grid*0.5f), yaw); - renderprefab(*p, o, yaw, 0, 0, 1, color); - } + prefab *p = loadprefab(name, false); + if(p) + { + block3 &b = *p->copy; + float yaw; + vec o = calcmodelpreviewpos(vec(b.s).mul(b.grid*0.5f), yaw); + renderprefab(*p, o, yaw, 0, 0, 1, color); + } } void mpcopy(editinfo *&e, selinfo &sel, bool local) { - if(local) game::edittrigger(sel, EDIT_COPY); - if(e==NULL) e = editinfos.add(new editinfo); - if(e->copy) freeblock(e->copy); - e->copy = NULL; - protectsel(e->copy = blockcopy(block3(sel), sel.grid)); - changed(sel); + if(local) game::edittrigger(sel, EDIT_COPY); + if(e==NULL) e = editinfos.add(new editinfo); + if(e->copy) freeblock(e->copy); + e->copy = NULL; + protectsel(e->copy = blockcopy(block3(sel), sel.grid)); + changed(sel); } void mppaste(editinfo *&e, selinfo &sel, bool local) { - if(e==NULL) return; - if(local) game::edittrigger(sel, EDIT_PASTE); - if(e->copy) pasteblock(*e->copy, sel, local); + if(e==NULL) return; + if(local) game::edittrigger(sel, EDIT_PASTE); + if(e->copy) pasteblock(*e->copy, sel, local); } void copy() { - if(noedit(true)) return; - mpcopy(localedit, sel, true); + if(noedit(true)) return; + mpcopy(localedit, sel, true); } void pastehilite() { - if(!localedit) return; + if(!localedit) return; sel.s = localedit->copy->s; - reorient(); - havesel = true; + reorient(); + havesel = true; } void paste() { - if(noedit(true)) return; - mppaste(localedit, sel, true); + if(noedit(true)) return; + mppaste(localedit, sel, true); } COMMAND(copy, ""); @@ -1542,31 +1541,31 @@ COMMANDN(redo, editredo, ""); static vector<int *> editingvslots; struct vslotref { - vslotref(int &index) { editingvslots.add(&index); } - ~vslotref() { editingvslots.pop(); } + vslotref(int &index) { editingvslots.add(&index); } + ~vslotref() { editingvslots.pop(); } }; #define editingvslot(...) vslotref vslotrefs[] = { __VA_ARGS__ }; (void)vslotrefs; void compacteditvslots() { - loopv(editingvslots) if(*editingvslots[i]) compactvslot(*editingvslots[i]); - loopv(unpackingvslots) compactvslot(*unpackingvslots[i].vslot); - loopv(editinfos) - { - editinfo *e = editinfos[i]; - compactvslots(e->copy->c(), e->copy->size()); - } - for(undoblock *u = undos.first; u; u = u->next) - if(!u->numents) - compactvslots(u->block()->c(), u->block()->size()); - for(undoblock *u = redos.first; u; u = u->next) - if(!u->numents) - compactvslots(u->block()->c(), u->block()->size()); + loopv(editingvslots) if(*editingvslots[i]) compactvslot(*editingvslots[i]); + loopv(unpackingvslots) compactvslot(*unpackingvslots[i].vslot); + loopv(editinfos) + { + editinfo *e = editinfos[i]; + compactvslots(e->copy->c(), e->copy->size()); + } + for(undoblock *u = undos.first; u; u = u->next) + if(!u->numents) + compactvslots(u->block()->c(), u->block()->size()); + for(undoblock *u = redos.first; u; u = u->next) + if(!u->numents) + compactvslots(u->block()->c(), u->block()->size()); } ///////////// height maps //////////////// -#define MAXBRUSH 64 +#define MAXBRUSH 64 #define MAXBRUSHC 63 #define MAXBRUSH2 32 int brush[MAXBRUSH][MAXBRUSH]; @@ -1578,23 +1577,23 @@ int brushmaxy = 0, brushminy = MAXBRUSH; void clearbrush() { - memset(brush, 0, sizeof brush); - brushmaxx = brushmaxy = 0; - brushminx = brushminy = MAXBRUSH; - paintbrush = false; + memset(brush, 0, sizeof brush); + brushmaxx = brushmaxy = 0; + brushminx = brushminy = MAXBRUSH; + paintbrush = false; } void brushvert(int *x, int *y, int *v) { - *x += MAXBRUSH2 - brushx + 1; // +1 for automatic padding - *y += MAXBRUSH2 - brushy + 1; - if(*x<0 || *y<0 || *x>=MAXBRUSH || *y>=MAXBRUSH) return; - brush[*x][*y] = clamp(*v, 0, 8); - paintbrush = paintbrush || (brush[*x][*y] > 0); - brushmaxx = min(MAXBRUSH-1, max(brushmaxx, *x+1)); - brushmaxy = min(MAXBRUSH-1, max(brushmaxy, *y+1)); - brushminx = max(0, min(brushminx, *x-1)); - brushminy = max(0, min(brushminy, *y-1)); + *x += MAXBRUSH2 - brushx + 1; // +1 for automatic padding + *y += MAXBRUSH2 - brushy + 1; + if(*x<0 || *y<0 || *x>=MAXBRUSH || *y>=MAXBRUSH) return; + brush[*x][*y] = clamp(*v, 0, 8); + paintbrush = paintbrush || (brush[*x][*y] > 0); + brushmaxx = min(MAXBRUSH-1, max(brushmaxx, *x+1)); + brushmaxy = min(MAXBRUSH-1, max(brushmaxy, *y+1)); + brushminx = max(0, min(brushminx, *x-1)); + brushminy = max(0, min(brushminy, *y-1)); } vector<int> htextures; @@ -1604,317 +1603,317 @@ COMMAND(brushvert, "iii"); void hmapcancel() { htextures.setsize(0); } COMMAND(hmapcancel, ""); ICOMMAND(hmapselect, "", (), - int t = lookupcube(cur).texture[orient]; - int i = htextures.find(t); - if(i<0) - htextures.add(t); - else - htextures.remove(i); + int t = lookupcube(cur).texture[orient]; + int i = htextures.find(t); + if(i<0) + htextures.add(t); + else + htextures.remove(i); ); inline bool isheightmap(int o, int d, bool empty, cube *c) { - return havesel || - (empty && isempty(*c)) || - htextures.empty() || - htextures.find(c->texture[o]) >= 0; + return havesel || + (empty && isempty(*c)) || + htextures.empty() || + htextures.find(c->texture[o]) >= 0; } namespace hmap { -# define PAINTED 1 -# define NOTHMAP 2 -# define MAPPED 16 - uchar flags[MAXBRUSH][MAXBRUSH]; - cube *cmap[MAXBRUSHC][MAXBRUSHC][4]; - int mapz[MAXBRUSHC][MAXBRUSHC]; - int map [MAXBRUSH][MAXBRUSH]; - - selinfo changes; - bool selecting; - int d, dc, dr, dcr, biasup, br, hws, fg; - int gx, gy, gz, mx, my, mz, nx, ny, nz, bmx, bmy, bnx, bny; - uint fs; - selinfo hundo; - - cube *getcube(ivec t, int f) - { - t[d] += dcr*f*gridsize; - if(t[d] > nz || t[d] < mz) return NULL; - cube *c = &lookupcube(t, gridsize); - if(c->children) forcemip(*c, false); - discardchildren(*c, true); - if(!isheightmap(sel.orient, d, true, c)) return NULL; - if (t.x < changes.o.x) changes.o.x = t.x; - else if(t.x > changes.s.x) changes.s.x = t.x; - if (t.y < changes.o.y) changes.o.y = t.y; - else if(t.y > changes.s.y) changes.s.y = t.y; - if (t.z < changes.o.z) changes.o.z = t.z; - else if(t.z > changes.s.z) changes.s.z = t.z; - return c; - } - - uint getface(cube *c, int d) - { - return 0x0f0f0f0f & ((dc ? c->faces[d] : 0x88888888 - c->faces[d]) >> fs); - } - - void pushside(cube &c, int d, int x, int y, int z) - { - ivec a; - getcubevector(c, d, x, y, z, a); - a[R[d]] = 8 - a[R[d]]; - setcubevector(c, d, x, y, z, a); - } - - void addpoint(int x, int y, int z, int v) - { - if(!(flags[x][y] & MAPPED)) - map[x][y] = v + (z*8); - flags[x][y] |= MAPPED; - } - - void select(int x, int y, int z) - { - if((NOTHMAP & flags[x][y]) || (PAINTED & flags[x][y])) return; - ivec t(d, x+gx, y+gy, dc ? z : hws-z); - t.shl(gridpower); - - // selections may damage; must makeundo before - hundo.o = t; - hundo.o[D[d]] -= dcr*gridsize*2; - makeundo(hundo); - - cube **c = cmap[x][y]; - loopk(4) c[k] = NULL; - c[1] = getcube(t, 0); - if(!c[1] || !isempty(*c[1])) - { // try up - c[2] = c[1]; - c[1] = getcube(t, 1); - if(!c[1] || isempty(*c[1])) { c[0] = c[1]; c[1] = c[2]; c[2] = NULL; } - else { z++; t[d]+=fg; } - } - else // drop down - { - z--; - t[d]-= fg; - c[0] = c[1]; - c[1] = getcube(t, 0); - } - - if(!c[1] || isempty(*c[1])) { flags[x][y] |= NOTHMAP; return; } - - flags[x][y] |= PAINTED; - mapz [x][y] = z; - - if(!c[0]) c[0] = getcube(t, 1); - if(!c[2]) c[2] = getcube(t, -1); - c[3] = getcube(t, -2); - c[2] = !c[2] || isempty(*c[2]) ? NULL : c[2]; - c[3] = !c[3] || isempty(*c[3]) ? NULL : c[3]; - - uint face = getface(c[1], d); - if(face == 0x08080808 && (!c[0] || !isempty(*c[0]))) { flags[x][y] |= NOTHMAP; return; } - if(c[1]->faces[R[d]] == F_SOLID) // was single - face += 0x08080808; - else // was pair - face += c[2] ? getface(c[2], d) : 0x08080808; - face += 0x08080808; // c[3] - uchar *f = (uchar*)&face; - addpoint(x, y, z, f[0]); - addpoint(x+1, y, z, f[1]); - addpoint(x, y+1, z, f[2]); - addpoint(x+1, y+1, z, f[3]); - - if(selecting) // continue to adjacent cubes - { - if(x>bmx) select(x-1, y, z); - if(x<bnx) select(x+1, y, z); - if(y>bmy) select(x, y-1, z); - if(y<bny) select(x, y+1, z); - } - } - - void ripple(int x, int y, int z, bool force) - { - if(force) select(x, y, z); - if((NOTHMAP & flags[x][y]) || !(PAINTED & flags[x][y])) return; - - bool changed = false; - int *o[4], best, par, q = 0; - loopi(2) loopj(2) o[i+j*2] = &map[x+i][y+j]; - #define pullhmap(I, LT, GT, M, N, A) do { \ - best = I; \ - loopi(4) if(*o[i] LT best) best = *o[q = i] - M; \ - par = (best&(~7)) + N; \ - /* dual layer for extra smoothness */ \ - if(*o[q^3] GT par && !(*o[q^1] LT par || *o[q^2] LT par)) { \ - if(*o[q^3] GT par A 8 || *o[q^1] != par || *o[q^2] != par) { \ - *o[q^3] = (*o[q^3] GT par A 8 ? par A 8 : *o[q^3]); \ - *o[q^1] = *o[q^2] = par; \ - changed = true; \ - } \ - /* single layer */ \ - } else { \ - loopj(4) if(*o[j] GT par) { \ - *o[j] = par; \ - changed = true; \ - } \ - } \ - } while(0) - - if(biasup) - pullhmap(0, >, <, 1, 0, -); - else - pullhmap(worldsize*8, <, >, 0, 8, +); - - cube **c = cmap[x][y]; - int e[2][2]; - int notempty = 0; - - loopk(4) if(c[k]) { - loopi(2) loopj(2) { - e[i][j] = min(8, map[x+i][y+j] - (mapz[x][y]+3-k)*8); - notempty |= e[i][j] > 0; - } - if(notempty) - { - c[k]->texture[sel.orient] = c[1]->texture[sel.orient]; - solidfaces(*c[k]); - loopi(2) loopj(2) - { - int f = e[i][j]; - if(f<0 || (f==0 && e[1-i][j]==0 && e[i][1-j]==0)) - { - f=0; - pushside(*c[k], d, i, j, 0); - pushside(*c[k], d, i, j, 1); - } - edgeset(cubeedge(*c[k], d, i, j), dc, dc ? f : 8-f); - } - } - else - emptyfaces(*c[k]); - } - - if(!changed) return; - if(x>mx) ripple(x-1, y, mapz[x][y], true); - if(x<nx) ripple(x+1, y, mapz[x][y], true); - if(y>my) ripple(x, y-1, mapz[x][y], true); - if(y<ny) ripple(x, y+1, mapz[x][y], true); +# define PAINTED 1 +# define NOTHMAP 2 +# define MAPPED 16 + uchar flags[MAXBRUSH][MAXBRUSH]; + cube *cmap[MAXBRUSHC][MAXBRUSHC][4]; + int mapz[MAXBRUSHC][MAXBRUSHC]; + int map [MAXBRUSH][MAXBRUSH]; + + selinfo changes; + bool selecting; + int d, dc, dr, dcr, biasup, br, hws, fg; + int gx, gy, gz, mx, my, mz, nx, ny, nz, bmx, bmy, bnx, bny; + uint fs; + selinfo hundo; + + cube *getcube(ivec t, int f) + { + t[d] += dcr*f*gridsize; + if(t[d] > nz || t[d] < mz) return NULL; + cube *c = &lookupcube(t, gridsize); + if(c->children) forcemip(*c, false); + discardchildren(*c, true); + if(!isheightmap(sel.orient, d, true, c)) return NULL; + if (t.x < changes.o.x) changes.o.x = t.x; + else if(t.x > changes.s.x) changes.s.x = t.x; + if (t.y < changes.o.y) changes.o.y = t.y; + else if(t.y > changes.s.y) changes.s.y = t.y; + if (t.z < changes.o.z) changes.o.z = t.z; + else if(t.z > changes.s.z) changes.s.z = t.z; + return c; + } + + uint getface(cube *c, int d) + { + return 0x0f0f0f0f & ((dc ? c->faces[d] : 0x88888888 - c->faces[d]) >> fs); + } + + void pushside(cube &c, int d, int x, int y, int z) + { + ivec a; + getcubevector(c, d, x, y, z, a); + a[R[d]] = 8 - a[R[d]]; + setcubevector(c, d, x, y, z, a); + } + + void addpoint(int x, int y, int z, int v) + { + if(!(flags[x][y] & MAPPED)) + map[x][y] = v + (z*8); + flags[x][y] |= MAPPED; + } + + void select(int x, int y, int z) + { + if((NOTHMAP & flags[x][y]) || (PAINTED & flags[x][y])) return; + ivec t(d, x+gx, y+gy, dc ? z : hws-z); + t.shl(gridpower); + + // selections may damage; must makeundo before + hundo.o = t; + hundo.o[D[d]] -= dcr*gridsize*2; + makeundo(hundo); + + cube **c = cmap[x][y]; + loopk(4) c[k] = NULL; + c[1] = getcube(t, 0); + if(!c[1] || !isempty(*c[1])) + { // try up + c[2] = c[1]; + c[1] = getcube(t, 1); + if(!c[1] || isempty(*c[1])) { c[0] = c[1]; c[1] = c[2]; c[2] = NULL; } + else { z++; t[d]+=fg; } + } + else // drop down + { + z--; + t[d]-= fg; + c[0] = c[1]; + c[1] = getcube(t, 0); + } + + if(!c[1] || isempty(*c[1])) { flags[x][y] |= NOTHMAP; return; } + + flags[x][y] |= PAINTED; + mapz [x][y] = z; + + if(!c[0]) c[0] = getcube(t, 1); + if(!c[2]) c[2] = getcube(t, -1); + c[3] = getcube(t, -2); + c[2] = !c[2] || isempty(*c[2]) ? NULL : c[2]; + c[3] = !c[3] || isempty(*c[3]) ? NULL : c[3]; + + uint face = getface(c[1], d); + if(face == 0x08080808 && (!c[0] || !isempty(*c[0]))) { flags[x][y] |= NOTHMAP; return; } + if(c[1]->faces[R[d]] == F_SOLID) // was single + face += 0x08080808; + else // was pair + face += c[2] ? getface(c[2], d) : 0x08080808; + face += 0x08080808; // c[3] + uchar *f = (uchar*)&face; + addpoint(x, y, z, f[0]); + addpoint(x+1, y, z, f[1]); + addpoint(x, y+1, z, f[2]); + addpoint(x+1, y+1, z, f[3]); + + if(selecting) // continue to adjacent cubes + { + if(x>bmx) select(x-1, y, z); + if(x<bnx) select(x+1, y, z); + if(y>bmy) select(x, y-1, z); + if(y<bny) select(x, y+1, z); + } + } + + void ripple(int x, int y, int z, bool force) + { + if(force) select(x, y, z); + if((NOTHMAP & flags[x][y]) || !(PAINTED & flags[x][y])) return; + + bool changed = false; + int *o[4], best, par, q = 0; + loopi(2) loopj(2) o[i+j*2] = &map[x+i][y+j]; + #define pullhmap(I, LT, GT, M, N, A) do { \ + best = I; \ + loopi(4) if(*o[i] LT best) best = *o[q = i] - M; \ + par = (best&(~7)) + N; \ + /* dual layer for extra smoothness */ \ + if(*o[q^3] GT par && !(*o[q^1] LT par || *o[q^2] LT par)) { \ + if(*o[q^3] GT par A 8 || *o[q^1] != par || *o[q^2] != par) { \ + *o[q^3] = (*o[q^3] GT par A 8 ? par A 8 : *o[q^3]); \ + *o[q^1] = *o[q^2] = par; \ + changed = true; \ + } \ + /* single layer */ \ + } else { \ + loopj(4) if(*o[j] GT par) { \ + *o[j] = par; \ + changed = true; \ + } \ + } \ + } while(0) + + if(biasup) + pullhmap(0, >, <, 1, 0, -); + else + pullhmap(worldsize*8, <, >, 0, 8, +); + + cube **c = cmap[x][y]; + int e[2][2]; + int notempty = 0; + + loopk(4) if(c[k]) { + loopi(2) loopj(2) { + e[i][j] = min(8, map[x+i][y+j] - (mapz[x][y]+3-k)*8); + notempty |= e[i][j] > 0; + } + if(notempty) + { + c[k]->texture[sel.orient] = c[1]->texture[sel.orient]; + solidfaces(*c[k]); + loopi(2) loopj(2) + { + int f = e[i][j]; + if(f<0 || (f==0 && e[1-i][j]==0 && e[i][1-j]==0)) + { + f=0; + pushside(*c[k], d, i, j, 0); + pushside(*c[k], d, i, j, 1); + } + edgeset(cubeedge(*c[k], d, i, j), dc, dc ? f : 8-f); + } + } + else + emptyfaces(*c[k]); + } + + if(!changed) return; + if(x>mx) ripple(x-1, y, mapz[x][y], true); + if(x<nx) ripple(x+1, y, mapz[x][y], true); + if(y>my) ripple(x, y-1, mapz[x][y], true); + if(y<ny) ripple(x, y+1, mapz[x][y], true); #define DIAGONAL_RIPPLE(a,b,exp) if(exp) { \ - if(flags[x a][ y] & PAINTED) \ - ripple(x a, y b, mapz[x a][y], true); \ - else if(flags[x][y b] & PAINTED) \ - ripple(x a, y b, mapz[x][y b], true); \ - } - - DIAGONAL_RIPPLE(-1, -1, (x>mx && y>my)); // do diagonals because adjacents - DIAGONAL_RIPPLE(-1, +1, (x>mx && y<ny)); // won't unless changed - DIAGONAL_RIPPLE(+1, +1, (x<nx && y<ny)); - DIAGONAL_RIPPLE(+1, -1, (x<nx && y>my)); - } + if(flags[x a][ y] & PAINTED) \ + ripple(x a, y b, mapz[x a][y], true); \ + else if(flags[x][y b] & PAINTED) \ + ripple(x a, y b, mapz[x][y b], true); \ + } + + DIAGONAL_RIPPLE(-1, -1, (x>mx && y>my)); // do diagonals because adjacents + DIAGONAL_RIPPLE(-1, +1, (x>mx && y<ny)); // won't unless changed + DIAGONAL_RIPPLE(+1, +1, (x<nx && y<ny)); + DIAGONAL_RIPPLE(+1, -1, (x<nx && y>my)); + } #define loopbrush(i) for(int x=bmx; x<=bnx+i; x++) for(int y=bmy; y<=bny+i; y++) - void paint() - { - loopbrush(1) - map[x][y] -= dr * brush[x][y]; - } - - void smooth() - { - int sum, div; - loopbrush(-2) - { - sum = 0; - div = 9; - loopi(3) loopj(3) - if(flags[x+i][y+j] & MAPPED) - sum += map[x+i][y+j]; - else div--; - if(div) - map[x+1][y+1] = sum / div; - } - } - - void rippleandset() - { - loopbrush(0) - ripple(x, y, gz, false); - } - - void run(int dir, int mode) - { - d = dimension(sel.orient); - dc = dimcoord(sel.orient); - dcr= dc ? 1 : -1; - dr = dir>0 ? 1 : -1; - br = dir>0 ? 0x08080808 : 0; - // biasup = mode == dir<0; - biasup = dir<0; - bool paintme = paintbrush; - int cx = (sel.corner&1 ? 0 : -1); - int cy = (sel.corner&2 ? 0 : -1); - hws= (worldsize>>gridpower); - gx = (cur[R[d]] >> gridpower) + cx - MAXBRUSH2; - gy = (cur[C[d]] >> gridpower) + cy - MAXBRUSH2; - gz = (cur[D[d]] >> gridpower); - fs = dc ? 4 : 0; - fg = dc ? gridsize : -gridsize; - mx = max(0, -gx); // ripple range - my = max(0, -gy); - nx = min(MAXBRUSH-1, hws-gx) - 1; - ny = min(MAXBRUSH-1, hws-gy) - 1; - if(havesel) - { // selection range - bmx = mx = max(mx, (sel.o[R[d]]>>gridpower)-gx); - bmy = my = max(my, (sel.o[C[d]]>>gridpower)-gy); - bnx = nx = min(nx, (sel.s[R[d]]+(sel.o[R[d]]>>gridpower))-gx-1); - bny = ny = min(ny, (sel.s[C[d]]+(sel.o[C[d]]>>gridpower))-gy-1); - } - if(havesel && mode<0) // -ve means smooth selection - paintme = false; - else - { // brush range - bmx = max(mx, brushminx); - bmy = max(my, brushminy); - bnx = min(nx, brushmaxx-1); - bny = min(ny, brushmaxy-1); - } - nz = worldsize-gridsize; - mz = 0; - hundo.s = ivec(d,1,1,5); - hundo.orient = sel.orient; - hundo.grid = gridsize; - forcenextundo(); - - changes.grid = gridsize; - changes.s = changes.o = cur; - memset(map, 0, sizeof map); - memset(flags, 0, sizeof flags); - - selecting = true; - select(clamp(MAXBRUSH2-cx, bmx, bnx), - clamp(MAXBRUSH2-cy, bmy, bny), - dc ? gz : hws - gz); - selecting = false; - if(paintme) - paint(); - else - smooth(); - rippleandset(); // pull up points to cubify, and set - changes.s.sub(changes.o).shr(gridpower).add(1); - changed(changes); - } + void paint() + { + loopbrush(1) + map[x][y] -= dr * brush[x][y]; + } + + void smooth() + { + int sum, div; + loopbrush(-2) + { + sum = 0; + div = 9; + loopi(3) loopj(3) + if(flags[x+i][y+j] & MAPPED) + sum += map[x+i][y+j]; + else div--; + if(div) + map[x+1][y+1] = sum / div; + } + } + + void rippleandset() + { + loopbrush(0) + ripple(x, y, gz, false); + } + + void run(int dir, int mode) + { + d = dimension(sel.orient); + dc = dimcoord(sel.orient); + dcr= dc ? 1 : -1; + dr = dir>0 ? 1 : -1; + br = dir>0 ? 0x08080808 : 0; + // biasup = mode == dir<0; + biasup = dir<0; + bool paintme = paintbrush; + int cx = (sel.corner&1 ? 0 : -1); + int cy = (sel.corner&2 ? 0 : -1); + hws= (worldsize>>gridpower); + gx = (cur[R[d]] >> gridpower) + cx - MAXBRUSH2; + gy = (cur[C[d]] >> gridpower) + cy - MAXBRUSH2; + gz = (cur[D[d]] >> gridpower); + fs = dc ? 4 : 0; + fg = dc ? gridsize : -gridsize; + mx = max(0, -gx); // ripple range + my = max(0, -gy); + nx = min(MAXBRUSH-1, hws-gx) - 1; + ny = min(MAXBRUSH-1, hws-gy) - 1; + if(havesel) + { // selection range + bmx = mx = max(mx, (sel.o[R[d]]>>gridpower)-gx); + bmy = my = max(my, (sel.o[C[d]]>>gridpower)-gy); + bnx = nx = min(nx, (sel.s[R[d]]+(sel.o[R[d]]>>gridpower))-gx-1); + bny = ny = min(ny, (sel.s[C[d]]+(sel.o[C[d]]>>gridpower))-gy-1); + } + if(havesel && mode<0) // -ve means smooth selection + paintme = false; + else + { // brush range + bmx = max(mx, brushminx); + bmy = max(my, brushminy); + bnx = min(nx, brushmaxx-1); + bny = min(ny, brushmaxy-1); + } + nz = worldsize-gridsize; + mz = 0; + hundo.s = ivec(d,1,1,5); + hundo.orient = sel.orient; + hundo.grid = gridsize; + forcenextundo(); + + changes.grid = gridsize; + changes.s = changes.o = cur; + memset(map, 0, sizeof map); + memset(flags, 0, sizeof flags); + + selecting = true; + select(clamp(MAXBRUSH2-cx, bmx, bnx), + clamp(MAXBRUSH2-cy, bmy, bny), + dc ? gz : hws - gz); + selecting = false; + if(paintme) + paint(); + else + smooth(); + rippleandset(); // pull up points to cubify, and set + changes.s.sub(changes.o).shr(gridpower).add(1); + changed(changes); + } } void edithmap(int dir, int mode) { - if((nompedit && multiplayer()) || !hmapsel) return; - hmap::run(dir, mode); + if((nompedit && multiplayer()) || !hmapsel) return; + hmap::run(dir, mode); } ///////////// main cube edit //////////////// @@ -1923,151 +1922,151 @@ int bounded(int n) { return n<0 ? 0 : (n>8 ? 8 : n); } void pushedge(uchar &edge, int dir, int dc) { - int ne = bounded(edgeget(edge, dc)+dir); - edgeset(edge, dc, ne); - int oe = edgeget(edge, 1-dc); - if((dir<0 && dc && oe>ne) || (dir>0 && dc==0 && oe<ne)) edgeset(edge, 1-dc, ne); + int ne = bounded(edgeget(edge, dc)+dir); + edgeset(edge, dc, ne); + int oe = edgeget(edge, 1-dc); + if((dir<0 && dc && oe>ne) || (dir>0 && dc==0 && oe<ne)) edgeset(edge, 1-dc, ne); } void linkedpush(cube &c, int d, int x, int y, int dc, int dir) { - ivec v, p; - getcubevector(c, d, x, y, dc, v); + ivec v, p; + getcubevector(c, d, x, y, dc, v); - loopi(2) loopj(2) - { - getcubevector(c, d, i, j, dc, p); - if(v==p) - pushedge(cubeedge(c, d, i, j), dir, dc); - } + loopi(2) loopj(2) + { + getcubevector(c, d, i, j, dc, p); + if(v==p) + pushedge(cubeedge(c, d, i, j), dir, dc); + } } static ushort getmaterial(cube &c) { - if(c.children) - { - ushort mat = getmaterial(c.children[7]); - loopi(7) if(mat != getmaterial(c.children[i])) return MAT_AIR; - return mat; - } - return c.material; + if(c.children) + { + ushort mat = getmaterial(c.children[7]); + loopi(7) if(mat != getmaterial(c.children[i])) return MAT_AIR; + return mat; + } + return c.material; } VAR(invalidcubeguard, 0, 1, 1); void mpeditface(int dir, int mode, selinfo &sel, bool local) { - if(mode==1 && (sel.cx || sel.cy || sel.cxs&1 || sel.cys&1)) mode = 0; - int d = dimension(sel.orient); - int dc = dimcoord(sel.orient); - int seldir = dc ? -dir : dir; - - if(local) - game::edittrigger(sel, EDIT_FACE, dir, mode); - - if(mode==1) - { - int h = sel.o[d]+dc*sel.grid; - if(((dir>0) == dc && h<=0) || ((dir<0) == dc && h>=worldsize)) return; - if(dir<0) sel.o[d] += sel.grid * seldir; - } - - if(dc) sel.o[d] += sel.us(d)-sel.grid; - sel.s[d] = 1; - - loopselxyz( - if(c.children) solidfaces(c); - ushort mat = getmaterial(c); - discardchildren(c, true); - c.material = mat; - if(mode==1) // fill command - { - if(dir<0) - { - solidfaces(c); - cube &o = blockcube(x, y, 1, sel, -sel.grid); - loopi(6) - c.texture[i] = o.children ? (int) DEFAULT_GEOM : (int) o.texture[i]; - } - else - emptyfaces(c); - } - else - { - uint bak = c.faces[d]; - uchar *p = (uchar *)&c.faces[d]; - - if(mode==2) - linkedpush(c, d, sel.corner&1, sel.corner>>1, dc, seldir); // corner command - else - { - loop(mx,2) loop(my,2) // pull/push edges command - { - if(x==0 && mx==0 && sel.cx) continue; - if(y==0 && my==0 && sel.cy) continue; - if(x==sel.s[R[d]]-1 && mx==1 && (sel.cx+sel.cxs)&1) continue; - if(y==sel.s[C[d]]-1 && my==1 && (sel.cy+sel.cys)&1) continue; - if(p[mx+my*2] != ((uchar *)&bak)[mx+my*2]) continue; - - linkedpush(c, d, mx, my, dc, seldir); - } - } - - optiface(p, c); - if(invalidcubeguard==1 && !isvalidcube(c)) - { - uint newbak = c.faces[d]; - uchar *m = (uchar *)&bak; - uchar *n = (uchar *)&newbak; - loopk(4) if(n[k] != m[k]) // tries to find partial edit that is valid - { - c.faces[d] = bak; - c.edges[d*4+k] = n[k]; - if(isvalidcube(c)) - m[k] = n[k]; - } - c.faces[d] = bak; - } - } - ); - if (mode==1 && dir>0) - sel.o[d] += sel.grid * seldir; + if(mode==1 && (sel.cx || sel.cy || sel.cxs&1 || sel.cys&1)) mode = 0; + int d = dimension(sel.orient); + int dc = dimcoord(sel.orient); + int seldir = dc ? -dir : dir; + + if(local) + game::edittrigger(sel, EDIT_FACE, dir, mode); + + if(mode==1) + { + int h = sel.o[d]+dc*sel.grid; + if(((dir>0) == dc && h<=0) || ((dir<0) == dc && h>=worldsize)) return; + if(dir<0) sel.o[d] += sel.grid * seldir; + } + + if(dc) sel.o[d] += sel.us(d)-sel.grid; + sel.s[d] = 1; + + loopselxyz( + if(c.children) solidfaces(c); + ushort mat = getmaterial(c); + discardchildren(c, true); + c.material = mat; + if(mode==1) // fill command + { + if(dir<0) + { + solidfaces(c); + cube &o = blockcube(x, y, 1, sel, -sel.grid); + loopi(6) + c.texture[i] = o.children ? (int) DEFAULT_GEOM : (int) o.texture[i]; + } + else + emptyfaces(c); + } + else + { + uint bak = c.faces[d]; + uchar *p = (uchar *)&c.faces[d]; + + if(mode==2) + linkedpush(c, d, sel.corner&1, sel.corner>>1, dc, seldir); // corner command + else + { + loop(mx,2) loop(my,2) // pull/push edges command + { + if(x==0 && mx==0 && sel.cx) continue; + if(y==0 && my==0 && sel.cy) continue; + if(x==sel.s[R[d]]-1 && mx==1 && (sel.cx+sel.cxs)&1) continue; + if(y==sel.s[C[d]]-1 && my==1 && (sel.cy+sel.cys)&1) continue; + if(p[mx+my*2] != ((uchar *)&bak)[mx+my*2]) continue; + + linkedpush(c, d, mx, my, dc, seldir); + } + } + + optiface(p, c); + if(invalidcubeguard==1 && !isvalidcube(c)) + { + uint newbak = c.faces[d]; + uchar *m = (uchar *)&bak; + uchar *n = (uchar *)&newbak; + loopk(4) if(n[k] != m[k]) // tries to find partial edit that is valid + { + c.faces[d] = bak; + c.edges[d*4+k] = n[k]; + if(isvalidcube(c)) + m[k] = n[k]; + } + c.faces[d] = bak; + } + } + ); + if (mode==1 && dir>0) + sel.o[d] += sel.grid * seldir; } void editface(int *dir, int *mode) { - if(noedit(moving!=0)) return; - if(hmapedit!=1) - mpeditface(*dir, *mode, sel, true); - else - edithmap(*dir, *mode); + if(noedit(moving!=0)) return; + if(hmapedit!=1) + mpeditface(*dir, *mode, sel, true); + else + edithmap(*dir, *mode); } VAR(selectionsurf, 0, 0, 1); void pushsel(int *dir) { - if(noedit(moving!=0)) return; - int d = dimension(orient); - int s = dimcoord(orient) ? -*dir : *dir; - sel.o[d] += s*sel.grid; - if(selectionsurf==1) - { - player->o[d] += s*sel.grid; - player->resetinterp(); - } + if(noedit(moving!=0)) return; + int d = dimension(orient); + int s = dimcoord(orient) ? -*dir : *dir; + sel.o[d] += s*sel.grid; + if(selectionsurf==1) + { + player->o[d] += s*sel.grid; + player->resetinterp(); + } } void mpdelcube(selinfo &sel, bool local) { - if(local) game::edittrigger(sel, EDIT_DELCUBE); - loopselxyz(discardchildren(c, true); emptyfaces(c)); + if(local) game::edittrigger(sel, EDIT_DELCUBE); + loopselxyz(discardchildren(c, true); emptyfaces(c)); } void delcube() { - if(noedit(true)) return; - mpdelcube(sel, true); + if(noedit(true)) return; + mpdelcube(sel, true); } COMMAND(pushsel, "i"); @@ -2080,14 +2079,14 @@ int curtexindex = -1, lasttex = 0, lasttexmillis = -1; int texpaneltimer = 0; vector<ushort> texmru; -void tofronttex() // maintain most recently used of the texture lists when applying texture +void tofronttex() // maintain most recently used of the texture lists when applying texture { - int c = curtexindex; - if(texmru.inrange(c)) - { - texmru.insert(0, texmru.remove(c)); - curtexindex = -1; - } + int c = curtexindex; + if(texmru.inrange(c)) + { + texmru.insert(0, texmru.remove(c)); + curtexindex = -1; + } } selinfo repsel; @@ -2099,421 +2098,421 @@ VAR(usevdelta, 1, 0, 0); static VSlot *remapvslot(int index, bool delta, const VSlot &ds) { - loopv(remappedvslots) if(remappedvslots[i].index == index) return remappedvslots[i].vslot; - VSlot &vs = lookupvslot(index, false); - if(vs.index < 0 || vs.index == DEFAULT_SKY) return NULL; - VSlot *edit = NULL; - if(delta) - { - VSlot ms; - mergevslot(ms, vs, ds); - edit = ms.changed ? editvslot(vs, ms) : vs.slot->variants; - } - else edit = ds.changed ? editvslot(vs, ds) : vs.slot->variants; - if(!edit) edit = &vs; - remappedvslots.add(vslotmap(vs.index, edit)); - return edit; + loopv(remappedvslots) if(remappedvslots[i].index == index) return remappedvslots[i].vslot; + VSlot &vs = lookupvslot(index, false); + if(vs.index < 0 || vs.index == DEFAULT_SKY) return NULL; + VSlot *edit = NULL; + if(delta) + { + VSlot ms; + mergevslot(ms, vs, ds); + edit = ms.changed ? editvslot(vs, ms) : vs.slot->variants; + } + else edit = ds.changed ? editvslot(vs, ds) : vs.slot->variants; + if(!edit) edit = &vs; + remappedvslots.add(vslotmap(vs.index, edit)); + return edit; } static void remapvslots(cube &c, bool delta, const VSlot &ds, int orient, bool &findrep, VSlot *&findedit) { - if(c.children) - { - loopi(8) remapvslots(c.children[i], delta, ds, orient, findrep, findedit); - return; - } - static VSlot ms; - if(orient<0) loopi(6) - { - VSlot *edit = remapvslot(c.texture[i], delta, ds); - if(edit) - { - c.texture[i] = edit->index; - if(!findedit) findedit = edit; - } - } - else - { - int i = visibleorient(c, orient); - VSlot *edit = remapvslot(c.texture[i], delta, ds); - if(edit) - { - if(findrep) - { - if(reptex < 0) reptex = c.texture[i]; - else if(reptex != c.texture[i]) findrep = false; - } - c.texture[i] = edit->index; - if(!findedit) findedit = edit; - } - } + if(c.children) + { + loopi(8) remapvslots(c.children[i], delta, ds, orient, findrep, findedit); + return; + } + static VSlot ms; + if(orient<0) loopi(6) + { + VSlot *edit = remapvslot(c.texture[i], delta, ds); + if(edit) + { + c.texture[i] = edit->index; + if(!findedit) findedit = edit; + } + } + else + { + int i = visibleorient(c, orient); + VSlot *edit = remapvslot(c.texture[i], delta, ds); + if(edit) + { + if(findrep) + { + if(reptex < 0) reptex = c.texture[i]; + else if(reptex != c.texture[i]) findrep = false; + } + c.texture[i] = edit->index; + if(!findedit) findedit = edit; + } + } } void edittexcube(cube &c, int tex, int orient, bool &findrep) { - if(orient<0) loopi(6) c.texture[i] = tex; - else - { - int i = visibleorient(c, orient); - if(findrep) - { - if(reptex < 0) reptex = c.texture[i]; - else if(reptex != c.texture[i]) findrep = false; - } - c.texture[i] = tex; - } - if(c.children) loopi(8) edittexcube(c.children[i], tex, orient, findrep); + if(orient<0) loopi(6) c.texture[i] = tex; + else + { + int i = visibleorient(c, orient); + if(findrep) + { + if(reptex < 0) reptex = c.texture[i]; + else if(reptex != c.texture[i]) findrep = false; + } + c.texture[i] = tex; + } + if(c.children) loopi(8) edittexcube(c.children[i], tex, orient, findrep); } VAR(allfaces, 0, 0, 1); void mpeditvslot(int delta, VSlot &ds, int allfaces, selinfo &sel, bool local) { - if(local) - { - game::edittrigger(sel, EDIT_VSLOT, delta, allfaces, 0, &ds); - if(!(lastsel==sel)) tofronttex(); - if(allfaces || !(repsel == sel)) reptex = -1; - repsel = sel; - } - bool findrep = local && !allfaces && reptex < 0; - VSlot *findedit = NULL; - loopselxyz(remapvslots(c, delta != 0, ds, allfaces ? -1 : sel.orient, findrep, findedit)); - remappedvslots.setsize(0); - if(local && findedit) - { - lasttex = findedit->index; - lasttexmillis = totalmillis; - curtexindex = texmru.find(lasttex); - if(curtexindex < 0) - { - curtexindex = texmru.length(); - texmru.add(lasttex); - } - } + if(local) + { + game::edittrigger(sel, EDIT_VSLOT, delta, allfaces, 0, &ds); + if(!(lastsel==sel)) tofronttex(); + if(allfaces || !(repsel == sel)) reptex = -1; + repsel = sel; + } + bool findrep = local && !allfaces && reptex < 0; + VSlot *findedit = NULL; + loopselxyz(remapvslots(c, delta != 0, ds, allfaces ? -1 : sel.orient, findrep, findedit)); + remappedvslots.setsize(0); + if(local && findedit) + { + lasttex = findedit->index; + lasttexmillis = totalmillis; + curtexindex = texmru.find(lasttex); + if(curtexindex < 0) + { + curtexindex = texmru.length(); + texmru.add(lasttex); + } + } } bool mpeditvslot(int delta, int allfaces, selinfo &sel, ucharbuf &buf) { - VSlot ds; - if(!unpackvslot(buf, ds, delta != 0)) return false; - editingvslot(ds.layer); - mpeditvslot(delta, ds, allfaces, sel, false); - return true; + VSlot ds; + if(!unpackvslot(buf, ds, delta != 0)) return false; + editingvslot(ds.layer); + mpeditvslot(delta, ds, allfaces, sel, false); + return true; } void vdelta(char *body) { - if(noedit()) return; - usevdelta++; - execute(body); - usevdelta--; + if(noedit()) return; + usevdelta++; + execute(body); + usevdelta--; } COMMAND(vdelta, "s"); void vrotate(int *n) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_ROTATION; - ds.rotation = usevdelta ? *n : clamp(*n, 0, 7); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_ROTATION; + ds.rotation = usevdelta ? *n : clamp(*n, 0, 7); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vrotate, "i"); ICOMMAND(getvrotate, "i", (int *tex), intret(lookupvslot(*tex, false).rotation)); void voffset(int *x, int *y) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_OFFSET; - ds.offset = usevdelta ? ivec2(*x, *y) : ivec2(*x, *y).max(0); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_OFFSET; + ds.offset = usevdelta ? ivec2(*x, *y) : ivec2(*x, *y).max(0); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(voffset, "ii"); ICOMMAND(getvoffset, "i", (int *tex), { - VSlot &vslot = lookupvslot(*tex, false); - defformatstring(str, "%d %d", vslot.offset.x, vslot.offset.y); - result(str); + VSlot &vslot = lookupvslot(*tex, false); + defformatstring(str, "%d %d", vslot.offset.x, vslot.offset.y); + result(str); }); void vscroll(float *s, float *t) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_SCROLL; - ds.scroll = vec2(*s, *t).div(1000); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_SCROLL; + ds.scroll = vec2(*s, *t).div(1000); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vscroll, "ff"); ICOMMAND(getvscroll, "i", (int *tex), { - VSlot &vslot = lookupvslot(*tex, false); - defformatstring(str, "%s %s", floatstr(vslot.scroll.x), floatstr(vslot.scroll.y)); - result(str); + VSlot &vslot = lookupvslot(*tex, false); + defformatstring(str, "%s %s", floatstr(vslot.scroll.x), floatstr(vslot.scroll.y)); + result(str); }); void vscale(float *scale) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_SCALE; - ds.scale = *scale <= 0 ? 1 : (usevdelta ? *scale : clamp(*scale, 1/8.0f, 8.0f)); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_SCALE; + ds.scale = *scale <= 0 ? 1 : (usevdelta ? *scale : clamp(*scale, 1/8.0f, 8.0f)); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vscale, "f"); ICOMMAND(getvscale, "i", (int *tex), floatret(lookupvslot(*tex, false).scale)); void vlayer(int *n) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_LAYER; - if(vslots.inrange(*n)) - { - ds.layer = *n; - if(vslots[ds.layer]->changed && nompedit && multiplayer()) return; - } - editingvslot(ds.layer); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_LAYER; + if(vslots.inrange(*n)) + { + ds.layer = *n; + if(vslots[ds.layer]->changed && nompedit && multiplayer()) return; + } + editingvslot(ds.layer); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vlayer, "i"); ICOMMAND(getvlayer, "i", (int *tex), intret(lookupvslot(*tex, false).layer)); void valpha(float *front, float *back) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_ALPHA; - ds.alphafront = clamp(*front, 0.0f, 1.0f); - ds.alphaback = clamp(*back, 0.0f, 1.0f); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_ALPHA; + ds.alphafront = clamp(*front, 0.0f, 1.0f); + ds.alphaback = clamp(*back, 0.0f, 1.0f); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(valpha, "ff"); ICOMMAND(getvalpha, "i", (int *tex), { - VSlot &vslot = lookupvslot(*tex, false); - defformatstring(str, "%s %s", floatstr(vslot.alphafront), floatstr(vslot.alphaback)); - result(str); + VSlot &vslot = lookupvslot(*tex, false); + defformatstring(str, "%s %s", floatstr(vslot.alphafront), floatstr(vslot.alphaback)); + result(str); }); void vcolor(float *r, float *g, float *b) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_COLOR; - ds.colorscale = vec(clamp(*r, 0.0f, 1.0f), clamp(*g, 0.0f, 1.0f), clamp(*b, 0.0f, 1.0f)); - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_COLOR; + ds.colorscale = vec(clamp(*r, 0.0f, 1.0f), clamp(*g, 0.0f, 1.0f), clamp(*b, 0.0f, 1.0f)); + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vcolor, "fff"); ICOMMAND(getvcolor, "i", (int *tex), { - VSlot &vslot = lookupvslot(*tex, false); - defformatstring(str, "%s %s %s", floatstr(vslot.colorscale.r), floatstr(vslot.colorscale.g), floatstr(vslot.colorscale.b)); - result(str); + VSlot &vslot = lookupvslot(*tex, false); + defformatstring(str, "%s %s %s", floatstr(vslot.colorscale.r), floatstr(vslot.colorscale.g), floatstr(vslot.colorscale.b)); + result(str); }); void vreset() { - if(noedit()) return; - VSlot ds; - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vreset, ""); void vshaderparam(const char *name, float *x, float *y, float *z, float *w) { - if(noedit()) return; - VSlot ds; - ds.changed = 1<<VSLOT_SHPARAM; - if(name[0]) - { - SlotShaderParam p = { getshaderparamname(name), -1, {*x, *y, *z, *w} }; - ds.params.add(p); - } - mpeditvslot(usevdelta, ds, allfaces, sel, true); + if(noedit()) return; + VSlot ds; + ds.changed = 1<<VSLOT_SHPARAM; + if(name[0]) + { + SlotShaderParam p = { getshaderparamname(name), -1, {*x, *y, *z, *w} }; + ds.params.add(p); + } + mpeditvslot(usevdelta, ds, allfaces, sel, true); } COMMAND(vshaderparam, "sffff"); ICOMMAND(getvshaderparam, "is", (int *tex, const char *name), { - VSlot &vslot = lookupvslot(*tex, false); - loopv(vslot.params) - { - SlotShaderParam &p = vslot.params[i]; - if(!strcmp(p.name, name)) - { - defformatstring(str, "%s %s %s %s", floatstr(p.val[0]), floatstr(p.val[1]), floatstr(p.val[2]), floatstr(p.val[3])); - result(str); - return; - } - } + VSlot &vslot = lookupvslot(*tex, false); + loopv(vslot.params) + { + SlotShaderParam &p = vslot.params[i]; + if(!strcmp(p.name, name)) + { + defformatstring(str, "%s %s %s %s", floatstr(p.val[0]), floatstr(p.val[1]), floatstr(p.val[2]), floatstr(p.val[3])); + result(str); + return; + } + } }); ICOMMAND(getvshaderparamnames, "i", (int *tex), { - VSlot &vslot = lookupvslot(*tex, false); - vector<char> str; - loopv(vslot.params) - { - SlotShaderParam &p = vslot.params[i]; - if(i) str.put(' '); - str.put(p.name, strlen(p.name)); - } - str.add('\0'); - stringret(newstring(str.getbuf(), str.length()-1)); + VSlot &vslot = lookupvslot(*tex, false); + vector<char> str; + loopv(vslot.params) + { + SlotShaderParam &p = vslot.params[i]; + if(i) str.put(' '); + str.put(p.name, strlen(p.name)); + } + str.add('\0'); + stringret(newstring(str.getbuf(), str.length()-1)); }); void mpedittex(int tex, int allfaces, selinfo &sel, bool local) { - if(local) - { - game::edittrigger(sel, EDIT_TEX, tex, allfaces); - if(allfaces || !(repsel == sel)) reptex = -1; - repsel = sel; - } - bool findrep = local && !allfaces && reptex < 0; - loopselxyz(edittexcube(c, tex, allfaces ? -1 : sel.orient, findrep)); + if(local) + { + game::edittrigger(sel, EDIT_TEX, tex, allfaces); + if(allfaces || !(repsel == sel)) reptex = -1; + repsel = sel; + } + bool findrep = local && !allfaces && reptex < 0; + loopselxyz(edittexcube(c, tex, allfaces ? -1 : sel.orient, findrep)); } static int unpacktex(int &tex, ucharbuf &buf, bool insert = true) { - if(tex < 0x10000) return true; - VSlot ds; - if(!unpackvslot(buf, ds, false)) return false; - VSlot &vs = *lookupslot(tex & 0xFFFF, false).variants; - if(vs.index < 0 || vs.index == DEFAULT_SKY) return false; - VSlot *edit = insert ? editvslot(vs, ds) : findvslot(*vs.slot, vs, ds); - if(!edit) return false; - tex = edit->index; - return true; + if(tex < 0x10000) return true; + VSlot ds; + if(!unpackvslot(buf, ds, false)) return false; + VSlot &vs = *lookupslot(tex & 0xFFFF, false).variants; + if(vs.index < 0 || vs.index == DEFAULT_SKY) return false; + VSlot *edit = insert ? editvslot(vs, ds) : findvslot(*vs.slot, vs, ds); + if(!edit) return false; + tex = edit->index; + return true; } int shouldpacktex(int index) { - if(vslots.inrange(index)) - { - VSlot &vs = *vslots[index]; - if(vs.changed) return 0x10000 + vs.slot->index; - } - return 0; + if(vslots.inrange(index)) + { + VSlot &vs = *vslots[index]; + if(vs.changed) return 0x10000 + vs.slot->index; + } + return 0; } bool mpedittex(int tex, int allfaces, selinfo &sel, ucharbuf &buf) { - if(!unpacktex(tex, buf)) return false; - mpedittex(tex, allfaces, sel, false); - return true; + if(!unpacktex(tex, buf)) return false; + mpedittex(tex, allfaces, sel, false); + return true; } void filltexlist() { - if(texmru.length()!=vslots.length()) - { - loopvrev(texmru) if(texmru[i]>=vslots.length()) - { - if(curtexindex > i) curtexindex--; - else if(curtexindex == i) curtexindex = -1; - texmru.remove(i); - } - loopv(vslots) if(texmru.find(i)<0) texmru.add(i); - } + if(texmru.length()!=vslots.length()) + { + loopvrev(texmru) if(texmru[i]>=vslots.length()) + { + if(curtexindex > i) curtexindex--; + else if(curtexindex == i) curtexindex = -1; + texmru.remove(i); + } + loopv(vslots) if(texmru.find(i)<0) texmru.add(i); + } } void compactmruvslots() { - remappedvslots.setsize(0); - loopvrev(texmru) - { - if(vslots.inrange(texmru[i])) - { - VSlot &vs = *vslots[texmru[i]]; - if(vs.index >= 0) - { - texmru[i] = vs.index; - continue; - } - } - if(curtexindex > i) curtexindex--; - else if(curtexindex == i) curtexindex = -1; - texmru.remove(i); - } - if(vslots.inrange(lasttex)) - { - VSlot &vs = *vslots[lasttex]; - lasttex = vs.index >= 0 ? vs.index : 0; - } - else lasttex = 0; - reptex = vslots.inrange(reptex) ? vslots[reptex]->index : -1; + remappedvslots.setsize(0); + loopvrev(texmru) + { + if(vslots.inrange(texmru[i])) + { + VSlot &vs = *vslots[texmru[i]]; + if(vs.index >= 0) + { + texmru[i] = vs.index; + continue; + } + } + if(curtexindex > i) curtexindex--; + else if(curtexindex == i) curtexindex = -1; + texmru.remove(i); + } + if(vslots.inrange(lasttex)) + { + VSlot &vs = *vslots[lasttex]; + lasttex = vs.index >= 0 ? vs.index : 0; + } + else lasttex = 0; + reptex = vslots.inrange(reptex) ? vslots[reptex]->index : -1; } void edittex(int i, bool save = true) { - lasttex = i; - lasttexmillis = totalmillis; - if(save) - { - loopvj(texmru) if(texmru[j]==lasttex) { curtexindex = j; break; } - } - mpedittex(i, allfaces, sel, true); + lasttex = i; + lasttexmillis = totalmillis; + if(save) + { + loopvj(texmru) if(texmru[j]==lasttex) { curtexindex = j; break; } + } + mpedittex(i, allfaces, sel, true); } void edittex_(int *dir) { - if(noedit()) return; - filltexlist(); - if(texmru.empty()) return; - texpaneltimer = 5000; - if(!(lastsel==sel)) tofronttex(); - curtexindex = clamp(curtexindex<0 ? 0 : curtexindex+*dir, 0, texmru.length()-1); - edittex(texmru[curtexindex], false); + if(noedit()) return; + filltexlist(); + if(texmru.empty()) return; + texpaneltimer = 5000; + if(!(lastsel==sel)) tofronttex(); + curtexindex = clamp(curtexindex<0 ? 0 : curtexindex+*dir, 0, texmru.length()-1); + edittex(texmru[curtexindex], false); } void gettex() { - if(noedit(true)) return; - filltexlist(); - int tex = -1; - loopxyz(sel, sel.grid, tex = c.texture[sel.orient]); - loopv(texmru) if(texmru[i]==tex) - { - curtexindex = i; - tofronttex(); - return; - } + if(noedit(true)) return; + filltexlist(); + int tex = -1; + loopxyz(sel, sel.grid, tex = c.texture[sel.orient]); + loopv(texmru) if(texmru[i]==tex) + { + curtexindex = i; + tofronttex(); + return; + } } void getcurtex() { - if(noedit(true)) return; - filltexlist(); - int index = curtexindex < 0 ? 0 : curtexindex; - if(!texmru.inrange(index)) return; - intret(texmru[index]); + if(noedit(true)) return; + filltexlist(); + int index = curtexindex < 0 ? 0 : curtexindex; + if(!texmru.inrange(index)) return; + intret(texmru[index]); } void getseltex() { - if(noedit(true)) return; - cube &c = lookupcube(sel.o, -sel.grid); - if(c.children || isempty(c)) return; - intret(c.texture[sel.orient]); + if(noedit(true)) return; + cube &c = lookupcube(sel.o, -sel.grid); + if(c.children || isempty(c)) return; + intret(c.texture[sel.orient]); } void gettexname(int *tex, int *subslot) { - if(noedit(true) || *tex<0) return; - VSlot &vslot = lookupvslot(*tex, false); - Slot &slot = *vslot.slot; - if(!slot.sts.inrange(*subslot)) return; - result(slot.sts[*subslot].name); + if(noedit(true) || *tex<0) return; + VSlot &vslot = lookupvslot(*tex, false); + Slot &slot = *vslot.slot; + if(!slot.sts.inrange(*subslot)) return; + result(slot.sts[*subslot].name); } void getslottex(int *idx) { - if(*idx < 0 || !slots.inrange(*idx)) { intret(-1); return; } - Slot &slot = lookupslot(*idx, false); - intret(slot.variants->index); + if(*idx < 0 || !slots.inrange(*idx)) { intret(-1); return; } + Slot &slot = lookupslot(*idx, false); + intret(slot.variants->index); } COMMANDN(edittex, edittex_, "i"); @@ -2529,38 +2528,38 @@ ICOMMAND(texloaded, "i", (int *tex), intret(slots.inrange(*tex) && slots[*tex]-> void replacetexcube(cube &c, int oldtex, int newtex) { - loopi(6) if(c.texture[i] == oldtex) c.texture[i] = newtex; - if(c.children) loopi(8) replacetexcube(c.children[i], oldtex, newtex); + loopi(6) if(c.texture[i] == oldtex) c.texture[i] = newtex; + if(c.children) loopi(8) replacetexcube(c.children[i], oldtex, newtex); } void mpreplacetex(int oldtex, int newtex, bool insel, selinfo &sel, bool local) { - if(local) game::edittrigger(sel, EDIT_REPLACE, oldtex, newtex, insel ? 1 : 0); - if(insel) - { - loopselxyz(replacetexcube(c, oldtex, newtex)); - } - else - { - loopi(8) replacetexcube(worldroot[i], oldtex, newtex); - } - allchanged(); + if(local) game::edittrigger(sel, EDIT_REPLACE, oldtex, newtex, insel ? 1 : 0); + if(insel) + { + loopselxyz(replacetexcube(c, oldtex, newtex)); + } + else + { + loopi(8) replacetexcube(worldroot[i], oldtex, newtex); + } + allchanged(); } bool mpreplacetex(int oldtex, int newtex, bool insel, selinfo &sel, ucharbuf &buf) { - if(!unpacktex(oldtex, buf, false)) return false; - editingvslot(oldtex); - if(!unpacktex(newtex, buf)) return false; - mpreplacetex(oldtex, newtex, insel, sel, false); - return true; + if(!unpacktex(oldtex, buf, false)) return false; + editingvslot(oldtex); + if(!unpacktex(newtex, buf)) return false; + mpreplacetex(oldtex, newtex, insel, sel, false); + return true; } void replace(bool insel) { - if(noedit()) return; - if(reptex < 0) { conoutf(CON_ERROR, "can only replace after a texture edit"); return; } - mpreplacetex(reptex, lasttex, insel, sel, true); + if(noedit()) return; + if(reptex < 0) { conoutf(CON_ERROR, "can only replace after a texture edit"); return; } + mpreplacetex(reptex, lasttex, insel, sel, true); } ICOMMAND(replace, "", (), replace(false)); @@ -2574,101 +2573,101 @@ uint mflip(uint face) { return (face&0xFF0000FF) | ((face&0x00FF0000)>>8) | ((fa void flipcube(cube &c, int d) { - swap(c.texture[d*2], c.texture[d*2+1]); - c.faces[D[d]] = dflip(c.faces[D[d]]); - c.faces[C[d]] = cflip(c.faces[C[d]]); - c.faces[R[d]] = rflip(c.faces[R[d]]); - if(c.children) - { - loopi(8) if(i&octadim(d)) swap(c.children[i], c.children[i-octadim(d)]); - loopi(8) flipcube(c.children[i], d); - } + swap(c.texture[d*2], c.texture[d*2+1]); + c.faces[D[d]] = dflip(c.faces[D[d]]); + c.faces[C[d]] = cflip(c.faces[C[d]]); + c.faces[R[d]] = rflip(c.faces[R[d]]); + if(c.children) + { + loopi(8) if(i&octadim(d)) swap(c.children[i], c.children[i-octadim(d)]); + loopi(8) flipcube(c.children[i], d); + } } void rotatequad(cube &a, cube &b, cube &c, cube &d) { - cube t = a; a = b; b = c; c = d; d = t; + cube t = a; a = b; b = c; c = d; d = t; } void rotatecube(cube &c, int d) // rotates cube clockwise. see pics in cvs for help. { - c.faces[D[d]] = cflip (mflip(c.faces[D[d]])); - c.faces[C[d]] = dflip (mflip(c.faces[C[d]])); - c.faces[R[d]] = rflip (mflip(c.faces[R[d]])); - swap(c.faces[R[d]], c.faces[C[d]]); - - swap(c.texture[2*R[d]], c.texture[2*C[d]+1]); - swap(c.texture[2*C[d]], c.texture[2*R[d]+1]); - swap(c.texture[2*C[d]], c.texture[2*C[d]+1]); - - if(c.children) - { - int row = octadim(R[d]); - int col = octadim(C[d]); - for(int i=0; i<=octadim(d); i+=octadim(d)) rotatequad - ( - c.children[i+row], - c.children[i], - c.children[i+col], - c.children[i+col+row] - ); - loopi(8) rotatecube(c.children[i], d); - } + c.faces[D[d]] = cflip (mflip(c.faces[D[d]])); + c.faces[C[d]] = dflip (mflip(c.faces[C[d]])); + c.faces[R[d]] = rflip (mflip(c.faces[R[d]])); + swap(c.faces[R[d]], c.faces[C[d]]); + + swap(c.texture[2*R[d]], c.texture[2*C[d]+1]); + swap(c.texture[2*C[d]], c.texture[2*R[d]+1]); + swap(c.texture[2*C[d]], c.texture[2*C[d]+1]); + + if(c.children) + { + int row = octadim(R[d]); + int col = octadim(C[d]); + for(int i=0; i<=octadim(d); i+=octadim(d)) rotatequad + ( + c.children[i+row], + c.children[i], + c.children[i+col], + c.children[i+col+row] + ); + loopi(8) rotatecube(c.children[i], d); + } } void mpflip(selinfo &sel, bool local) { - if(local) - { - game::edittrigger(sel, EDIT_FLIP); - makeundo(); - } - int zs = sel.s[dimension(sel.orient)]; - loopxy(sel) - { - loop(z,zs) flipcube(selcube(x, y, z), dimension(sel.orient)); - loop(z,zs/2) - { - cube &a = selcube(x, y, z); - cube &b = selcube(x, y, zs-z-1); - swap(a, b); - } - } - changed(sel); + if(local) + { + game::edittrigger(sel, EDIT_FLIP); + makeundo(); + } + int zs = sel.s[dimension(sel.orient)]; + loopxy(sel) + { + loop(z,zs) flipcube(selcube(x, y, z), dimension(sel.orient)); + loop(z,zs/2) + { + cube &a = selcube(x, y, z); + cube &b = selcube(x, y, zs-z-1); + swap(a, b); + } + } + changed(sel); } void flip() { - if(noedit()) return; - mpflip(sel, true); + if(noedit()) return; + mpflip(sel, true); } void mprotate(int cw, selinfo &sel, bool local) { - if(local) game::edittrigger(sel, EDIT_ROTATE, cw); - int d = dimension(sel.orient); - if(!dimcoord(sel.orient)) cw = -cw; - int m = sel.s[C[d]] < sel.s[R[d]] ? C[d] : R[d]; - int ss = sel.s[m] = max(sel.s[R[d]], sel.s[C[d]]); - if(local) makeundo(); - loop(z,sel.s[D[d]]) loopi(cw>0 ? 1 : 3) - { - loopxy(sel) rotatecube(selcube(x,y,z), d); - loop(y,ss/2) loop(x,ss-1-y*2) rotatequad - ( - selcube(ss-1-y, x+y, z), - selcube(x+y, y, z), - selcube(y, ss-1-x-y, z), - selcube(ss-1-x-y, ss-1-y, z) - ); - } - changed(sel); + if(local) game::edittrigger(sel, EDIT_ROTATE, cw); + int d = dimension(sel.orient); + if(!dimcoord(sel.orient)) cw = -cw; + int m = sel.s[C[d]] < sel.s[R[d]] ? C[d] : R[d]; + int ss = sel.s[m] = max(sel.s[R[d]], sel.s[C[d]]); + if(local) makeundo(); + loop(z,sel.s[D[d]]) loopi(cw>0 ? 1 : 3) + { + loopxy(sel) rotatecube(selcube(x,y,z), d); + loop(y,ss/2) loop(x,ss-1-y*2) rotatequad + ( + selcube(ss-1-y, x+y, z), + selcube(x+y, y, z), + selcube(y, ss-1-x-y, z), + selcube(ss-1-x-y, ss-1-y, z) + ); + } + changed(sel); } void rotate(int *cw) { - if(noedit()) return; - mprotate(*cw, sel, true); + if(noedit()) return; + mprotate(*cw, sel, true); } COMMAND(flip, ""); @@ -2677,83 +2676,83 @@ COMMAND(rotate, "i"); enum { EDITMATF_EMPTY = 0x10000, EDITMATF_NOTEMPTY = 0x20000, EDITMATF_SOLID = 0x30000, EDITMATF_NOTSOLID = 0x40000 }; static const struct { const char *name; int filter; } editmatfilters[] = { - { "empty", EDITMATF_EMPTY }, - { "notempty", EDITMATF_NOTEMPTY }, - { "solid", EDITMATF_SOLID }, - { "notsolid", EDITMATF_NOTSOLID } + { "empty", EDITMATF_EMPTY }, + { "notempty", EDITMATF_NOTEMPTY }, + { "solid", EDITMATF_SOLID }, + { "notsolid", EDITMATF_NOTSOLID } }; void setmat(cube &c, ushort mat, ushort matmask, ushort filtermat, ushort filtermask, int filtergeom) { - if(c.children) - loopi(8) setmat(c.children[i], mat, matmask, filtermat, filtermask, filtergeom); - else if((c.material&filtermask) == filtermat) - { - switch(filtergeom) - { - case EDITMATF_EMPTY: if(isempty(c)) break; return; - case EDITMATF_NOTEMPTY: if(!isempty(c)) break; return; - case EDITMATF_SOLID: if(isentirelysolid(c)) break; return; - case EDITMATF_NOTSOLID: if(!isentirelysolid(c)) break; return; - } - if(mat!=MAT_AIR) - { - c.material &= matmask; - c.material |= mat; - } - else c.material = MAT_AIR; - } + if(c.children) + loopi(8) setmat(c.children[i], mat, matmask, filtermat, filtermask, filtergeom); + else if((c.material&filtermask) == filtermat) + { + switch(filtergeom) + { + case EDITMATF_EMPTY: if(isempty(c)) break; return; + case EDITMATF_NOTEMPTY: if(!isempty(c)) break; return; + case EDITMATF_SOLID: if(isentirelysolid(c)) break; return; + case EDITMATF_NOTSOLID: if(!isentirelysolid(c)) break; return; + } + if(mat!=MAT_AIR) + { + c.material &= matmask; + c.material |= mat; + } + else c.material = MAT_AIR; + } } void mpeditmat(int matid, int filter, selinfo &sel, bool local) { - if(local) game::edittrigger(sel, EDIT_MAT, matid, filter); - - ushort filtermat = 0, filtermask = 0, matmask; - int filtergeom = 0; - if(filter >= 0) - { - filtermat = filter&0xFFFF; - filtermask = filtermat&(MATF_VOLUME|MATF_INDEX) ? (int) MATF_VOLUME|MATF_INDEX : (filtermat&MATF_CLIP ? (int) MATF_CLIP : (int) filtermat); - filtergeom = filter&~0xFFFF; - } - if(matid < 0) - { - matid = 0; - matmask = filtermask; - if(isclipped(filtermat&MATF_VOLUME)) matmask &= ~MATF_CLIP; - if(isdeadly(filtermat&MATF_VOLUME)) matmask &= ~MAT_DEATH; - } - else - { - matmask = matid&(MATF_VOLUME|MATF_INDEX) ? 0 : (matid&MATF_CLIP ? ~MATF_CLIP : ~matid); - if(isclipped(matid&MATF_VOLUME)) matid |= MAT_CLIP; - if(isdeadly(matid&MATF_VOLUME)) matid |= MAT_DEATH; - } - loopselxyz(setmat(c, matid, matmask, filtermat, filtermask, filtergeom)); + if(local) game::edittrigger(sel, EDIT_MAT, matid, filter); + + ushort filtermat = 0, filtermask = 0, matmask; + int filtergeom = 0; + if(filter >= 0) + { + filtermat = filter&0xFFFF; + filtermask = filtermat&(MATF_VOLUME|MATF_INDEX) ? (int) MATF_VOLUME|MATF_INDEX : (filtermat&MATF_CLIP ? (int) MATF_CLIP : (int) filtermat); + filtergeom = filter&~0xFFFF; + } + if(matid < 0) + { + matid = 0; + matmask = filtermask; + if(isclipped(filtermat&MATF_VOLUME)) matmask &= ~MATF_CLIP; + if(isdeadly(filtermat&MATF_VOLUME)) matmask &= ~MAT_DEATH; + } + else + { + matmask = matid&(MATF_VOLUME|MATF_INDEX) ? 0 : (matid&MATF_CLIP ? ~MATF_CLIP : ~matid); + if(isclipped(matid&MATF_VOLUME)) matid |= MAT_CLIP; + if(isdeadly(matid&MATF_VOLUME)) matid |= MAT_DEATH; + } + loopselxyz(setmat(c, matid, matmask, filtermat, filtermask, filtergeom)); } void editmat(char *name, char *filtername) { - if(noedit()) return; - int filter = -1; - if(filtername[0]) - { - loopi(sizeof(editmatfilters)/sizeof(editmatfilters[0])) if(!strcmp(editmatfilters[i].name, filtername)) { filter = editmatfilters[i].filter; break; } - if(filter < 0) filter = findmaterial(filtername); - if(filter < 0) - { - conoutf(CON_ERROR, "unknown material \"%s\"", filtername); - return; - } - } - int id = -1; - if(name[0] || filter < 0) - { - id = findmaterial(name); - if(id<0) { conoutf(CON_ERROR, "unknown material \"%s\"", name); return; } - } - mpeditmat(id, filter, sel, true); + if(noedit()) return; + int filter = -1; + if(filtername[0]) + { + loopi(sizeof(editmatfilters)/sizeof(editmatfilters[0])) if(!strcmp(editmatfilters[i].name, filtername)) { filter = editmatfilters[i].filter; break; } + if(filter < 0) filter = findmaterial(filtername); + if(filter < 0) + { + conoutf(CON_ERROR, "unknown material \"%s\"", filtername); + return; + } + } + int id = -1; + if(name[0] || filter < 0) + { + id = findmaterial(name); + if(id<0) { conoutf(CON_ERROR, "unknown material \"%s\"", name); return; } + } + mpeditmat(id, filter, sel, true); } COMMAND(editmat, "ss"); @@ -2773,106 +2772,106 @@ VAR(texguinum, 1, -1, 0); struct texturegui : g3d_callback { - bool menuon; - vec menupos; - int menustart, menutab; - - texturegui() : menustart(-1) {} - - void gui(g3d_gui &g, bool firstpass) - { - int origtab = menutab, numtabs = max((slots.length() + texguiwidth*texguiheight - 1)/(texguiwidth*texguiheight), 1); - if(!firstpass) texguinum = -1; - g.start(menustart, 0.04f, &menutab); - bool oldautotab = g.allowautotab(false); - loopi(numtabs) - { - g.tab(!i ? "Textures" : NULL, 0xFFDD88); - if(i+1 != origtab) continue; //don't load textures on non-visible tabs! - Slot *rollover = NULL; - loop(h, texguiheight) - { - g.pushlist(); - loop(w, texguiwidth) - { - extern VSlot dummyvslot; - int ti = (i*texguiheight+h)*texguiwidth+w; - if(ti<slots.length()) - { - Slot &slot = lookupslot(ti, false); - VSlot &vslot = *slot.variants; - if(slot.sts.empty()) continue; - else if(!slot.loaded && !slot.thumbnail) - { - if(totalmillis-lastthumbnail<texguitime) - { - g.texture(dummyvslot, texguiscale, false); //create an empty space - continue; - } - loadthumbnail(slot); - lastthumbnail = totalmillis; - } - int ret = g.texture(vslot, texguiscale, true); - if(ret&G3D_ROLLOVER) { rollover = &slot; texguinum = ti; } - if(ret&G3D_UP && (slot.loaded || slot.thumbnail!=notexture)) - { - edittex(vslot.index); - hudshader->set(); - } - } - else - { - g.texture(dummyvslot, texguiscale, false); //create an empty space - } - } - g.poplist(); - } - if(texguiname) - { - if(rollover) - { - defformatstring(name, "%d \f7:\fc %s", texguinum, rollover->sts[0].name); - g.title(name, 0xFFDD88); - } - else g.space(1); - } - } - g.allowautotab(oldautotab); - g.end(); - } - - void showtextures(bool on) - { - if(on == menuon) return; - if((menuon = on)) - { - if(menustart <= lasttexmillis) - menutab = 1+clamp(lookupvslot(lasttex, false).slot->index, 0, slots.length()-1)/(texguiwidth*texguiheight); - menupos = menuinfrontofplayer(); - menustart = starttime(); - } - else texguinum = -1; - } - - void show() - { - if(!menuon) return; - filltexlist(); - extern int usegui2d; - if(!editmode || ((!texgui2d || !usegui2d) && camera1->o.dist(menupos) > menuautoclose)) { menuon = false; texguinum = -1; } - else g3d_addgui(this, menupos, texgui2d ? GUI_2D : 0); - } + bool menuon; + vec menupos; + int menustart, menutab; + + texturegui() : menustart(-1) {} + + void gui(g3d_gui &g, bool firstpass) + { + int origtab = menutab, numtabs = max((slots.length() + texguiwidth*texguiheight - 1)/(texguiwidth*texguiheight), 1); + if(!firstpass) texguinum = -1; + g.start(menustart, 0.04f, &menutab); + bool oldautotab = g.allowautotab(false); + loopi(numtabs) + { + g.tab(!i ? "Textures" : NULL, 0xFFDD88); + if(i+1 != origtab) continue; //don't load textures on non-visible tabs! + Slot *rollover = NULL; + loop(h, texguiheight) + { + g.pushlist(); + loop(w, texguiwidth) + { + extern VSlot dummyvslot; + int ti = (i*texguiheight+h)*texguiwidth+w; + if(ti<slots.length()) + { + Slot &slot = lookupslot(ti, false); + VSlot &vslot = *slot.variants; + if(slot.sts.empty()) continue; + else if(!slot.loaded && !slot.thumbnail) + { + if(totalmillis-lastthumbnail<texguitime) + { + g.texture(dummyvslot, texguiscale, false); //create an empty space + continue; + } + loadthumbnail(slot); + lastthumbnail = totalmillis; + } + int ret = g.texture(vslot, texguiscale, true); + if(ret&G3D_ROLLOVER) { rollover = &slot; texguinum = ti; } + if(ret&G3D_UP && (slot.loaded || slot.thumbnail!=notexture)) + { + edittex(vslot.index); + hudshader->set(); + } + } + else + { + g.texture(dummyvslot, texguiscale, false); //create an empty space + } + } + g.poplist(); + } + if(texguiname) + { + if(rollover) + { + defformatstring(name, "%d \f7:\fc %s", texguinum, rollover->sts[0].name); + g.title(name, 0xFFDD88); + } + else g.space(1); + } + } + g.allowautotab(oldautotab); + g.end(); + } + + void showtextures(bool on) + { + if(on == menuon) return; + if((menuon = on)) + { + if(menustart <= lasttexmillis) + menutab = 1+clamp(lookupvslot(lasttex, false).slot->index, 0, slots.length()-1)/(texguiwidth*texguiheight); + menupos = menuinfrontofplayer(); + menustart = starttime(); + } + else texguinum = -1; + } + + void show() + { + if(!menuon) return; + filltexlist(); + extern int usegui2d; + if(!editmode || ((!texgui2d || !usegui2d) && camera1->o.dist(menupos) > menuautoclose)) { menuon = false; texguinum = -1; } + else g3d_addgui(this, menupos, texgui2d ? GUI_2D : 0); + } } gui; void g3d_texturemenu() { - gui.show(); + gui.show(); } void showtexgui(int *n) { - if(!editmode) { conoutf(CON_ERROR, "operation only allowed in edit mode"); return; } - gui.showtextures(*n==0 ? !gui.menuon : *n==1); + if(!editmode) { conoutf(CON_ERROR, "operation only allowed in edit mode"); return; } + gui.showtextures(*n==0 ? !gui.menuon : *n==1); } // 0/noargs = toggle, 1 = on, other = off - will autoclose if too far away or exit editmode @@ -2880,97 +2879,97 @@ COMMAND(showtexgui, "i"); bool cleartexgui() { - if(!gui.menuon) return false; - gui.showtextures(false); - return true; + if(!gui.menuon) return false; + gui.showtextures(false); + return true; } ICOMMAND(cleartexgui, "", (), intret(cleartexgui() ? 1 : 0)); void rendertexturepanel(int w, int h) { - if((texpaneltimer -= curtime)>0 && editmode) - { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - pushhudmatrix(); - hudmatrix.scale(h/1800.0f, h/1800.0f, 1); - flushhudmatrix(false); - SETSHADER(hudrgb); - - int y = 50, gap = 10; - - gle::defvertex(2); - gle::deftexcoord0(); - - loopi(7) - { - int s = (i == 3 ? 285 : 220), ti = curtexindex+i-3; - if(texmru.inrange(ti)) - { - VSlot &vslot = lookupvslot(texmru[ti]), *layer = NULL; - Slot &slot = *vslot.slot; - Texture *tex = slot.sts.empty() ? notexture : slot.sts[0].t, *glowtex = NULL, *layertex = NULL; - if(slot.texmask&(1<<TEX_GLOW)) - { - loopvj(slot.sts) if(slot.sts[j].type==TEX_GLOW) { glowtex = slot.sts[j].t; break; } - } - if(vslot.layer) - { - layer = &lookupvslot(vslot.layer); - layertex = layer->slot->sts.empty() ? notexture : layer->slot->sts[0].t; - } - float sx = min(1.0f, tex->xs/(float)tex->ys), sy = min(1.0f, tex->ys/(float)tex->xs); - int x = w*1800/h-s-50, r = s; - vec2 tc[4] = { vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1) }; - float xoff = vslot.offset.x, yoff = vslot.offset.y; - if(vslot.rotation) - { - const texrotation &r = texrotations[vslot.rotation]; - if(r.swapxy) { swap(xoff, yoff); loopk(4) swap(tc[k].x, tc[k].y); } - if(r.flipx) { xoff *= -1; loopk(4) tc[k].x *= -1; } - if(r.flipy) { yoff *= -1; loopk(4) tc[k].y *= -1; } - } - loopk(4) { tc[k].x = tc[k].x/sx - xoff/tex->xs; tc[k].y = tc[k].y/sy - yoff/tex->ys; } - glBindTexture(GL_TEXTURE_2D, tex->id); - loopj(glowtex ? 3 : 2) - { - if(j < 2) gle::color(vec(vslot.colorscale).mul(j), texpaneltimer/1000.0f); - else - { - glBindTexture(GL_TEXTURE_2D, glowtex->id); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - gle::color(vslot.glowcolor, texpaneltimer/1000.0f); - } - gle::begin(GL_TRIANGLE_STRIP); - gle::attribf(x, y); gle::attrib(tc[0]); - gle::attribf(x+r, y); gle::attrib(tc[1]); - gle::attribf(x, y+r); gle::attrib(tc[3]); - gle::attribf(x+r, y+r); gle::attrib(tc[2]); - xtraverts += gle::end(); - if(j==1 && layertex) - { - gle::color(layer->colorscale, texpaneltimer/1000.0f); - glBindTexture(GL_TEXTURE_2D, layertex->id); - gle::begin(GL_TRIANGLE_STRIP); - gle::attribf(x+r/2, y+r/2); gle::attrib(tc[0]); - gle::attribf(x+r, y+r/2); gle::attrib(tc[1]); - gle::attribf(x+r/2, y+r); gle::attrib(tc[3]); - gle::attribf(x+r, y+r); gle::attrib(tc[2]); - xtraverts += gle::end(); - } - if(!j) - { - r -= 10; - x += 5; - y += 5; - } - else if(j == 2) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - } - y += s+gap; - } - - pophudmatrix(true, false); - hudshader->set(); - } + if((texpaneltimer -= curtime)>0 && editmode) + { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + pushhudmatrix(); + hudmatrix.scale(h/1800.0f, h/1800.0f, 1); + flushhudmatrix(false); + SETSHADER(hudrgb); + + int y = 50, gap = 10; + + gle::defvertex(2); + gle::deftexcoord0(); + + loopi(7) + { + int s = (i == 3 ? 285 : 220), ti = curtexindex+i-3; + if(texmru.inrange(ti)) + { + VSlot &vslot = lookupvslot(texmru[ti]), *layer = NULL; + Slot &slot = *vslot.slot; + Texture *tex = slot.sts.empty() ? notexture : slot.sts[0].t, *glowtex = NULL, *layertex = NULL; + if(slot.texmask&(1<<TEX_GLOW)) + { + loopvj(slot.sts) if(slot.sts[j].type==TEX_GLOW) { glowtex = slot.sts[j].t; break; } + } + if(vslot.layer) + { + layer = &lookupvslot(vslot.layer); + layertex = layer->slot->sts.empty() ? notexture : layer->slot->sts[0].t; + } + float sx = min(1.0f, tex->xs/(float)tex->ys), sy = min(1.0f, tex->ys/(float)tex->xs); + int x = w*1800/h-s-50, r = s; + vec2 tc[4] = { vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1) }; + float xoff = vslot.offset.x, yoff = vslot.offset.y; + if(vslot.rotation) + { + const texrotation &r = texrotations[vslot.rotation]; + if(r.swapxy) { swap(xoff, yoff); loopk(4) swap(tc[k].x, tc[k].y); } + if(r.flipx) { xoff *= -1; loopk(4) tc[k].x *= -1; } + if(r.flipy) { yoff *= -1; loopk(4) tc[k].y *= -1; } + } + loopk(4) { tc[k].x = tc[k].x/sx - xoff/tex->xs; tc[k].y = tc[k].y/sy - yoff/tex->ys; } + glBindTexture(GL_TEXTURE_2D, tex->id); + loopj(glowtex ? 3 : 2) + { + if(j < 2) gle::color(vec(vslot.colorscale).mul(j), texpaneltimer/1000.0f); + else + { + glBindTexture(GL_TEXTURE_2D, glowtex->id); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + gle::color(vslot.glowcolor, texpaneltimer/1000.0f); + } + gle::begin(GL_TRIANGLE_STRIP); + gle::attribf(x, y); gle::attrib(tc[0]); + gle::attribf(x+r, y); gle::attrib(tc[1]); + gle::attribf(x, y+r); gle::attrib(tc[3]); + gle::attribf(x+r, y+r); gle::attrib(tc[2]); + xtraverts += gle::end(); + if(j==1 && layertex) + { + gle::color(layer->colorscale, texpaneltimer/1000.0f); + glBindTexture(GL_TEXTURE_2D, layertex->id); + gle::begin(GL_TRIANGLE_STRIP); + gle::attribf(x+r/2, y+r/2); gle::attrib(tc[0]); + gle::attribf(x+r, y+r/2); gle::attrib(tc[1]); + gle::attribf(x+r/2, y+r); gle::attrib(tc[3]); + gle::attribf(x+r, y+r); gle::attrib(tc[2]); + xtraverts += gle::end(); + } + if(!j) + { + r -= 10; + x += 5; + y += 5; + } + else if(j == 2) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + } + y += s+gap; + } + + pophudmatrix(true, false); + hudshader->set(); + } } |
