summaryrefslogtreecommitdiff
path: root/src/engine/octaedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/octaedit.cpp')
-rw-r--r--src/engine/octaedit.cpp4221
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();
+ }
}