diff --git a/source/src/protos.h b/source/src/protos.h index 9f5eb278..e940e9ef 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -621,6 +621,8 @@ extern int findentity(int type, int index = 0); extern int findentity(int type, int index, uchar attr2); extern void newentity(int index, int x, int y, int z, const char *what, float v1, float v2, float v3, float v4); extern void mapmrproper(bool manual); +extern void clearworldvisibility(); +extern void calcworldvisibility(); extern vector deleted_ents; // worldlight diff --git a/source/src/world.cpp b/source/src/world.cpp index 2c8655a2..c625a108 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -756,14 +756,93 @@ COMMANDF(calcmipstats, "", () conoutf("current mips: %d / %d / %d / %d / %d / %d / %d", st[0], st[1], st[2], st[3], st[4], st[5], st[6]); }); -#define INVISWTEX (1<<0) -#define INVISUTEX (1<<1) -#define INVISIBLE (1<<2) +void clearworldvisibility() +{ + sqr *s = world; + loopirev(cubicsize) (s++)->visible = 0; +} + +void calcworldvisibility() +{ + sqr *s, *o[4], *r; + + // default to invisible, we'll mark all visible afterwards + r = world; loopirev(ssize * ssize) (r++)->visible = INVISUTEX|INVISWTEX; + + // check visibility of wall & upper wall in mip 0 + for(int y = 0; y < ssize; y++) for(int x = 0; x < ssize; x++) + { + s = S(x,y); uchar &rs = s->visible; + if(x < 1 || x > ssize - 2 || y < 1 || y > ssize - 2) continue; // we need 1 cube safety-space - all outside is invisible anyway + o[0] = s - ssize; + o[1] = s + ssize; + o[2] = s + 1; + o[3] = s - 1; + loopi(4) if(!SOLID(o[i])) + { + if(SOLID(s) || s->floor > o[i]->floor || (o[i]->type == FHF && (s->type != FHF || s->floor != o[i]->floor))) rs &= ~INVISWTEX; // wall texture visible + if(!SOLID(s) && (s->ceil < o[i]->ceil || (o[i]->type == CHF && (s->type != CHF || s->ceil != o[i]->ceil)))) rs &= ~INVISUTEX; // upper wall texture visible + } + if(SOLID(s) && SOLID(o[0]) && SOLID(o[1]) && SOLID(o[2]) && SOLID(o[3])) rs |= INVISIBLE; + } + + // corners are rendered at the highest possible mip - make sure, the right helper cubes are marked visible (including actually hidden ones) + // (this is a lot of effort, but there's no easier way... savemap's toptimize() does it wrong, for example + for(int mip = SMALLEST_FACTOR; mip > 0; mip--) + { + int mfactor = sfactor - mip, bs = 1 << mfactor; + for(int y = 1; y < bs - 1; y++) for(int x = 1; x < bs - 1; x++) + { + s = SWS(wmip[mip], x, y, mfactor); + if(s->type == CORNER && (mip == SMALLEST_FACTOR || SWS(wmip[mip + 1], x / 2, y / 2, mfactor - 1)->type != CORNER)) + { // highest corner mip (this one is rendered) - mark helper cubes + sqr *z = SWS(s,-1,0,mfactor); + sqr *t = SWS(s,1,0,mfactor); + sqr *v = SWS(s,0,1,mfactor); + sqr *w = SWS(s,0,-1,mfactor); + if(SOLID(z) || SOLID(t)) + { + if(SOLID(w)) S(x << mip, (y - 1) << mip)->visible &= ~(INVISWTEX|INVISIBLE); + else if(SOLID(v)) S(x << mip, (y + 1) << mip)->visible &= ~(INVISWTEX|INVISIBLE); + } + } + } + } + // propagate visibility and visible textures into higher mips + for(int mip = 0; mip < SMALLEST_FACTOR; mip++) + { + int mfactor = sfactor - mip, bs = 1 << mfactor; + for(int y = 0; y < bs; y++) for(int x = 0; x < bs; x++) + { + s = SWS(wmip[mip], x, y, mfactor); + r = SWS(wmip[mip + 1], x / 2, y / 2, mfactor - 1); + uchar &rs = s->visible, &rr = r->visible; + if(!((x | y) & 1)) rr = rs; + else rr &= rs; + if(!(rs & INVISWTEX)) r->wtex = s->wtex; + if(!(rs & INVISUTEX)) r->utex = s->utex; + } + } + + // corners are rendered at the highest possible mip - make sure, the right cubes of the lot is marked visible (including actually hidden ones) + for(int mip = SMALLEST_FACTOR; mip > 0; mip--) + { + int mfactor = sfactor - mip, bs = 1 << mfactor; + for(int y = 1; y < bs - 1; y++) for(int x = 1; x < bs - 1; x++) + { + s = SWS(wmip[mip], x, y, mfactor); + if(s->type == CORNER && (mip == SMALLEST_FACTOR || SWS(wmip[mip + 1], x / 2, y / 2, mfactor - 1)->type != CORNER)) + { // highest mip - mark the important cube like the highest mip + S(x << mip, y << mip)->visible = s->visible; + } + } + } // visibility flags complete ;) +} void mapmrproper(bool manual) { - int sta[SMALLEST_FACTOR + 1], stb[SMALLEST_FACTOR + 1], stc[SMALLEST_FACTOR + 1]; - sqr *s, *r, *o[4]; + int sta[SMALLEST_FACTOR + 1] = { 0 }, stb[SMALLEST_FACTOR + 1] = { 0 }, stc[SMALLEST_FACTOR + 1] = { 0 }; + sqr *s, *r; block b = { 0, 0, ssize, ssize }; if(manual) { @@ -799,83 +878,12 @@ void mapmrproper(bool manual) memcpy(world, worldbackup, ssize*ssize*sizeof(sqr)); delete[] worldbackup; - // default to invisible, we'll mark all visible afterwards - r = world; loopirev(ssize * ssize) (r++)->reserved[0] = INVISUTEX|INVISWTEX; - - // check visibility of wall & upper wall in mip 0 - for(int y = 0; y < ssize; y++) for(int x = 0; x < ssize; x++) - { - s = S(x,y); uchar &rs = s->reserved[0]; - if(x < 1 || x > ssize - 2 || y < 1 || y > ssize - 2) continue; // we need 1 cube safety-space - all outside is invisible anyway - o[0] = s - ssize; - o[1] = s + ssize; - o[2] = s + 1; - o[3] = s - 1; - loopi(4) if(!SOLID(o[i])) - { - if(SOLID(s) || s->floor > o[i]->floor || (o[i]->type == FHF && (s->type != FHF || s->floor != o[i]->floor))) rs &= ~INVISWTEX; // wall texture visible - if(!SOLID(s) && (s->ceil < o[i]->ceil || (o[i]->type == CHF && (s->type != CHF || s->ceil != o[i]->ceil)))) rs &= ~INVISUTEX; // upper wall texture visible - } - if(SOLID(s) && SOLID(o[0]) && SOLID(o[1]) && SOLID(o[2]) && SOLID(o[3])) rs |= INVISIBLE; - } - - // corners are rendered at the highest possible mip - make sure, the right helper cubes are marked visible (including actually hidden ones) - // (this is a lot of effort, but there's no easier way... savemap's toptimize() does it wrong, for example - for(int mip = SMALLEST_FACTOR; mip > 0; mip--) - { - int mfactor = sfactor - mip, bs = 1 << mfactor; - for(int y = 1; y < bs - 1; y++) for(int x = 1; x < bs - 1; x++) - { - s = SWS(wmip[mip], x, y, mfactor); - if(s->type == CORNER && (mip == SMALLEST_FACTOR || SWS(wmip[mip + 1], x / 2, y / 2, mfactor - 1)->type != CORNER)) - { // highest corner mip (this one is rendered) - mark helper cubes - sqr *z = SWS(s,-1,0,mfactor); - sqr *t = SWS(s,1,0,mfactor); - sqr *v = SWS(s,0,1,mfactor); - sqr *w = SWS(s,0,-1,mfactor); - if(SOLID(z) || SOLID(t)) - { - if(SOLID(w)) S(x << mip, (y - 1) << mip)->reserved[0] &= ~(INVISWTEX|INVISIBLE); - else if(SOLID(v)) S(x << mip, (y + 1) << mip)->reserved[0] &= ~(INVISWTEX|INVISIBLE); - } - } - } - } - - // propagate visibility and visible textures into higher mips - for(int mip = 0; mip < SMALLEST_FACTOR; mip++) - { - int mfactor = sfactor - mip, bs = 1 << mfactor; - for(int y = 0; y < bs; y++) for(int x = 0; x < bs; x++) - { - s = SWS(wmip[mip], x, y, mfactor); - r = SWS(wmip[mip + 1], x / 2, y / 2, mfactor - 1); - uchar &rs = s->reserved[0], &rr = r->reserved[0]; - if(!((x | y) & 1)) rr = rs; - else rr &= rs; - if(!(rs & INVISWTEX)) r->wtex = s->wtex; - if(!(rs & INVISUTEX)) r->utex = s->utex; - } - } - - // corners are rendered at the highest possible mip - make sure, the right cubes of the lot is marked visible (including actually hidden ones) - for(int mip = SMALLEST_FACTOR; mip > 0; mip--) - { - int mfactor = sfactor - mip, bs = 1 << mfactor; - for(int y = 1; y < bs - 1; y++) for(int x = 1; x < bs - 1; x++) - { - s = SWS(wmip[mip], x, y, mfactor); - if(s->type == CORNER && (mip == SMALLEST_FACTOR || SWS(wmip[mip + 1], x / 2, y / 2, mfactor - 1)->type != CORNER)) - { // highest mip - mark the important cube like the highest mip - S(x << mip, y << mip)->reserved[0] = s->reserved[0]; - } - } - } // visibility flags complete ;) - //r = world; loopirev(ssize * ssize) { r->tag = (r->tag & 0xc0) + r->reserved[0]; r++; } // easy debugging + // calculate cube visibility + calcworldvisibility(); // optimize utex & wtex according to mips & visibility - #define domip0(b) for(int yy = y << mip; yy < (y + 1) << mip; yy++) for(int xx = x << mip; xx < (x + 1) << mip; xx++) { s = S(xx,yy); uchar &rs = s->reserved[0]; b ; } - for(int mip = SMALLEST_FACTOR; mip > 0; mip--) + #define domip0(b) for(int yy = y << mip; yy < (y + 1) << mip; yy++) for(int xx = x << mip; xx < (x + 1) << mip; xx++) { s = S(xx,yy); uchar &rs = s->visible; b ; } + for(int mip = 2; mip > 0; mip--) { int mfactor = sfactor - mip, bs = 1 << mfactor; for(int y = 0; y < bs; y++) for(int x = 0; x < bs; x++) @@ -884,12 +892,12 @@ void mapmrproper(bool manual) if(mip > 1) loopi(4) { s = SWS(wmip[mip - 1], x * 2 + (i & 1), y * 2 + i / 2, mfactor + 1); - uchar &rs = s->reserved[0]; + uchar &rs = s->visible; if(rs & INVISWTEX) s->wtex = r->wtex; if(rs & INVISUTEX) s->utex = r->utex; } if(r->defer) continue; - if(r->reserved[0] & INVISIBLE) + if(r->visible & INVISIBLE) { domip0(rs &= INVISIBLE;); continue; // do not touch hidden solid blocks... for some reason it messes up filesize @@ -914,7 +922,7 @@ void mapmrproper(bool manual) } } - loopirev(ssize * ssize) world[i].reserved[0] = 0; // cleanup + clearworldvisibility(); // cleanup // recalc everything with the optimized data calclight(); diff --git a/source/src/world.h b/source/src/world.h index 249c6ad1..ce779caa 100644 --- a/source/src/world.h +++ b/source/src/world.h @@ -20,7 +20,8 @@ struct sqr char occluded; // true when occluded uchar utex; // upper wall tex id uchar tag; // used by triggers - uchar reserved[2]; + uchar visible; // temporarily used to flag the visibility of a cube (INVISWTEX, INVISUTEX, INVISIBLE) + uchar reserved; }; struct servsqr // server variant of sqr @@ -47,6 +48,13 @@ enum // stuff encoded in sqr.tag }; #define TAGANYCLIP (TAGCLIP|TAGPLCLIP) +enum +{ + INVISWTEX = 1<<0, + INVISUTEX = 1<<1, + INVISIBLE = 1<<2 +}; + enum { MHF_AUTOMAPCONFIG = 1<<0 }; #define MAPVERSION 10 // default map format version to be written (bump if map format changes, see worldio.cpp)