#include "engine.h" struct QuadNode { int x, y, size; uint filled; QuadNode *child[4]; QuadNode(int x, int y, int size) : x(x), y(y), size(size), filled(0) { loopi(4) child[i] = 0; } void clear() { loopi(4) DELETEP(child[i]); } ~QuadNode() { clear(); } void insert(int mx, int my, int msize) { if(size == msize) { filled = 0xF; return; } int csize = size>>1, i = 0; if(mx >= x+csize) i |= 1; if(my >= y+csize) i |= 2; if(csize == msize) { filled |= (1 << i); return; } if(!child[i]) child[i] = new QuadNode(i&1 ? x+csize : x, i&2 ? y+csize : y, csize); child[i]->insert(mx, my, msize); loopj(4) if(child[j]) { if(child[j]->filled == 0xF) { DELETEP(child[j]); filled |= (1 << j); } } } void genmatsurf(ushort mat, uchar orient, uchar visible, int x, int y, int z, int size, materialsurface *&matbuf) { materialsurface &m = *matbuf++; m.material = mat; m.orient = orient; m.visible = visible; m.csize = size; m.rsize = size; int dim = dimension(orient); m.o[C[dim]] = x; m.o[R[dim]] = y; m.o[dim] = z; } void genmatsurfs(ushort mat, uchar orient, uchar flags, int z, materialsurface *&matbuf) { if(filled == 0xF) genmatsurf(mat, orient, flags, x, y, z, size, matbuf); else if(filled) { int csize = size>>1; loopi(4) if(filled & (1 << i)) genmatsurf(mat, orient, flags, i&1 ? x+csize : x, i&2 ? y+csize : y, z, csize, matbuf); } loopi(4) if(child[i]) child[i]->genmatsurfs(mat, orient, flags, z, matbuf); } }; static float wfwave; static const bvec4 matnormals[6] = { bvec4(0x80, 0, 0), bvec4(0x7F, 0, 0), bvec4(0, 0x80, 0), bvec4(0, 0x7F, 0), bvec4(0, 0, 0x80), bvec4(0, 0, 0x7F) }; static void renderwaterfall(const materialsurface &m, float offset) { if(gle::attribbuf.empty()) { gle::defvertex(); gle::defnormal(4, GL_BYTE); gle::begin(GL_QUADS); } float x = m.o.x, y = m.o.y, zmin = m.o.z, zmax = zmin; if(m.ends&1) zmin += -WATER_OFFSET-WATER_AMPLITUDE; if(m.ends&2) zmax += wfwave; int csize = m.csize, rsize = m.rsize; switch(m.orient) { #define GENFACEORIENT(orient, v0, v1, v2, v3) \ case orient: v0 v1 v2 v3 break; #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \ { \ gle::attribf(mx sx, my sy, mz sz); \ gle::attrib(matnormals[orient]); \ } GENFACEVERTSXY(x, x, y, y, zmin, zmax, /**/, + csize, /**/, + rsize, + offset, - offset) #undef GENFACEORIENT #undef GENFACEVERT } } static void drawmaterial(const materialsurface &m, float offset, const bvec4 &color) { if(gle::attribbuf.empty()) { gle::defvertex(); gle::defcolor(4, GL_UNSIGNED_BYTE); gle::begin(GL_QUADS); } float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize; switch(m.orient) { #define GENFACEORIENT(orient, v0, v1, v2, v3) \ case orient: v0 v1 v2 v3 break; #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \ { \ gle::attribf(mx sx, my sy, mz sz); \ gle::attrib(color); \ } GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset) #undef GENFACEORIENT #undef GENFACEVERT } } const struct material { const char *name; ushort id; } materials[] = { {"air", MAT_AIR}, {"water", MAT_WATER}, {"water1", MAT_WATER}, {"water2", MAT_WATER+1}, {"water3", MAT_WATER+2}, {"water4", MAT_WATER+3}, {"glass", MAT_GLASS}, {"glass1", MAT_GLASS}, {"glass2", MAT_GLASS+1}, {"glass3", MAT_GLASS+2}, {"glass4", MAT_GLASS+3}, {"lava", MAT_LAVA}, {"lava1", MAT_LAVA}, {"lava2", MAT_LAVA+1}, {"lava3", MAT_LAVA+2}, {"lava4", MAT_LAVA+3}, {"clip", MAT_CLIP}, {"noclip", MAT_NOCLIP}, {"gameclip", MAT_GAMECLIP}, {"death", MAT_DEATH}, {"alpha", MAT_ALPHA} }; int findmaterial(const char *name) { loopi(sizeof(materials)/sizeof(material)) { if(!strcmp(materials[i].name, name)) return materials[i].id; } return -1; } const char *findmaterialname(int mat) { loopi(sizeof(materials)/sizeof(materials[0])) if(materials[i].id == mat) return materials[i].name; return NULL; } const char *getmaterialdesc(int mat, const char *prefix) { static const ushort matmasks[] = { MATF_VOLUME|MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_ALPHA }; static string desc; desc[0] = '\0'; loopi(sizeof(matmasks)/sizeof(matmasks[0])) if(mat&matmasks[i]) { const char *matname = findmaterialname(mat&matmasks[i]); if(matname) { concatstring(desc, desc[0] ? ", " : prefix); concatstring(desc, matname); } } return desc; } int visiblematerial(const cube &c, int orient, const ivec &co, int size, ushort matmask) { ushort mat = c.material&matmask; switch(mat) { case MAT_AIR: break; case MAT_LAVA: case MAT_WATER: if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask)) return (orient != O_BOTTOM ? MATSURF_VISIBLE : MATSURF_EDIT_ONLY); break; case MAT_GLASS: if(visibleface(c, orient, co, size, MAT_GLASS, MAT_AIR, matmask)) return MATSURF_VISIBLE; break; default: if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask)) return MATSURF_EDIT_ONLY; break; } return MATSURF_NOT_VISIBLE; } void genmatsurfs(const cube &c, const ivec &co, int size, vector &matsurfs) { loopi(6) { static const ushort matmasks[] = { MATF_VOLUME|MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_ALPHA }; loopj(sizeof(matmasks)/sizeof(matmasks[0])) { int matmask = matmasks[j]; int vis = visiblematerial(c, i, co, size, matmask&~MATF_INDEX); if(vis != MATSURF_NOT_VISIBLE) { materialsurface m; m.material = c.material&matmask; m.orient = i; m.visible = vis; m.o = co; m.csize = m.rsize = size; if(dimcoord(i)) m.o[dimension(i)] += size; matsurfs.add(m); break; } } } } static inline bool mergematcmp(const materialsurface &x, const materialsurface &y) { int dim = dimension(x.orient), c = C[dim], r = R[dim]; if(x.o[r] + x.rsize < y.o[r] + y.rsize) return true; if(x.o[r] + x.rsize > y.o[r] + y.rsize) return false; return x.o[c] < y.o[c]; } static int mergematr(materialsurface *m, int sz, materialsurface &n) { int dim = dimension(n.orient), c = C[dim], r = R[dim]; for(int i = sz-1; i >= 0; --i) { if(m[i].o[r] + m[i].rsize < n.o[r]) break; if(m[i].o[r] + m[i].rsize == n.o[r] && m[i].o[c] == n.o[c] && m[i].csize == n.csize) { n.o[r] = m[i].o[r]; n.rsize += m[i].rsize; memmove(&m[i], &m[i+1], (sz - (i+1)) * sizeof(materialsurface)); return 1; } } return 0; } static int mergematc(materialsurface &m, materialsurface &n) { int dim = dimension(n.orient), c = C[dim], r = R[dim]; if(m.o[r] == n.o[r] && m.rsize == n.rsize && m.o[c] + m.csize == n.o[c]) { n.o[c] = m.o[c]; n.csize += m.csize; return 1; } return 0; } static int mergemat(materialsurface *m, int sz, materialsurface &n) { for(bool merged = false; sz; merged = true) { int rmerged = mergematr(m, sz, n); sz -= rmerged; if(!rmerged && merged) break; if(!sz) break; int cmerged = mergematc(m[sz-1], n); sz -= cmerged; if(!cmerged) break; } m[sz++] = n; return sz; } static int mergemats(materialsurface *m, int sz) { quicksort(m, sz, mergematcmp); int nsz = 0; loopi(sz) nsz = mergemat(m, nsz, m[i]); return nsz; } static inline bool optmatcmp(const materialsurface &x, const materialsurface &y) { if(x.material < y.material) return true; if(x.material > y.material) return false; if(x.orient > y.orient) return true; if(x.orient < y.orient) return false; int dim = dimension(x.orient); return x.o[dim] < y.o[dim]; } VARF(optmats, 0, 1, 1, allchanged()); int optimizematsurfs(materialsurface *matbuf, int matsurfs) { quicksort(matbuf, matsurfs, optmatcmp); if(!optmats) return matsurfs; materialsurface *cur = matbuf, *end = matbuf+matsurfs; while(cur < end) { materialsurface *start = cur++; int dim = dimension(start->orient); while(cur < end && cur->material == start->material && cur->orient == start->orient && cur->visible == start->visible && cur->o[dim] == start->o[dim]) ++cur; if(!isliquid(start->material&MATF_VOLUME) || start->orient != O_TOP || !vertwater) { if(start!=matbuf) memmove(matbuf, start, (cur-start)*sizeof(materialsurface)); matbuf += mergemats(matbuf, cur-start); } else if(cur-start>=4) { QuadNode vmats(0, 0, worldsize); loopi(cur-start) vmats.insert(start[i].o[C[dim]], start[i].o[R[dim]], start[i].csize); vmats.genmatsurfs(start->material, start->orient, start->visible, start->o[dim], matbuf); } else { if(start!=matbuf) memmove(matbuf, start, (cur-start)*sizeof(materialsurface)); matbuf += cur-start; } } return matsurfs - (end-matbuf); } struct waterinfo { materialsurface *m; double depth, area; }; void setupmaterials(int start, int len) { int hasmat = 0; vector water; unionfind uf; if(!len) len = valist.length(); for(int i = start; i < len; i++) { vtxarray *va = valist[i]; materialsurface *skip = NULL; loopj(va->matsurfs) { materialsurface &m = va->matbuf[j]; int matvol = m.material&MATF_VOLUME; if(matvol==MAT_WATER && m.orient==O_TOP) { m.index = water.length(); loopvk(water) { materialsurface &n = *water[k].m; if(m.material!=n.material || m.o.z!=n.o.z) continue; if(n.o.x+n.rsize==m.o.x || m.o.x+m.rsize==n.o.x) { if(n.o.y+n.csize>m.o.y && n.o.ym.o.x && n.o.xmaterial && m.orient == skip->orient && skip->skip < 0xFFFF) skip->skip++; else skip = &m; } } loopv(water) { int root = uf.find(i); if(i==root) continue; materialsurface &m = *water[i].m, &n = *water[root].m; if(m.light && (!m.light->attr1 || !n.light || (n.light->attr1 && m.light->attr1 > n.light->attr1))) n.light = m.light; water[root].depth += water[i].depth; water[root].area += water[i].area; } loopv(water) { int root = uf.find(i); water[i].m->light = water[root].m->light; water[i].m->depth = (short)(water[root].depth/water[root].area); } if(hasmat&(0xF< ymin && ymax > xmin) continue; int c = sortorigin[dim]; if(c > xmin && c < xmax) return sortedit; if(c > ymin && c < ymax) return !sortedit; xmin = abs(xmin - c); xmax = abs(xmax - c); ymin = abs(ymin - c); ymax = abs(ymax - c); if(max(xmin, xmax) <= min(ymin, ymax)) return sortedit; else if(max(ymin, ymax) <= min(xmin, xmax)) return !sortedit; } if(x.material < y.material) return sortedit; if(x.material > y.material) return !sortedit; return false; } void sortmaterials(vector &vismats) { sortorigin = ivec(camera1->o); if(reflecting) sortorigin.z = int(reflectz - (camera1->o.z - reflectz)); vec dir; vecfromyawpitch(camera1->yaw, reflecting ? -camera1->pitch : camera1->pitch, 1, 0, dir); loopi(3) { dir[i] = fabs(dir[i]); sortdim[i] = i; } if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]); if(dir[sortdim[1]] > dir[sortdim[0]]) swap(sortdim[1], sortdim[0]); if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]); for(vtxarray *va = reflecting ? reflectedva : visibleva; va; va = reflecting ? va->rnext : va->next) { if(!va->matsurfs || va->occluded >= OCCLUDE_BB) continue; if(reflecting || refracting>0 ? va->o.z+va->size <= reflectz : va->o.z >= reflectz) continue; loopi(va->matsurfs) { materialsurface &m = va->matbuf[i]; if(!editmode || !showmat || drawtex) { int matvol = m.material&MATF_VOLUME; if(matvol==MAT_WATER && (m.orient==O_TOP || (refracting<0 && reflectz>worldsize))) { i += m.skip; continue; } if(m.visible == MATSURF_EDIT_ONLY) { i += m.skip; continue; } if(glaring && matvol!=MAT_LAVA) { i += m.skip; continue; } } else if(glaring) continue; vismats.add(&m); } } sortedit = editmode && showmat && !drawtex; vismats.sort(vismatcmp); } void rendermatgrid(vector &vismats) { enablepolygonoffset(GL_POLYGON_OFFSET_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); int lastmat = -1; bvec4 color(0, 0, 0, 0); loopvrev(vismats) { materialsurface &m = *vismats[i]; if(m.material != lastmat) { switch(m.material&~MATF_INDEX) { case MAT_WATER: color = bvec4( 0, 0, 85, 255); break; // blue case MAT_CLIP: color = bvec4(85, 0, 0, 255); break; // red case MAT_GLASS: color = bvec4( 0, 85, 85, 255); break; // cyan case MAT_NOCLIP: color = bvec4( 0, 85, 0, 255); break; // green case MAT_LAVA: color = bvec4(85, 40, 0, 255); break; // orange case MAT_GAMECLIP: color = bvec4(85, 85, 0, 255); break; // yellow case MAT_DEATH: color = bvec4(40, 40, 40, 255); break; // black case MAT_ALPHA: color = bvec4(85, 0, 85, 255); break; // pink default: continue; } lastmat = m.material; } drawmaterial(m, -0.1f, color); } xtraverts += gle::end(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); disablepolygonoffset(GL_POLYGON_OFFSET_LINE); } #define GLASSVARS(name) \ bvec name##color(0x20, 0x80, 0xC0); \ HVARFR(name##colour, 0, 0x2080C0, 0xFFFFFF, \ { \ if(!name##colour) name##colour = 0x2080C0; \ name##color = bvec((name##colour>>16)&0xFF, (name##colour>>8)&0xFF, name##colour&0xFF); \ }); GLASSVARS(glass) GLASSVARS(glass2) GLASSVARS(glass3) GLASSVARS(glass4) GETMATIDXVAR(glass, colour, int) GETMATIDXVAR(glass, color, const bvec &) VARP(glassenv, 0, 1, 1); static void drawglass(const materialsurface &m, float offset) { if(gle::attribbuf.empty()) { gle::defvertex(); gle::defnormal(4, GL_BYTE); gle::begin(GL_QUADS); } float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize; switch(m.orient) { #define GENFACEORIENT(orient, v0, v1, v2, v3) \ case orient: v0 v1 v2 v3 break; #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \ { \ gle::attribf(mx sx, my sy, mz sz); \ gle::attrib(matnormals[orient]); \ } GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset) #undef GENFACEORIENT #undef GENFACEVERT } } VARFP(waterfallenv, 0, 1, 1, preloadwatershaders()); static inline void changematerial(int mat, int orient) { switch(mat&~MATF_INDEX) { case MAT_LAVA: if(orient==O_TOP) flushlava(); else xtraverts += gle::end(); break; default: xtraverts += gle::end(); break; } } void rendermaterials() { vector vismats; sortmaterials(vismats); if(vismats.empty()) return; glDisable(GL_CULL_FACE); MSlot *mslot = NULL; int lastorient = -1, lastmat = -1, usedwaterfall = -1; bool depth = true, blended = false; ushort envmapped = EMID_NONE; GLOBALPARAM(camera, camera1->o); int lastfogtype = 1; if(editmode && showmat && !drawtex) { glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glEnable(GL_BLEND); blended = true; foggednotextureshader->set(); zerofogcolor(); lastfogtype = 0; bvec4 color(0, 0, 0, 0); loopv(vismats) { const materialsurface &m = *vismats[i]; if(lastmat!=m.material) { switch(m.material&~MATF_INDEX) { case MAT_WATER: color = bvec4(255, 128, 0, 255); break; // blue case MAT_CLIP: color = bvec4( 0, 255, 255, 255); break; // red case MAT_GLASS: color = bvec4(255, 0, 0, 255); break; // cyan case MAT_NOCLIP: color = bvec4(255, 0, 255, 255); break; // green case MAT_LAVA: color = bvec4( 0, 128, 255, 255); break; // orange case MAT_GAMECLIP: color = bvec4( 0, 0, 255, 255); break; // yellow case MAT_DEATH: color = bvec4(192, 192, 192, 255); break; // black case MAT_ALPHA: color = bvec4( 0, 255, 0, 255); break; // pink default: continue; } lastmat = m.material; } drawmaterial(m, -0.1f, color); } xtraverts += gle::end(); } else loopv(vismats) { const materialsurface &m = *vismats[i]; int matvol = m.material&~MATF_INDEX; if(lastmat!=m.material || lastorient!=m.orient || (matvol==MAT_GLASS && envmapped && m.envmap != envmapped)) { int fogtype = lastfogtype; switch(matvol) { case MAT_WATER: if(m.orient == O_TOP) continue; if(lastmat == m.material) break; mslot = &lookupmaterialslot(m.material, false); if(!mslot->loaded || !mslot->sts.inrange(1)) continue; else { changematerial(lastmat, lastorient); glBindTexture(GL_TEXTURE_2D, mslot->sts[1].t->id); bvec wfcol = getwaterfallcolor(m.material); if(wfcol.iszero()) wfcol = getwatercolor(m.material); gle::color(wfcol, 192); int wfog = getwaterfog(m.material); if(!wfog && !waterfallenv) { foggednotextureshader->set(); fogtype = 1; if(blended) { glDisable(GL_BLEND); blended = false; } if(!depth) { glDepthMask(GL_TRUE); depth = true; } } else if((!waterfallrefract || reflecting || refracting) && !waterfallenv) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); SETSHADER(waterfall); fogtype = 0; if(!blended) { glEnable(GL_BLEND); blended = true; } if(depth) { glDepthMask(GL_FALSE); depth = false; } } else { fogtype = 1; if(waterfallrefract && wfog && !reflecting && !refracting) { if(waterfallenv) SETSHADER(waterfallenvrefract); else SETSHADER(waterfallrefract); if(blended) { glDisable(GL_BLEND); blended = false; } if(!depth) { glDepthMask(GL_TRUE); depth = true; } } else { SETSHADER(waterfallenv); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if(wfog) { if(!blended) { glEnable(GL_BLEND); blended = true; } if(depth) { glDepthMask(GL_FALSE); depth = false; } } else { if(blended) { glDisable(GL_BLEND); blended = false; } if(!depth) { glDepthMask(GL_TRUE); depth = true; } } } if(usedwaterfall != m.material) { Texture *dudv = mslot->sts.inrange(5) ? mslot->sts[5].t : notexture; float scale = TEX_SCALE/(dudv->ys*mslot->scale); LOCALPARAMF(dudvoffset, 0, scale*16*lastmillis/1000.0f); glActiveTexture_(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mslot->sts.inrange(4) ? mslot->sts[4].t->id : notexture->id); glActiveTexture_(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, mslot->sts.inrange(5) ? mslot->sts[5].t->id : notexture->id); if(waterfallenv) { glActiveTexture_(GL_TEXTURE3); glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(*mslot)); } if(waterfallrefract && (!reflecting || !refracting) && usedwaterfall < 0) { glActiveTexture_(GL_TEXTURE4); extern void setupwaterfallrefract(); setupwaterfallrefract(); } glActiveTexture_(GL_TEXTURE0); usedwaterfall = m.material; } } float angle = fmod(float(lastmillis/600.0f/(2*M_PI)), 1.0f), s = angle - int(angle) - 0.5f; s *= 8 - fabs(s)*16; wfwave = vertwater ? WATER_AMPLITUDE*s-WATER_OFFSET : -WATER_OFFSET; float scroll = 16.0f*lastmillis/1000.0f; float xscale = TEX_SCALE/(mslot->sts[1].t->xs*mslot->scale); float yscale = -TEX_SCALE/(mslot->sts[1].t->ys*mslot->scale); LOCALPARAMF(waterfalltexgen, xscale, yscale, 0.0f, scroll); } break; case MAT_LAVA: if(lastmat==m.material && lastorient!=O_TOP && m.orient!=O_TOP) break; mslot = &lookupmaterialslot(m.material, false); if(!mslot->loaded) continue; else { int subslot = m.orient==O_TOP ? 0 : 1; if(!mslot->sts.inrange(subslot)) continue; changematerial(lastmat, lastorient); glBindTexture(GL_TEXTURE_2D, mslot->sts[subslot].t->id); } if(lastmat!=m.material) { if(!depth) { glDepthMask(GL_TRUE); depth = true; } if(blended) { glDisable(GL_BLEND); blended = false; } float t = lastmillis/2000.0f; t -= floor(t); t = 1.0f - 2*fabs(t-0.5f); extern int glare; if(glare) t = 0.625f + 0.075f*t; else t = 0.5f + 0.5f*t; gle::colorf(t, t, t); if(glaring) SETSHADER(lavaglare); else SETSHADER(lava); fogtype = 1; } if(m.orient!=O_TOP) { float angle = fmod(float(lastmillis/2000.0f/(2*M_PI)), 1.0f), s = angle - int(angle) - 0.5f; s *= 8 - fabs(s)*16; wfwave = vertwater ? WATER_AMPLITUDE*s-WATER_OFFSET : -WATER_OFFSET; float scroll = 16.0f*lastmillis/3000.0f; float xscale = TEX_SCALE/(mslot->sts[1].t->xs*mslot->scale); float yscale = -TEX_SCALE/(mslot->sts[1].t->ys*mslot->scale); LOCALPARAMF(lavatexgen, xscale, yscale, 0.0f, scroll); } else setuplava(mslot->sts[0].t, mslot->scale); break; case MAT_GLASS: if((m.envmap==EMID_NONE || !glassenv || envmapped==m.envmap) && lastmat==m.material) break; changematerial(lastmat, lastorient); if(m.envmap!=EMID_NONE && glassenv && envmapped!=m.envmap) { glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(m.envmap)); envmapped = m.envmap; } if(lastmat!=m.material) { if(!blended) { glEnable(GL_BLEND); blended = true; } if(depth) { glDepthMask(GL_FALSE); depth = false; } const bvec &gcol = getglasscolor(m.material); if(m.envmap!=EMID_NONE && glassenv) { glBlendFunc(GL_ONE, GL_SRC_ALPHA); gle::color(gcol); SETSHADER(glass); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gle::color(gcol, 40); foggednotextureshader->set(); fogtype = 1; } } break; default: continue; } lastmat = m.material; lastorient = m.orient; if(fogtype!=lastfogtype) { if(fogtype) resetfogcolor(); else zerofogcolor(); lastfogtype = fogtype; } } switch(matvol) { case MAT_WATER: renderwaterfall(m, 0.1f); break; case MAT_LAVA: if(m.orient==O_TOP) renderlava(m); else renderwaterfall(m, 0.1f); break; case MAT_GLASS: drawglass(m, 0.1f); break; } } if(lastorient >= 0) changematerial(lastmat, lastorient); if(!depth) glDepthMask(GL_TRUE); if(blended) glDisable(GL_BLEND); if(!lastfogtype) resetfogcolor(); extern int wireframe; if(editmode && showmat && !drawtex && !wireframe) { foggednotextureshader->set(); rendermatgrid(vismats); } glEnable(GL_CULL_FACE); }