diff --git a/src/engine/render/grass.cpp b/src/engine/render/grass.cpp index 41dc1120a..0be32d706 100644 --- a/src/engine/render/grass.cpp +++ b/src/engine/render/grass.cpp @@ -273,43 +273,6 @@ namespace //internal functionality not seen by other files } } - // generates grass geometry for a given vertex array - void gengrassquads(vtxarray *va) - { - for(int i = 0; i < va->grasstris.length(); i++) - { - grasstri &g = va->grasstris[i]; - if(view.isfoggedsphere(g.radius, g.center)) - { - continue; - } - float dist = g.center.dist(camera1->o); - if(dist - g.radius > grassdist) - { - continue; - } - Slot &s = *lookupvslot(g.texture, false).slot; - if(!s.grasstex) - { - if(!s.grass) - { - continue; - } - s.grasstex = textureload(s.grass, 2); - } - grassgroup *group = nullptr; - for(int i = 0; i < numgrasswedges; ++i) - { - grasswedge &w = grasswedges[i]; - if(w.bound1.dist(g.center) > g.radius || w.bound2.dist(g.center) > g.radius) - { - continue; - } - gengrassquads(group, w, g, s.grasstex); - } - } - } - Shader *grassshader = nullptr; void cleargrassshaders() @@ -333,6 +296,43 @@ namespace //internal functionality not seen by other files /* externally relevant functions */ /////////////////////////////////// +// generates grass geometry for a given vertex array +void vtxarray::gengrassquads() +{ + for(int i = 0; i < grasstris.length(); i++) + { + grasstri &g = grasstris[i]; + if(view.isfoggedsphere(g.radius, g.center)) + { + continue; + } + float dist = g.center.dist(camera1->o); + if(dist - g.radius > grassdist) + { + continue; + } + Slot &s = *lookupvslot(g.texture, false).slot; + if(!s.grasstex) + { + if(!s.grass) + { + continue; + } + s.grasstex = textureload(s.grass, 2); + } + grassgroup *group = nullptr; + for(int i = 0; i < numgrasswedges; ++i) + { + grasswedge &w = grasswedges[i]; + if(w.bound1.dist(g.center) > g.radius || w.bound2.dist(g.center) > g.radius) + { + continue; + } + ::gengrassquads(group, w, g, s.grasstex); //we want the free function, so need :: + } + } +} + void generategrass() { if(!grass || !grassdist) @@ -367,7 +367,7 @@ void generategrass() { continue; } - gengrassquads(va); + va->gengrassquads(); } if(grassgroups.empty()) diff --git a/src/engine/render/octarender.cpp b/src/engine/render/octarender.cpp index d02e0b133..c65c35481 100644 --- a/src/engine/render/octarender.cpp +++ b/src/engine/render/octarender.cpp @@ -40,341 +40,241 @@ std::vector tjoints; VARFP(filltjoints, 0, 1, 1, rootworld.allchanged()); //eliminate "sparklies" by filling in geom t-joints -/* internally relevant functionality */ -/////////////////////////////////////// - -namespace +struct vboinfo { - struct vboinfo - { - int uses; - uchar *data; - }; + int uses; + uchar *data; +}; - hashtable vbos; +hashtable vbos; - VARFN(vbosize, maxvbosize, 0, 1<<14, 1<<16, rootworld.allchanged()); +VARFN(vbosize, maxvbosize, 0, 1<<14, 1<<16, rootworld.allchanged()); - //vbo (vertex buffer object) enum is local to this file - enum +//vbo (vertex buffer object) enum is local to this file +enum +{ + VBO_VBuf = 0, + VBO_EBuf, + VBO_SkyBuf, + VBO_DecalBuf, + VBO_NumVBOs +}; + +vector vbodata[VBO_NumVBOs]; +vector vbovas[VBO_NumVBOs]; +int vbosize[VBO_NumVBOs]; + +void destroyvbo(GLuint vbo) +{ + vboinfo *exists = vbos.access(vbo); + if(!exists) { - VBO_VBuf = 0, - VBO_EBuf, - VBO_SkyBuf, - VBO_DecalBuf, - VBO_NumVBOs - }; - - vector vbodata[VBO_NumVBOs]; - vector vbovas[VBO_NumVBOs]; - int vbosize[VBO_NumVBOs]; + return; + } + vboinfo &vbi = *exists; + if(vbi.uses <= 0) + { + return; + } + vbi.uses--; + if(!vbi.uses) + { + glDeleteBuffers_(1, &vbo); + if(vbi.data) + { + delete[] vbi.data; + } + vbos.remove(vbo); + } +} - void destroyvbo(GLuint vbo) +//vtxarray function for handling private vtxarray members +void vtxarray::vavbo(GLuint vbo, int type, uchar * data) +{ + switch(type) { - vboinfo *exists = vbos.access(vbo); - if(!exists) + case VBO_VBuf: { - return; + vbuf = vbo; + vdata = reinterpret_cast(data); + break; } - vboinfo &vbi = *exists; - if(vbi.uses <= 0) + case VBO_EBuf: { - return; + ebuf = vbo; + edata = reinterpret_cast(data); + break; } - vbi.uses--; - if(!vbi.uses) + case VBO_SkyBuf: { - glDeleteBuffers_(1, &vbo); - if(vbi.data) - { - delete[] vbi.data; - } - vbos.remove(vbo); + skybuf = vbo; + skydata = reinterpret_cast(data); + break; + } + case VBO_DecalBuf: + { + decalbuf = vbo; + decaldata = reinterpret_cast(data); + break; } } +} +//sets up vbos (vertex buffer objects) for the pointer-to-array-of-vtxarray **vas +//by setting up each vertex array's vbuf and vdata +void genvbo(int type, void *buf, int len, vtxarray **vas, int numva) +{ + gle::disable(); - //sets up vbos (vertex buffer objects) for the pointer-to-array-of-vtxarray **vas - //by setting up each vertex array's vbuf and vdata - void genvbo(int type, void *buf, int len, vtxarray **vas, int numva) - { - gle::disable(); - - GLuint vbo; - glGenBuffers_(1, &vbo); - GLenum target = type==VBO_VBuf ? GL_ARRAY_BUFFER : GL_ELEMENT_ARRAY_BUFFER; - glBindBuffer_(target, vbo); - glBufferData_(target, len, buf, GL_STATIC_DRAW); - glBindBuffer_(target, 0); + GLuint vbo; + glGenBuffers_(1, &vbo); + GLenum target = type==VBO_VBuf ? GL_ARRAY_BUFFER : GL_ELEMENT_ARRAY_BUFFER; + glBindBuffer_(target, vbo); + glBufferData_(target, len, buf, GL_STATIC_DRAW); + glBindBuffer_(target, 0); - vboinfo &vbi = vbos[vbo]; - vbi.uses = numva; - vbi.data = new uchar[len]; - memcpy(vbi.data, buf, len); + vboinfo &vbi = vbos[vbo]; + vbi.uses = numva; + vbi.data = new uchar[len]; + memcpy(vbi.data, buf, len); - for(int i = 0; i < numva; ++i) - { - vtxarray *va = vas[i]; - switch(type) - { - case VBO_VBuf: - { - va->vbuf = vbo; - va->vdata = reinterpret_cast(vbi.data); - break; - } - case VBO_EBuf: - { - va->ebuf = vbo; - va->edata = reinterpret_cast(vbi.data); - break; - } - case VBO_SkyBuf: - { - va->skybuf = vbo; - va->skydata = reinterpret_cast(vbi.data); - break; - } - case VBO_DecalBuf: - { - va->decalbuf = vbo; - va->decaldata = reinterpret_cast(vbi.data); - break; - } - } - } + for(int i = 0; i < numva; ++i) + { + vtxarray *va = vas[i]; + va->vavbo(vbo, type, vbi.data); } +} - void flushvbo(int type = -1) +void flushvbo(int type = -1) +{ + if(type < 0) { - if(type < 0) - { - for(int i = 0; i < VBO_NumVBOs; ++i) - { - flushvbo(i); - } - return; - } - - vector &data = vbodata[type]; - if(data.empty()) + for(int i = 0; i < VBO_NumVBOs; ++i) { - return; + flushvbo(i); } - vector &vas = vbovas[type]; - genvbo(type, data.getbuf(), data.length(), vas.getbuf(), vas.length()); - data.setsize(0); - vas.setsize(0); - vbosize[type] = 0; + return; } - uchar *addvbo(vtxarray *va, int type, int numelems, int elemsize) + vector &data = vbodata[type]; + if(data.empty()) { - switch(type) - { - case VBO_VBuf: - { - va->voffset = vbosize[type]; - break; - } - case VBO_EBuf: - { - va->eoffset = vbosize[type]; - break; - } - case VBO_SkyBuf: - { - va->skyoffset = vbosize[type]; - break; - } - case VBO_DecalBuf: - { - va->decaloffset = vbosize[type]; - break; - } - } - vbosize[type] += numelems; - vector &data = vbodata[type]; - vector &vas = vbovas[type]; - vas.add(va); - int len = numelems*elemsize; - uchar *buf = data.reserve(len).buf; - data.advance(len); - return buf; + return; } + vector &vas = vbovas[type]; + genvbo(type, data.getbuf(), data.length(), vas.getbuf(), vas.length()); + data.setsize(0); + vas.setsize(0); + vbosize[type] = 0; +} - class verthash - { - public: - std::vector verts; +class verthash +{ + public: + std::vector verts; - verthash() { clearverts(); } + verthash() { clearverts(); } - int addvert(const vertex &v) + int addvert(const vertex &v) + { + uint h = hthash(v.pos)&(hashsize-1); + for(int i = table[h]; i>=0; i = chain[i]) { - uint h = hthash(v.pos)&(hashsize-1); - for(int i = table[h]; i>=0; i = chain[i]) - { - const vertex &c = verts[i]; - if(c.pos==v.pos && c.tc==v.tc && c.norm==v.norm && c.tangent==v.tangent) - { - return i; - } - } - if(verts.size() >= USHRT_MAX) + const vertex &c = verts[i]; + if(c.pos==v.pos && c.tc==v.tc && c.norm==v.norm && c.tangent==v.tangent) { - return -1; - } - verts.push_back(v); - chain.emplace_back(table[h]); - return table[h] = verts.size()-1; - } - - void clearverts() - { - memset(table, -1, sizeof(table)); - chain.clear(); - verts.clear(); + return i; + } } - private: - static const int hashsize = 1<<13; - int table[hashsize]; - - std::vector chain; - int addvert(const vec &pos, const vec &tc = vec(0, 0, 0), const bvec &norm = bvec(128, 128, 128), const vec4 &tangent = vec4(128, 128, 128, 128)) + if(verts.size() >= USHRT_MAX) { - vertex vtx; - vtx.pos = pos; - vtx.tc = tc; - vtx.norm = norm; - vtx.tangent = tangent; - return addvert(vtx); + return -1; } - }; - - //alpha enum local to this file - enum - { - Alpha_None = 0, - Alpha_Back, - Alpha_Front, - Alpha_Refract - }; - - class sortkey - { - public: - ushort tex; - uchar orient, layer, alpha; - - sortkey() {} - sortkey(ushort tex, uchar orient, uchar layer = BlendLayer_Top, uchar alpha = Alpha_None) - : tex(tex), orient(orient), layer(layer), alpha(alpha) - {} + verts.push_back(v); + chain.emplace_back(table[h]); + return table[h] = verts.size()-1; + } - bool operator==(const sortkey &o) const - { - return tex==o.tex && orient==o.orient && layer==o.layer && alpha==o.alpha; - } + void clearverts() + { + memset(table, -1, sizeof(table)); + chain.clear(); + verts.clear(); + } + private: + static const int hashsize = 1<<13; + int table[hashsize]; - static bool sort(const sortkey &x, const sortkey &y) - { - if(x.alpha < y.alpha) - { - return true; - } - if(x.alpha > y.alpha) - { - return false; - } - if(x.layer < y.layer) - { - return true; - } - if(x.layer > y.layer) - { - return false; - } - if(x.tex == y.tex) - { - if(x.orient < y.orient) - { - return true; - } - if(x.orient > y.orient) - { - return false; - } - return false; - } - VSlot &xs = lookupvslot(x.tex, false), - &ys = lookupvslot(y.tex, false); - if(xs.slot->shader < ys.slot->shader) - { - return true; - } - if(xs.slot->shader > ys.slot->shader) - { - return false; - } - if(xs.slot->params.length() < ys.slot->params.length()) - { - return true; - } - if(xs.slot->params.length() > ys.slot->params.length()) - { - return false; - } - if(x.tex < y.tex) - { - return true; - } - else - { - return false; - } - } - }; + std::vector chain; - inline bool htcmp(const sortkey &x, const sortkey &y) - { - return x == y; - } + int addvert(const vec &pos, const vec &tc = vec(0, 0, 0), const bvec &norm = bvec(128, 128, 128), const vec4 &tangent = vec4(128, 128, 128, 128)) + { + vertex vtx; + vtx.pos = pos; + vtx.tc = tc; + vtx.norm = norm; + vtx.tangent = tangent; + return addvert(vtx); + } +}; - inline uint hthash(const sortkey &k) - { - return k.tex; - } +//alpha enum local to this file +enum +{ + Alpha_None = 0, + Alpha_Back, + Alpha_Front, + Alpha_Refract +}; - struct decalkey - { - ushort tex, reuse; +class sortkey +{ + public: + ushort tex; + uchar orient, layer, alpha; - decalkey() {} - decalkey(ushort tex, ushort reuse = 0) - : tex(tex), reuse(reuse) + sortkey() {} + sortkey(ushort tex, uchar orient, uchar layer = BlendLayer_Top, uchar alpha = Alpha_None) + : tex(tex), orient(orient), layer(layer), alpha(alpha) {} - bool operator==(const decalkey &o) const + bool operator==(const sortkey &o) const { - return tex==o.tex && reuse==o.reuse; + return tex==o.tex && orient==o.orient && layer==o.layer && alpha==o.alpha; } - static bool sort(const decalkey &x, const decalkey &y) + static bool sort(const sortkey &x, const sortkey &y) { + if(x.alpha < y.alpha) + { + return true; + } + if(x.alpha > y.alpha) + { + return false; + } + if(x.layer < y.layer) + { + return true; + } + if(x.layer > y.layer) + { + return false; + } if(x.tex == y.tex) { - if(x.reuse < y.reuse) + if(x.orient < y.orient) { return true; } - else + if(x.orient > y.orient) { return false; } + return false; } - DecalSlot &xs = lookupdecalslot(x.tex, false), - &ys = lookupdecalslot(y.tex, false); + VSlot &xs = lookupvslot(x.tex, false), + &ys = lookupvslot(y.tex, false); if(xs.slot->shader < ys.slot->shader) { return true; @@ -400,492 +300,130 @@ namespace return false; } } - }; +}; - inline bool htcmp(const decalkey &x, const decalkey &y) - { - return x == y; - } +inline bool htcmp(const sortkey &x, const sortkey &y) +{ + return x == y; +} - inline uint hthash(const decalkey &k) +inline uint hthash(const sortkey &k) +{ + return k.tex; +} + +struct decalkey +{ + ushort tex, reuse; + + decalkey() {} + decalkey(ushort tex, ushort reuse = 0) + : tex(tex), reuse(reuse) + {} + + bool operator==(const decalkey &o) const { - return k.tex; + return tex==o.tex && reuse==o.reuse; } - struct sortval + static bool sort(const decalkey &x, const decalkey &y) { - vector tris; - - sortval() {} - }; + if(x.tex == y.tex) + { + if(x.reuse < y.reuse) + { + return true; + } + else + { + return false; + } + } + DecalSlot &xs = lookupdecalslot(x.tex, false), + &ys = lookupdecalslot(y.tex, false); + if(xs.slot->shader < ys.slot->shader) + { + return true; + } + if(xs.slot->shader > ys.slot->shader) + { + return false; + } + if(xs.slot->params.length() < ys.slot->params.length()) + { + return true; + } + if(xs.slot->params.length() > ys.slot->params.length()) + { + return false; + } + if(x.tex < y.tex) + { + return true; + } + else + { + return false; + } + } +}; - class vacollect : public verthash - { - public: - int size; - ivec origin; - std::vector matsurfs; - vector mapmodels, decals, extdecals; - vec skymin, skymax; - vec alphamin, alphamax; - vec refractmin, refractmax; - vector grasstris; - int worldtris, skytris; - vector skyindices; - hashtable indices; - - void clear() - { - clearverts(); - worldtris = skytris = decaltris = 0; - indices.clear(); - decalindices.clear(); - skyindices.setsize(0); - matsurfs.clear(); - mapmodels.setsize(0); - decals.setsize(0); - extdecals.setsize(0); - grasstris.setsize(0); - texs.setsize(0); - decaltexs.setsize(0); - alphamin = refractmin = skymin = vec(1e16f, 1e16f, 1e16f); - alphamax = refractmax = skymax = vec(-1e16f, -1e16f, -1e16f); - } - - void setupdata(vtxarray *va) - { - optimize(); - gendecals(); - - va->verts = verts.size(); - va->tris = worldtris/3; - va->vbuf = 0; - va->vdata = 0; - va->minvert = 0; - va->maxvert = va->verts-1; - va->voffset = 0; - if(va->verts) - { - if(vbosize[VBO_VBuf] + static_cast(verts.size()) > maxvbosize || - vbosize[VBO_EBuf] + worldtris > USHRT_MAX || - vbosize[VBO_SkyBuf] + skytris > USHRT_MAX || - vbosize[VBO_DecalBuf] + decaltris > USHRT_MAX) - { - flushvbo(); - } - uchar *vdata = addvbo(va, VBO_VBuf, va->verts, sizeof(vertex)); - genverts(vdata); - va->minvert += va->voffset; - va->maxvert += va->voffset; - } +inline bool htcmp(const decalkey &x, const decalkey &y) +{ + return x == y; +} - va->matbuf = nullptr; - va->matsurfs = matsurfs.size(); - va->matmask = 0; - if(va->matsurfs) - { - va->matbuf = new materialsurface[matsurfs.size()]; - memcpy(va->matbuf, matsurfs.data(), matsurfs.size()*sizeof(materialsurface)); - for(uint i = 0; i < matsurfs.size(); i++) - { - materialsurface &m = matsurfs[i]; - if(m.visible == MatSurf_EditOnly) - { - continue; - } - switch(m.material) - { - case Mat_Glass: - case Mat_Water: - { - break; - } - default: - { - continue; - } - } - va->matmask |= 1<skybuf = 0; - va->skydata = 0; - va->skyoffset = 0; - va->sky = skyindices.length(); - if(va->sky) - { - ushort *skydata = reinterpret_cast(addvbo(va, VBO_SkyBuf, va->sky, sizeof(ushort))); - memcpy(skydata, skyindices.getbuf(), va->sky*sizeof(ushort)); - if(va->voffset) - { - for(int i = 0; i < va->sky; ++i) - { - skydata[i] += va->voffset; - } - } - } +struct sortval +{ + vector tris; - va->texelems = nullptr; - va->texs = texs.length(); - va->alphabacktris = 0; - va->alphaback = 0; - va->alphafronttris = 0; - va->alphafront = 0; - va->refracttris = 0; - va->refract = 0; - va->ebuf = 0; - va->edata = 0; - va->eoffset = 0; - if(va->texs) - { - va->texelems = new elementset[va->texs]; - ushort *edata = reinterpret_cast(addvbo(va, VBO_EBuf, worldtris, sizeof(ushort))), - *curbuf = edata; - for(int i = 0; i < texs.length(); i++) - { - const sortkey &k = texs[i]; - const sortval &t = indices[k]; - elementset &e = va->texelems[i]; - e.texture = k.tex; - e.orient = k.orient; - e.layer = k.layer; - ushort *startbuf = curbuf; - e.minvert = USHRT_MAX; - e.maxvert = 0; - - if(t.tris.length()) - { - memcpy(curbuf, t.tris.getbuf(), t.tris.length() * sizeof(ushort)); - for(int j = 0; j < t.tris.length(); j++) - { - curbuf[j] += va->voffset; - e.minvert = std::min(e.minvert, curbuf[j]); - e.maxvert = std::max(e.maxvert, curbuf[j]); - } - curbuf += t.tris.length(); - } - e.length = curbuf-startbuf; - if(k.alpha==Alpha_Back) - { - va->texs--; - va->tris -= e.length/3; - va->alphaback++; - va->alphabacktris += e.length/3; - } - else if(k.alpha==Alpha_Front) - { - va->texs--; - va->tris -= e.length/3; - va->alphafront++; - va->alphafronttris += e.length/3; - } - else if(k.alpha==Alpha_Refract) - { - va->texs--; - va->tris -= e.length/3; - va->refract++; - va->refracttris += e.length/3; - } - } - } + sortval() {} +}; - va->texmask = 0; - va->dyntexs = 0; - for(int i = 0; i < (va->texs+va->alphaback+va->alphafront+va->refract); ++i) - { - VSlot &vslot = lookupvslot(va->texelems[i].texture, false); - if(vslot.isdynamic()) - { - va->dyntexs++; - } - Slot &slot = *vslot.slot; - for(int j = 0; j < slot.sts.length(); j++) - { - va->texmask |= 1< matsurfs; + vector mapmodels, decals, extdecals; + vec skymin, skymax; + vec alphamin, alphamax; + vec refractmin, refractmax; + vector grasstris; + int worldtris, skytris; + vector skyindices; + hashtable indices; - va->decalbuf = 0; - va->decaldata = 0; - va->decaloffset = 0; - va->decalelems = nullptr; - va->decaltexs = decaltexs.length(); - va->decaltris = decaltris/3; - if(va->decaltexs) - { - va->decalelems = new elementset[va->decaltexs]; - ushort *edata = reinterpret_cast(addvbo(va, VBO_DecalBuf, decaltris, sizeof(ushort))), - *curbuf = edata; - for(int i = 0; i < decaltexs.length(); i++) - { - const decalkey &k = decaltexs[i]; - const sortval &t = decalindices[k]; - elementset &e = va->decalelems[i]; - e.texture = k.tex; - e.reuse = k.reuse; - ushort *startbuf = curbuf; - e.minvert = USHRT_MAX; - e.maxvert = 0; - if(t.tris.length()) - { - memcpy(curbuf, t.tris.getbuf(), t.tris.length() * sizeof(ushort)); - for(int j = 0; j < t.tris.length(); j++) - { - curbuf[j] += va->voffset; - e.minvert = std::min(e.minvert, curbuf[j]); - e.maxvert = std::max(e.maxvert, curbuf[j]); - } - curbuf += t.tris.length(); - } - e.length = curbuf-startbuf; - } - } - if(grasstris.length()) - { - va->grasstris.move(grasstris); - loadgrassshaders(); - } - if(mapmodels.length()) - { - va->mapmodels.put(mapmodels.getbuf(), mapmodels.length()); - } - if(decals.length()) - { - va->decals.put(decals.getbuf(), decals.length()); - } - } + hashtable decalindices; + vector texs; + vector decaltexs; + int decaltris; - bool emptyva() - { - return verts.empty() && matsurfs.empty() && skyindices.empty() && grasstris.empty() && mapmodels.empty() && decals.empty(); - } + void clear(); - private: - hashtable decalindices; - vector texs; - vector decaltexs; - int decaltris; + bool emptyva(); - void optimize() - { - ENUMERATE_KT(indices, sortkey, k, sortval, t, - { - if(t.tris.length()) - { - texs.add(k); - } - }); - texs.sort(sortkey::sort); + void optimize(); - matsurfs.resize(optimizematsurfs(matsurfs.data(), matsurfs.size())); - } + void gendecals(); - void genverts(void *buf) - { - vertex *f = reinterpret_cast(buf); - for(vertex i : verts) - { - const vertex &v = i; - *f = v; - f->norm.flip(); - f->tangent.flip(); - f++; - } - } + void genverts(void *buf); - void gendecal(const extentity &e, DecalSlot &s, const decalkey &key) - { - matrix3 orient; - orient.identity(); - if(e.attr2) - { - orient.rotate_around_z(sincosmod360(e.attr2)); - } - if(e.attr3) - { - orient.rotate_around_x(sincosmod360(e.attr3)); - } - if(e.attr4) - { - orient.rotate_around_y(sincosmod360(-e.attr4)); - } - vec size(std::max(static_cast(e.attr5), 1.0f)); - size.y *= s.depth; - if(!s.sts.empty()) - { - Texture *t = s.sts[0].t; - if(t->xs < t->ys) - { - size.x *= t->xs / static_cast(t->ys); - } - else if(t->xs > t->ys) - { - size.z *= t->ys / static_cast(t->xs); - } - } - vec center = orient.transform(vec(0, size.y*0.5f, 0)).add(e.o), - radius = orient.abstransform(vec(size).mul(0.5f)), - bbmin = vec(center).sub(radius), - bbmax = vec(center).add(radius), - clipoffset = orient.transposedtransform(center).msub(size, 0.5f); - for(int i = 0; i < texs.length(); i++) - { - const sortkey &k = texs[i]; - if(k.layer == BlendLayer_Blend || k.alpha != Alpha_None) - { - continue; - } - const sortval &t = indices[k]; - if(t.tris.empty()) - { - continue; - } - decalkey tkey(key); - if(shouldreuseparams(s, lookupvslot(k.tex, false))) - { - tkey.reuse = k.tex; - } - for(int j = 0; j < t.tris.length(); j += 3) - { - const vertex &t0 = verts[t.tris[j]], - &t1 = verts[t.tris[j+1]], - &t2 = verts[t.tris[j+2]]; - vec v0 = t0.pos, - v1 = t1.pos, - v2 = t2.pos, - tmin = vec(v0).min(v1).min(v2), - tmax = vec(v0).max(v1).max(v2); - if(tmin.x >= bbmax.x || tmin.y >= bbmax.y || tmin.z >= bbmax.z || - tmax.x <= bbmin.x || tmax.y <= bbmin.y || tmax.z <= bbmin.z) - { - continue; - } - float f0 = t0.norm.tonormal().dot(orient.b), - f1 = t1.norm.tonormal().dot(orient.b), - f2 = t2.norm.tonormal().dot(orient.b); - if(f0 >= 0 && f1 >= 0 && f2 >= 0) - { - continue; - } - vec p1[9], p2[9]; - p1[0] = v0; - p1[1] = v1; - p1[2] = v2; - int nump = polyclip(p1, 3, orient.b, clipoffset.y, clipoffset.y + size.y, p2); - if(nump < 3) - { - continue; - } - nump = polyclip(p2, nump, orient.a, clipoffset.x, clipoffset.x + size.x, p1); - if(nump < 3) - { - continue; - } - nump = polyclip(p1, nump, orient.c, clipoffset.z, clipoffset.z + size.z, p2); - if(nump < 3) - { - continue; - } - vec4 n0 = t0.norm, - n1 = t1.norm, - n2 = t2.norm, - x0 = t0.tangent, - x1 = t1.tangent, - x2 = t2.tangent; - vec e1 = vec(v1).sub(v0), - e2 = vec(v2).sub(v0); - float d11 = e1.dot(e1), - d12 = e1.dot(e2), - d22 = e2.dot(e2); - int idx[9]; - for(int k = 0; k < nump; ++k) - { - vertex v; - v.pos = p2[k]; - vec ep = vec(v.pos).sub(v0); - float dp1 = ep.dot(e1), - dp2 = ep.dot(e2), - denom = d11*d22 - d12*d12, - b1 = (d22*dp1 - d12*dp2) / denom, - b2 = (d11*dp2 - d12*dp1) / denom, - b0 = 1 - b1 - b2; - v.norm.lerp(n0, n1, n2, b0, b1, b2); - v.norm.w = static_cast(127.5f - 127.5f*(f0*b0 + f1*b1 + f2*b2)); - vec tc = orient.transposedtransform(vec(center).sub(v.pos)).div(size).add(0.5f); - v.tc = vec(tc.x, tc.z, s.fade ? tc.y * s.depth / s.fade : 1.0f); - v.tangent.lerp(x0, x1, x2, b0, b1, b2); - idx[k] = addvert(v); - } - vector &tris = decalindices[tkey].tris; - for(int k = 0; k < nump-2; ++k) - { - if(idx[0] != idx[k+1] && idx[k+1] != idx[k+2] && idx[k+2] != idx[0]) - { - tris.add(idx[0]); - tris.add(idx[k+1]); - tris.add(idx[k+2]); - decaltris += 3; - } - } - } - } - } + private: + void gendecal(const extentity &e, DecalSlot &s, const decalkey &key); +} vc; - void gendecals() - { - if(decals.length()) - { - extdecals.put(decals.getbuf(), decals.length()); - } - if(extdecals.empty()) - { - return; - } - vector &ents = entities::getents(); - for(int i = 0; i < extdecals.length(); i++) - { - octaentities *oe = extdecals[i]; - for(int j = 0; j < oe->decals.length(); j++) - { - extentity &e = *ents[oe->decals[j]]; - if(e.flags&EntFlag_Render) - { - continue; - } - e.flags |= EntFlag_Render; - DecalSlot &s = lookupdecalslot(e.attr1, true); - if(!s.shader) - { - continue; - } - decalkey k(e.attr1); - gendecal(e, s, k); - } - } - for(int i = 0; i < extdecals.length(); i++) - { - octaentities *oe = extdecals[i]; - for(int j = 0; j < oe->decals.length(); j++) - { - extentity &e = *ents[oe->decals[j]]; - if(e.flags&EntFlag_Render) - { - e.flags &= ~EntFlag_Render; - } - } - } - ENUMERATE_KT(decalindices, decalkey, k, sortval, t, - { - if(t.tris.length()) - { - decaltexs.add(k); - } - }); - decaltexs.sort(decalkey::sort); - } - } vc; +/* internally relevant functionality */ +/////////////////////////////////////// +namespace +{ int recalcprogress = 0; // [rotation][orient] @@ -1653,7 +1191,7 @@ namespace va->hasmerges = 0; va->mergelevel = -1; - vc.setupdata(va); + va->setupdata(&vc); if(va->alphafronttris || va->alphabacktris || va->refracttris) { @@ -1807,28 +1345,12 @@ namespace mfl.setsize(0); } - //recursively finds and adds decals to vacollect object vc - void finddecals(vtxarray *va) - { - if(va->hasmerges&(Merge_Origin|Merge_Part)) - { - for(int i = 0; i < va->decals.length(); i++) - { - vc.extdecals.add(va->decals[i]); - } - for(int i = 0; i < va->children.length(); i++) - { - finddecals(va->children[i]); - } - } - } - void rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel) // creates vertices and indices ready to be put into a va { if(c.ext && c.ext->va) { maxlevel = std::max(maxlevel, c.ext->va->mergelevel); - finddecals(c.ext->va); + c.ext->va->finddecals(); return; // don't re-render } @@ -1897,23 +1419,6 @@ namespace } } - void calcgeombb(const ivec &co, int size, ivec &bbmin, ivec &bbmax) - { - vec vmin(co), - vmax = vmin; - vmin.add(size); - - for(uint i = 0; i < vc.verts.size(); i++) - { - const vec &v = vc.verts[i].pos; - vmin.min(v); - vmax.max(v); - } - - bbmin = ivec(vmin.mul(8)).shr(3); - bbmax = ivec(vmax.mul(8)).add(7).shr(3); - } - int entdepth = -1; octaentities *entstack[32]; @@ -1940,8 +1445,8 @@ namespace { vtxarray *va = newva(co, size); ext(c).va = va; - calcgeombb(co, size, va->geommin, va->geommax); - calcmatbb(va, co, size, vc.matsurfs); + va->calcgeombb(co, size); + va->calcmatbb(co, size, vc.matsurfs); va->hasmerges = vahasmerges; va->mergelevel = vamergemax; } @@ -2134,6 +1639,246 @@ namespace } } +void vacollect::clear() +{ + clearverts(); + worldtris = skytris = decaltris = 0; + indices.clear(); + decalindices.clear(); + skyindices.setsize(0); + matsurfs.clear(); + mapmodels.setsize(0); + decals.setsize(0); + extdecals.setsize(0); + grasstris.setsize(0); + texs.setsize(0); + decaltexs.setsize(0); + alphamin = refractmin = skymin = vec(1e16f, 1e16f, 1e16f); + alphamax = refractmax = skymax = vec(-1e16f, -1e16f, -1e16f); +} + +bool vacollect::emptyva() +{ + return verts.empty() && matsurfs.empty() && skyindices.empty() && grasstris.empty() && mapmodels.empty() && decals.empty(); +} + +void vacollect::optimize() +{ + ENUMERATE_KT(indices, sortkey, k, sortval, t, + { + if(t.tris.length()) + { + texs.add(k); + } + }); + texs.sort(sortkey::sort); + + matsurfs.resize(optimizematsurfs(matsurfs.data(), matsurfs.size())); +} + +void vacollect::gendecals() +{ + if(decals.length()) + { + extdecals.put(decals.getbuf(), decals.length()); + } + if(extdecals.empty()) + { + return; + } + vector &ents = entities::getents(); + for(int i = 0; i < extdecals.length(); i++) + { + octaentities *oe = extdecals[i]; + for(int j = 0; j < oe->decals.length(); j++) + { + extentity &e = *ents[oe->decals[j]]; + if(e.flags&EntFlag_Render) + { + continue; + } + e.flags |= EntFlag_Render; + DecalSlot &s = lookupdecalslot(e.attr1, true); + if(!s.shader) + { + continue; + } + decalkey k(e.attr1); + gendecal(e, s, k); + } + } + for(int i = 0; i < extdecals.length(); i++) + { + octaentities *oe = extdecals[i]; + for(int j = 0; j < oe->decals.length(); j++) + { + extentity &e = *ents[oe->decals[j]]; + if(e.flags&EntFlag_Render) + { + e.flags &= ~EntFlag_Render; + } + } + } + ENUMERATE_KT(decalindices, decalkey, k, sortval, t, + { + if(t.tris.length()) + { + decaltexs.add(k); + } + }); + decaltexs.sort(decalkey::sort); +} + +void vacollect::genverts(void *buf) +{ + vertex *f = reinterpret_cast(buf); + for(vertex i : verts) + { + const vertex &v = i; + *f = v; + f->norm.flip(); + f->tangent.flip(); + f++; + } +} + +void vacollect::gendecal(const extentity &e, DecalSlot &s, const decalkey &key) +{ + matrix3 orient; + orient.identity(); + if(e.attr2) + { + orient.rotate_around_z(sincosmod360(e.attr2)); + } + if(e.attr3) + { + orient.rotate_around_x(sincosmod360(e.attr3)); + } + if(e.attr4) + { + orient.rotate_around_y(sincosmod360(-e.attr4)); + } + vec size(std::max(static_cast(e.attr5), 1.0f)); + size.y *= s.depth; + if(!s.sts.empty()) + { + Texture *t = s.sts[0].t; + if(t->xs < t->ys) + { + size.x *= t->xs / static_cast(t->ys); + } + else if(t->xs > t->ys) + { + size.z *= t->ys / static_cast(t->xs); + } + } + vec center = orient.transform(vec(0, size.y*0.5f, 0)).add(e.o), + radius = orient.abstransform(vec(size).mul(0.5f)), + bbmin = vec(center).sub(radius), + bbmax = vec(center).add(radius), + clipoffset = orient.transposedtransform(center).msub(size, 0.5f); + for(int i = 0; i < texs.length(); i++) + { + const sortkey &k = texs[i]; + if(k.layer == BlendLayer_Blend || k.alpha != Alpha_None) + { + continue; + } + const sortval &t = indices[k]; + if(t.tris.empty()) + { + continue; + } + decalkey tkey(key); + if(shouldreuseparams(s, lookupvslot(k.tex, false))) + { + tkey.reuse = k.tex; + } + for(int j = 0; j < t.tris.length(); j += 3) + { + const vertex &t0 = verts[t.tris[j]], + &t1 = verts[t.tris[j+1]], + &t2 = verts[t.tris[j+2]]; + vec v0 = t0.pos, + v1 = t1.pos, + v2 = t2.pos, + tmin = vec(v0).min(v1).min(v2), + tmax = vec(v0).max(v1).max(v2); + if(tmin.x >= bbmax.x || tmin.y >= bbmax.y || tmin.z >= bbmax.z || + tmax.x <= bbmin.x || tmax.y <= bbmin.y || tmax.z <= bbmin.z) + { + continue; + } + float f0 = t0.norm.tonormal().dot(orient.b), + f1 = t1.norm.tonormal().dot(orient.b), + f2 = t2.norm.tonormal().dot(orient.b); + if(f0 >= 0 && f1 >= 0 && f2 >= 0) + { + continue; + } + vec p1[9], p2[9]; + p1[0] = v0; + p1[1] = v1; + p1[2] = v2; + int nump = polyclip(p1, 3, orient.b, clipoffset.y, clipoffset.y + size.y, p2); + if(nump < 3) + { + continue; + } + nump = polyclip(p2, nump, orient.a, clipoffset.x, clipoffset.x + size.x, p1); + if(nump < 3) + { + continue; + } + nump = polyclip(p1, nump, orient.c, clipoffset.z, clipoffset.z + size.z, p2); + if(nump < 3) + { + continue; + } + vec4 n0 = t0.norm, + n1 = t1.norm, + n2 = t2.norm, + x0 = t0.tangent, + x1 = t1.tangent, + x2 = t2.tangent; + vec e1 = vec(v1).sub(v0), + e2 = vec(v2).sub(v0); + float d11 = e1.dot(e1), + d12 = e1.dot(e2), + d22 = e2.dot(e2); + int idx[9]; + for(int k = 0; k < nump; ++k) + { + vertex v; + v.pos = p2[k]; + vec ep = vec(v.pos).sub(v0); + float dp1 = ep.dot(e1), + dp2 = ep.dot(e2), + denom = d11*d22 - d12*d12, + b1 = (d22*dp1 - d12*dp2) / denom, + b2 = (d11*dp2 - d12*dp1) / denom, + b0 = 1 - b1 - b2; + v.norm.lerp(n0, n1, n2, b0, b1, b2); + v.norm.w = static_cast(127.5f - 127.5f*(f0*b0 + f1*b1 + f2*b2)); + vec tc = orient.transposedtransform(vec(center).sub(v.pos)).div(size).add(0.5f); + v.tc = vec(tc.x, tc.z, s.fade ? tc.y * s.depth / s.fade : 1.0f); + v.tangent.lerp(x0, x1, x2, b0, b1, b2); + idx[k] = addvert(v); + } + vector &tris = decalindices[tkey].tris; + for(int k = 0; k < nump-2; ++k) + { + if(idx[0] != idx[k+1] && idx[k+1] != idx[k+2] && idx[k+2] != idx[0]) + { + tris.add(idx[0]); + tris.add(idx[k+1]); + tris.add(idx[k+2]); + decaltris += 3; + } + } + } + } +} /* externally relevant functionality */ /////////////////////////////////////// @@ -2289,61 +2034,61 @@ void guessnormals(const vec *pos, int numverts, vec *normals) * * if reparent is set to true, assigns child vertex arrays to the parent of the selected va */ -void destroyva(vtxarray *va, bool reparent) +void vtxarray::destroyva(bool reparent) { - wverts -= va->verts; - wtris -= va->tris + va->alphabacktris + va->alphafronttris + va->refracttris + va->decaltris; + wverts -= verts; + wtris -= tris + alphabacktris + alphafronttris + refracttris + decaltris; allocva--; - valist.removeobj(va); - if(!va->parent) + valist.removeobj(this); + if(!parent) { - varoot.removeobj(va); + varoot.removeobj(this); } if(reparent) { - if(va->parent) + if(parent) { - va->parent->children.removeobj(va); + parent->children.removeobj(this); } - for(int i = 0; i < va->children.length(); i++) + for(int i = 0; i < children.length(); i++) { - vtxarray *child = va->children[i]; - child->parent = va->parent; + vtxarray *child = children[i]; + child->parent = parent; if(child->parent) { child->parent->children.add(child); } } } - if(va->vbuf) + if(vbuf) { - destroyvbo(va->vbuf); + destroyvbo(vbuf); } - if(va->ebuf) + if(ebuf) { - destroyvbo(va->ebuf); + destroyvbo(ebuf); } - if(va->skybuf) + if(skybuf) { - destroyvbo(va->skybuf); + destroyvbo(skybuf); } - if(va->decalbuf) + if(decalbuf) { - destroyvbo(va->decalbuf); + destroyvbo(decalbuf); } - if(va->texelems) + if(texelems) { - delete[] va->texelems; + delete[] texelems; } - if(va->decalelems) + if(decalelems) { - delete[] va->decalelems; + delete[] decalelems; } - if(va->matbuf) + if(matbuf) { - delete[] va->matbuf; + delete[] matbuf; } - delete va; + delete this; } //recursively clear vertex arrays for a cube object and its children @@ -2355,7 +2100,7 @@ void clearvas(cube *c) { if(c[i].ext->va) { - destroyva(c[i].ext->va, false); + c[i].ext->va->destroyva(false); } c[i].ext->va = nullptr; c[i].ext->tjoints = -1; @@ -2367,41 +2112,313 @@ void clearvas(cube *c) } } -void updatevabb(vtxarray *va, bool force) +//recursively adds to the vc vertexcollect object the decals at every vertex array (and its children) +void vtxarray::finddecals() +{ + if(hasmerges&(Merge_Origin|Merge_Part)) + { + for(int i = 0; i < decals.length(); i++) + { + vc.extdecals.add(decals[i]); + } + for(int i = 0; i < children.length(); i++) + { + children[i]->finddecals(); + } + } +} + +void vtxarray::updatevabb(bool force) { - if(!force && va->bbmin.x >= 0) + if(!force && bbmin.x >= 0) { return; } - va->bbmin = va->geommin; - va->bbmax = va->geommax; - va->bbmin.min(va->watermin); - va->bbmax.max(va->watermax); - va->bbmin.min(va->glassmin); - va->bbmax.max(va->glassmax); - for(int i = 0; i < va->children.length(); i++) + bbmin = geommin; + bbmax = geommax; + bbmin.min(watermin); + bbmax.max(watermax); + bbmin.min(glassmin); + bbmax.max(glassmax); + for(int i = 0; i < children.length(); i++) + { + vtxarray *child = children[i]; + child->updatevabb(force); + bbmin.min(child->bbmin); + bbmax.max(child->bbmax); + } + for(int i = 0; i < mapmodels.length(); i++) + { + octaentities *oe = mapmodels[i]; + bbmin.min(oe->bbmin); + bbmax.max(oe->bbmax); + } + for(int i = 0; i < decals.length(); i++) + { + octaentities *oe = decals[i]; + bbmin.min(oe->bbmin); + bbmax.max(oe->bbmax); + } + bbmin.max(o); + bbmax.min(ivec(o).add(size)); + worldmin.min(bbmin); + worldmax.max(bbmax); +} + +void vtxarray::setupdata(vacollect* vacol) +{ + vacol->optimize(); + vacol->gendecals(); + + verts = vacol->verts.size(); + tris = vacol->worldtris/3; + vbuf = 0; + vdata = 0; + minvert = 0; + maxvert = verts-1; + voffset = 0; + if(verts) + { + if(vbosize[VBO_VBuf] + static_cast(vacol->verts.size()) > maxvbosize || + vbosize[VBO_EBuf] + vacol->worldtris > USHRT_MAX || + vbosize[VBO_SkyBuf] + vacol->skytris > USHRT_MAX || + vbosize[VBO_DecalBuf] + vacol->decaltris > USHRT_MAX) + { + flushvbo(); + } + uchar *vdata = addvbo(VBO_VBuf, verts, sizeof(vertex)); + vacol->genverts(vdata); + minvert += voffset; + maxvert += voffset; + } + + matbuf = nullptr; + matsurfs = vacol->matsurfs.size(); + matmask = 0; + if(matsurfs) + { + matbuf = new materialsurface[vacol->matsurfs.size()]; + memcpy(matbuf, vacol->matsurfs.data(), vacol->matsurfs.size()*sizeof(materialsurface)); + for(int i = 0; i < vacol->matsurfs.size(); i++) + { + materialsurface &m = vacol->matsurfs[i]; + if(m.visible == MatSurf_EditOnly) + { + continue; + } + switch(m.material) + { + case Mat_Glass: + case Mat_Water: + { + break; + } + default: + { + continue; + } + } + matmask |= 1<skyindices.length(); + if(sky) + { + ushort *skydata = reinterpret_cast(addvbo(VBO_SkyBuf, sky, sizeof(ushort))); + memcpy(skydata, vacol->skyindices.getbuf(), sky*sizeof(ushort)); + if(voffset) + { + for(int i = 0; i < sky; ++i) + { + skydata[i] += voffset; + } + } + } + + texelems = nullptr; + texs = vacol->texs.length(); + alphabacktris = 0; + alphaback = 0; + alphafronttris = 0; + alphafront = 0; + refracttris = 0; + refract = 0; + ebuf = 0; + edata = 0; + eoffset = 0; + if(texs) + { + texelems = new elementset[texs]; + ushort *edata = reinterpret_cast(addvbo(VBO_EBuf, vacol->worldtris, sizeof(ushort))), + *curbuf = edata; + for(int i = 0; i < vacol->texs.length(); i++) + { + const sortkey &k = vacol->texs[i]; + const sortval &t = vacol->indices[k]; + elementset &e = texelems[i]; + e.texture = k.tex; + e.orient = k.orient; + e.layer = k.layer; + ushort *startbuf = curbuf; + e.minvert = USHRT_MAX; + e.maxvert = 0; + + if(t.tris.length()) + { + memcpy(curbuf, t.tris.getbuf(), t.tris.length() * sizeof(ushort)); + for(int j = 0; j < t.tris.length(); j++) + { + curbuf[j] += voffset; + e.minvert = std::min(e.minvert, curbuf[j]); + e.maxvert = std::max(e.maxvert, curbuf[j]); + } + curbuf += t.tris.length(); + } + e.length = curbuf-startbuf; + if(k.alpha==Alpha_Back) + { + texs--; + tris -= e.length/3; + alphaback++; + alphabacktris += e.length/3; + } + else if(k.alpha==Alpha_Front) + { + texs--; + tris -= e.length/3; + alphafront++; + alphafronttris += e.length/3; + } + else if(k.alpha==Alpha_Refract) + { + texs--; + tris -= e.length/3; + refract++; + refracttris += e.length/3; + } + } + } + + texmask = 0; + dyntexs = 0; + for(int i = 0; i < (texs+alphaback+alphafront+refract); ++i) + { + VSlot &vslot = lookupvslot(texelems[i].texture, false); + if(vslot.isdynamic()) + { + dyntexs++; + } + Slot &slot = *vslot.slot; + for(int j = 0; j < slot.sts.length(); j++) + { + texmask |= 1<decaltexs.length(); + decaltris = vacol->decaltris/3; + if(decaltexs) + { + decalelems = new elementset[decaltexs]; + ushort *edata = reinterpret_cast(addvbo(VBO_DecalBuf, vacol->decaltris, sizeof(ushort))), + *curbuf = edata; + for(int i = 0; i < vacol->decaltexs.length(); i++) + { + const decalkey &k = vacol->decaltexs[i]; + const sortval &t = vacol->decalindices[k]; + elementset &e = decalelems[i]; + e.texture = k.tex; + e.reuse = k.reuse; + ushort *startbuf = curbuf; + e.minvert = USHRT_MAX; + e.maxvert = 0; + if(t.tris.length()) + { + memcpy(curbuf, t.tris.getbuf(), t.tris.length() * sizeof(ushort)); + for(int j = 0; j < t.tris.length(); j++) + { + curbuf[j] += voffset; + e.minvert = std::min(e.minvert, curbuf[j]); + e.maxvert = std::max(e.maxvert, curbuf[j]); + } + curbuf += t.tris.length(); + } + e.length = curbuf-startbuf; + } + } + if(vacol->grasstris.length()) + { + grasstris.move(vacol->grasstris); + loadgrassshaders(); + } + if(vacol->mapmodels.length()) + { + mapmodels.put(vacol->mapmodels.getbuf(), vacol->mapmodels.length()); + } + if(vacol->decals.length()) { - vtxarray *child = va->children[i]; - updatevabb(child, force); - va->bbmin.min(child->bbmin); - va->bbmax.max(child->bbmax); + decals.put(vacol->decals.getbuf(), vacol->decals.length()); } - for(int i = 0; i < va->mapmodels.length(); i++) +} + +void vtxarray::calcgeombb(const ivec &co, int size) +{ + vec vmin(co), + vmax = vmin; + vmin.add(size); + + for(uint i = 0; i < vc.verts.size(); i++) { - octaentities *oe = va->mapmodels[i]; - va->bbmin.min(oe->bbmin); - va->bbmax.max(oe->bbmax); + const vec &v = vc.verts[i].pos; + vmin.min(v); + vmax.max(v); } - for(int i = 0; i < va->decals.length(); i++) + + bbmin = ivec(vmin.mul(8)).shr(3); + bbmax = ivec(vmax.mul(8)).add(7).shr(3); +} + +uchar * vtxarray::addvbo(int type, int numelems, int elemsize) +{ + switch(type) { - octaentities *oe = va->decals[i]; - va->bbmin.min(oe->bbmin); - va->bbmax.max(oe->bbmax); + case VBO_VBuf: + { + voffset = vbosize[type]; + break; + } + case VBO_EBuf: + { + eoffset = vbosize[type]; + break; + } + case VBO_SkyBuf: + { + skyoffset = vbosize[type]; + break; + } + case VBO_DecalBuf: + { + decaloffset = vbosize[type]; + break; + } } - va->bbmin.max(va->o); - va->bbmax.min(ivec(va->o).add(va->size)); - worldmin.min(va->bbmin); - worldmax.max(va->bbmax); + vbosize[type] += numelems; + vector &data = vbodata[type]; + vector &vas = vbovas[type]; + vas.add(this); + int len = numelems*elemsize; + uchar *buf = data.reserve(len).buf; + data.advance(len); + return buf; } //update vertex array bounding boxes recursively from the root va object down to all children @@ -2413,7 +2430,7 @@ void updatevabbs(bool force) worldmax = ivec(0, 0, 0); for(int i = 0; i < varoot.length(); i++) { - updatevabb(varoot[i], true); + varoot[i]->updatevabb(true); } if(worldmin.x >= worldmax.x) { @@ -2425,7 +2442,7 @@ void updatevabbs(bool force) { for(int i = 0; i < varoot.length(); i++) { - updatevabb(varoot[i]); + varoot[i]->updatevabb(); } } } diff --git a/src/engine/render/octarender.h b/src/engine/render/octarender.h index 90845dcd7..d5bdb3889 100644 --- a/src/engine/render/octarender.h +++ b/src/engine/render/octarender.h @@ -52,45 +52,119 @@ struct grasstri ushort texture; }; -struct vtxarray +struct renderstate { - vtxarray *parent; - vector children; - vtxarray *next, *rnext; // linked list of visible VOBs - vertex *vdata; // vertex data - ushort voffset, eoffset, skyoffset, decaloffset; // offset into vertex data - ushort *edata, *skydata, *decaldata; // vertex indices - GLuint vbuf, ebuf, skybuf, decalbuf; // VBOs - ushort minvert, maxvert; // DRE info - elementset *texelems, *decalelems; // List of element indices sets (range) per texture - materialsurface *matbuf; // buffer of material surfaces - int verts, - tris, - texs, - alphabacktris, alphaback, - alphafronttris, alphafront, - refracttris, refract, - texmask, - sky, - matsurfs, matmask, - distance, rdistance, - dyntexs, //dynamic if vscroll presentss - decaltris, decaltexs; - ivec o; - int size; // location and size of cube. - ivec geommin, geommax; // BB of geom - ivec alphamin, alphamax; // BB of alpha geom - ivec refractmin, refractmax; // BB of refract geom - ivec skymin, skymax; // BB of any sky geom - ivec watermin, watermax; // BB of any water - ivec glassmin, glassmax; // BB of any glass - ivec bbmin, bbmax; // BB of everything including children - uchar curvfc, occluded; - occludequery *query; - vector mapmodels, decals; - vector grasstris; - int hasmerges, mergelevel; - int shadowmask; + bool colormask, depthmask; + int alphaing; + GLuint vbuf; + bool vattribs, vquery; + vec colorscale; + float alphascale; + float refractscale; + vec refractcolor; + int globals, tmu; + GLuint textures[7]; + Slot *slot, *texgenslot; + VSlot *vslot, *texgenvslot; + vec2 texgenscroll; + int texgenorient, texgenmillis; + + renderstate(); +}; + +struct decalrenderer; + +class vacollect; + +class vtxarray +{ + public: + vtxarray *parent; + vector children; + vtxarray *next, *rnext; // linked list of visible VOBs + vertex *vdata; // vertex data + ushort eoffset, skyoffset, decaloffset; // offset into vertex data + ushort *edata, *skydata; // vertex indices + GLuint vbuf, ebuf, skybuf, decalbuf; // VBOs + elementset *texelems; + materialsurface *matbuf; // buffer of material surfaces + int verts, + tris, + texs, + alphabacktris, + alphafronttris, + refracttris, + sky, + matsurfs, + distance, rdistance, + dyntexs, //dynamic if vscroll presentss + decaltris; + ivec o; + int size; // location and size of cube. + ivec geommin, geommax; // BB of geom + ivec alphamin, alphamax; // BB of alpha geom + ivec refractmin, refractmax; // BB of refract geom + ivec skymin, skymax; // BB of any sky geom + ivec watermin, watermax; // BB of any water + ivec glassmin, glassmax; // BB of any glass + ivec bbmin, bbmax; // BB of everything including children + uchar curvfc, occluded; + occludequery *query; + vector mapmodels, decals; + vector grasstris; + int hasmerges, mergelevel; + int shadowmask; + void updatevabb(bool force = false); + void findspotshadowvas(); + void findrsmshadowvas(); + void findcsmshadowvas(); + void finddecals(); + void mergedecals(); + void findshadowvas(); + void calcgeombb(const ivec &co, int size); + + bool bbinsideva(const ivec &bo, const ivec &br); + void renderva(renderstate &cur, int pass = 0, bool doquery = false); + void drawvatris(GLsizei numindices, int offset); + void drawvaskytris(); + void calcmatbb(const ivec &co, int size, std::vector &matsurfs); //from material.cpp + void gengrassquads(); //from grass.cpp + + template + void findvisiblevas(); + + void changevbuf(decalrenderer &cur); + void changevbuf(renderstate &cur, int pass); + void setupdata(vacollect* vacol); + void vavbo(GLuint vbo, int type, uchar * data); + + //visibleva functions: loops through va->next + void renderoutline(); + void rendergeom(); + bool renderexplicitsky(bool outline = false); + int findalphavas(); + + //basically a destructor + void destroyva(bool reparent = true); + + private: + ushort voffset; + ushort *decaldata; // vertex indices + ushort minvert, maxvert; // DRE info + elementset *decalelems; // List of element indices sets (range) per texture + int alphaback, alphafront; + int refract; + int texmask; + int matmask; + int decaltexs; + + float vadist(const vec &p); + void addvisibleva(); + void mergetexs(renderstate &cur, elementset *texs = nullptr, int offset = 0); + void renderzpass(renderstate &cur); + void addshadowva(float dist); + uchar * addvbo(int type, int numelems, int elemsize); + void renderquery(renderstate &cur, bool full = true); }; extern ivec worldmin, worldmax; @@ -103,8 +177,6 @@ extern void guessnormals(const vec *pos, int numverts, vec *normals); extern void reduceslope(ivec &n); extern void findtjoints(); extern void clearvas(cube *c); -extern void destroyva(vtxarray *va, bool reparent = true); -extern void updatevabb(vtxarray *va, bool force = false); extern void updatevabbs(bool force = false); #endif diff --git a/src/engine/render/renderalpha.cpp b/src/engine/render/renderalpha.cpp index 61017954a..8565f3c8c 100644 --- a/src/engine/render/renderalpha.cpp +++ b/src/engine/render/renderalpha.cpp @@ -11,6 +11,7 @@ #include "../../shared/glexts.h" #include "hdr.h" +#include "octarender.h" #include "rendergl.h" #include "renderlights.h" #include "rendermodel.h" @@ -68,7 +69,7 @@ namespace void GBuffer::rendertransparent() { - int hasalphavas = findalphavas(), + int hasalphavas = visibleva->findalphavas(), hasmats = findmaterials(); bool hasmodels = transmdlsx1 < transmdlsx2 && transmdlsy1 < transmdlsy2; if(!hasalphavas && !hasmats && !hasmodels) //don't transparent render if there is no alpha diff --git a/src/engine/render/rendergl.cpp b/src/engine/render/rendergl.cpp index 62cfaceaa..d54926007 100644 --- a/src/engine/render/rendergl.cpp +++ b/src/engine/render/rendergl.cpp @@ -2058,7 +2058,7 @@ void gl_drawview(void (*gamefxn)(), void(*hudfxn)(), void(*editfxn)()) } else if(limitsky() && editmode) { - renderexplicitsky(true); + visibleva->renderexplicitsky(true); } //ambient obscurance (ambient occlusion) on geometry & models only @@ -2112,7 +2112,7 @@ void gl_drawview(void (*gamefxn)(), void(*hudfxn)(), void(*editfxn)()) { if(!wireframe && outline) { - renderoutline(); //edit mode geometry outline + visibleva->renderoutline(); //edit mode geometry outline } glerror(); rendereditmaterials(); diff --git a/src/engine/render/renderlights.cpp b/src/engine/render/renderlights.cpp index f8abc214b..45871b7bc 100644 --- a/src/engine/render/renderlights.cpp +++ b/src/engine/render/renderlights.cpp @@ -3948,10 +3948,10 @@ void rendergbuffer(bool depthclear, void (*gamefxn)()) if(limitsky()) { - renderexplicitsky(); + visibleva->renderexplicitsky(); glerror(); } - rendergeom(); + visibleva->rendergeom(); glerror(); renderdecals(); glerror(); diff --git a/src/engine/render/renderva.cpp b/src/engine/render/renderva.cpp index fca3f6514..9d7afca1b 100644 --- a/src/engine/render/renderva.cpp +++ b/src/engine/render/renderva.cpp @@ -66,11 +66,26 @@ struct shadowmesh int draws[6]; }; +struct decalrenderer +{ + GLuint vbuf; + vec colorscale; + int globals, tmu; + GLuint textures[7]; + DecalSlot *slot; + + decalrenderer() : vbuf(0), colorscale(1, 1, 1), globals(-1), tmu(-1), slot(nullptr) + { + for(int i = 0; i < 7; ++i) + { + textures[i] = 0; + } + } +}; + /* internally relevant functionality */ /////////////////////////////////////// -void findshadowvas(vector &vas); - namespace { void drawtris(GLsizei numindices, const GLvoid *indices, ushort minvert, ushort maxvert) @@ -79,16 +94,6 @@ namespace glde++; } - void drawvatris(vtxarray *va, GLsizei numindices, int offset) - { - drawtris(numindices, (ushort *)0 + va->eoffset + offset, va->minvert, va->maxvert); - } - - void drawvaskytris(vtxarray *va) - { - drawtris(va->sky, (ushort *)0 + va->skyoffset, va->minvert, va->maxvert); - } - ///////// view frustrum culling /////////////////////// float vadist(vtxarray *va, const vec &p) @@ -100,25 +105,6 @@ namespace vtxarray *vasort[vasortsize]; - void addvisibleva(vtxarray *va) - { - float dist = vadist(va, camera1->o); - va->distance = static_cast(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/ - - int hash = std::clamp(static_cast(dist*vasortsize/worldsize), 0, vasortsize-1); - vtxarray **prev = &vasort[hash], - *cur = vasort[hash]; - - while(cur && va->distance >= cur->distance) - { - prev = &cur->next; - cur = cur->next; - } - - va->next = cur; - *prev = va; - } - void sortvisiblevas() { visibleva = nullptr; @@ -138,53 +124,13 @@ namespace } } - template - void findvisiblevas(vector &vas) - { - for(int i = 0; i < vas.length(); i++) - { - vtxarray &v = *vas[i]; - int prevvfc = v.curvfc; - v.curvfc = fullvis ? ViewFrustumCull_FullyVisible : view.isvisiblecube(v.o, v.size); - if(v.curvfc != ViewFrustumCull_NotVisible) - { - bool resetchildren = prevvfc >= ViewFrustumCull_NotVisible || resetocclude; - if(resetchildren) - { - v.occluded = !v.texs ? Occlude_Geom : Occlude_Nothing; - v.query = nullptr; - } - addvisibleva(&v); - if(v.children.length()) - { - if(fullvis || v.curvfc == ViewFrustumCull_FullyVisible) - { - if(resetchildren) - { - findvisiblevas(v.children); - } - else - { - findvisiblevas(v.children); - } - } - else if(resetchildren) - { - findvisiblevas(v.children); - } - else - { - findvisiblevas(v.children); - } - } - } - } - } - void findvisiblevas() { memset(vasort, 0, sizeof(vasort)); - findvisiblevas(varoot); + for(int i = 0; i < varoot.length(); ++i) + { + varoot[i]->findvisiblevas(); + } sortvisiblevas(); } @@ -409,12 +355,6 @@ namespace rendermapmodel(e.attr1, anim, e.o, e.attr2, e.attr3, e.attr4, Model_CullVFC | Model_CullDist, basetime, e.attr5 > 0 ? e.attr5/100.0f : 1.0f); } - bool bbinsideva(const ivec &bo, const ivec &br, vtxarray *va) - { - return bo.x >= va->bbmin.x && bo.y >= va->bbmin.y && bo.z >= va->bbmin.z && - br.x <= va->bbmax.x && br.y <= va->bbmax.y && br.z <= va->bbmax.z; - } - bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size) { LOOP_OCTA_BOX(o, size, bo, br) @@ -423,7 +363,7 @@ namespace if(c[i].ext && c[i].ext->va) { vtxarray *va = c[i].ext->va; - if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && bbinsideva(bo, br, va))) + if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && va->bbinsideva(bo, br))) { continue; } @@ -513,23 +453,6 @@ namespace vtxarray *shadowva = nullptr; - void addshadowva(vtxarray *va, float dist) - { - va->rdistance = static_cast(dist); - - int hash = std::clamp(static_cast(dist*vasortsize/shadowradius), 0, vasortsize-1); - vtxarray **prev = &vasort[hash], *cur = vasort[hash]; - - while(cur && va->rdistance > cur->rdistance) - { - prev = &cur->rnext; - cur = cur->rnext; - } - - va->rnext = cur; - *prev = va; - } - void sortshadowvas() { shadowva = nullptr; @@ -549,116 +472,8 @@ namespace } } - void findcsmshadowvas(vector &vas) - { - for(int i = 0; i < vas.length(); i++) - { - vtxarray &v = *vas[i]; - ivec bbmin, bbmax; - if(v.children.length() || v.mapmodels.length()) - { - bbmin = v.bbmin; - bbmax = v.bbmax; - } - else - { - bbmin = v.geommin; - bbmax = v.geommax; - } - v.shadowmask = calcbbcsmsplits(bbmin, bbmax); - if(v.shadowmask) - { - float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias; - addshadowva(&v, dist); - if(v.children.length()) - { - findcsmshadowvas(v.children); - } - } - } - } - - void findrsmshadowvas(vector &vas) - { - for(int i = 0; i < vas.length(); i++) - { - vtxarray &v = *vas[i]; - ivec bbmin, bbmax; - if(v.children.length() || v.mapmodels.length()) - { - bbmin = v.bbmin; - bbmax = v.bbmax; - } - else - { - bbmin = v.geommin; - bbmax = v.geommax; - } - v.shadowmask = calcbbrsmsplits(bbmin, bbmax); - if(v.shadowmask) - { - float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias; - addshadowva(&v, dist); - if(v.children.length()) - { - findrsmshadowvas(v.children); - } - } - } - } - - void findspotshadowvas(vector &vas) - { - for(int i = 0; i < vas.length(); i++) - { - vtxarray &v = *vas[i]; - float dist = vadist(&v, shadoworigin); - if(dist < shadowradius || !smdistcull) - { - v.shadowmask = !smbbcull || (v.children.length() || v.mapmodels.length() ? - bbinsidespot(shadoworigin, shadowdir, shadowspot, v.bbmin, v.bbmax) : - bbinsidespot(shadoworigin, shadowdir, shadowspot, v.geommin, v.geommax)) ? 1 : 0; - addshadowva(&v, dist); - if(v.children.length()) - { - findspotshadowvas(v.children); - } - } - } - } - octaentities *shadowmms = nullptr; - struct renderstate - { - bool colormask, depthmask; - int alphaing; - GLuint vbuf; - bool vattribs, vquery; - vec colorscale; - float alphascale; - float refractscale; - vec refractcolor; - int globals, tmu; - GLuint textures[7]; - Slot *slot, *texgenslot; - VSlot *vslot, *texgenvslot; - vec2 texgenscroll; - int texgenorient, texgenmillis; - - renderstate() : colormask(true), depthmask(true), alphaing(0), vbuf(0), vattribs(false), - vquery(false), colorscale(1, 1, 1), alphascale(0), refractscale(0), - refractcolor(1, 1, 1), globals(-1), tmu(-1), slot(nullptr), - texgenslot(nullptr), vslot(nullptr), texgenvslot(nullptr), - texgenscroll(0, 0), texgenorient(-1), texgenmillis(lastmillis) - { - for(int k = 0; k < 7; ++k) - { - textures[k] = 0; - } - } - }; - void disablevbuf(renderstate &cur) { gle::clearvbo(); @@ -688,24 +503,6 @@ namespace cur.vquery = false; } - void renderquery(renderstate &cur, occludequery *query, vtxarray *va, bool full = true) - { - if(!cur.vquery) - { - enablevquery(cur); - } - startquery(query); - if(full) - { - drawbb(ivec(va->bbmin).sub(1), ivec(va->bbmax).sub(va->bbmin).add(2)); - } - else - { - drawbb(va->geommin, ivec(va->geommax).sub(va->geommin)); - } - endquery(); - } - enum { RenderPass_GBuffer = 0, @@ -808,106 +605,7 @@ namespace vector geombatches; int firstbatch = -1, - numbatches = 0; - - void mergetexs(renderstate &cur, vtxarray *va, elementset *texs = nullptr, int offset = 0) - { - int numtexs; - if(!texs) - { - texs = va->texelems; - numtexs = va->texs; - if(cur.alphaing) - { - texs += va->texs; - offset += 3*(va->tris); - numtexs = va->alphaback; - if(cur.alphaing > 1) - { - numtexs += va->alphafront + va->refract; - } - } - } - - if(firstbatch < 0) - { - firstbatch = geombatches.length(); - numbatches = numtexs; - for(int i = 0; i < numtexs-1; ++i) - { - geombatches.add(geombatch(texs[i], offset, va)).next = i+1; - offset += texs[i].length; - } - geombatches.add(geombatch(texs[numtexs-1], offset, va)); - return; - } - - int prevbatch = -1, - curbatch = firstbatch, - curtex = 0; - do - { - geombatch &b = geombatches.add(geombatch(texs[curtex], offset, va)); - offset += texs[curtex].length; - int dir = -1; - while(curbatch >= 0) - { - dir = b.compare(geombatches[curbatch]); - if(dir <= 0) - { - break; - } - prevbatch = curbatch; - curbatch = geombatches[curbatch].next; - } - if(!dir) - { - int last = curbatch, next; - for(;;) - { - next = geombatches[last].batch; - if(next < 0) - { - break; - } - last = next; - } - if(last==curbatch) - { - b.batch = curbatch; - b.next = geombatches[curbatch].next; - if(prevbatch < 0) - { - firstbatch = geombatches.length()-1; - } - else - { - geombatches[prevbatch].next = geombatches.length()-1; - } - curbatch = geombatches.length()-1; - } - else - { - b.batch = next; - geombatches[last].batch = geombatches.length()-1; - } - } - else - { - numbatches++; - b.next = curbatch; - if(prevbatch < 0) - { - firstbatch = geombatches.length()-1; - } - else - { - geombatches[prevbatch].next = geombatches.length()-1; - } - prevbatch = geombatches.length()-1; - } - } while(++curtex < numtexs); - } + numbatches = 0; void enablevattribs(renderstate &cur, bool all = true) { @@ -933,23 +631,6 @@ namespace cur.vattribs = false; } - void changevbuf(renderstate &cur, int pass, vtxarray *va) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->ebuf); - cur.vbuf = va->vbuf; - - vertex *vdata = nullptr; - gle::vertexpointer(sizeof(vertex), vdata->pos.v); - - if(pass==RenderPass_GBuffer || pass==RenderPass_ReflectiveShadowMap) - { - gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE); - gle::texcoord0pointer(sizeof(vertex), vdata->tc.v); - gle::tangentpointer(sizeof(vertex), vdata->tangent.v, GL_BYTE); - } - } - void changebatchtmus(renderstate &cur) { if(cur.tmu != 0) @@ -1197,7 +878,7 @@ namespace if(cur.vbuf != b.va->vbuf) { - changevbuf(cur, pass, b.va); + b.va->changevbuf(cur, pass); } if(pass == RenderPass_GBuffer || pass == RenderPass_ReflectiveShadowMap) { @@ -1227,155 +908,6 @@ namespace resetbatches(); } - void renderzpass(renderstate &cur, vtxarray *va) - { - if(!cur.vattribs) - { - if(cur.vquery) - { - disablevquery(cur); - } - enablevattribs(cur, false); - } - if(cur.vbuf!=va->vbuf) - { - changevbuf(cur, RenderPass_Z, va); - } - if(!cur.depthmask) - { - cur.depthmask = true; - glDepthMask(GL_TRUE); - } - if(cur.colormask) - { - cur.colormask = false; - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } - int firsttex = 0, - numtris = va->tris, - offset = 0; - if(cur.alphaing) - { - firsttex += va->texs; - offset += 3*(va->tris); - numtris = va->alphabacktris + va->alphafronttris + va->refracttris; - xtravertsva += 3*numtris; - } - else - { - xtravertsva += va->verts; - } - nocolorshader->set(); - drawvatris(va, 3*numtris, offset); - } -//====================================================== STARTVAQUERY ENDVAQUERY - #define STARTVAQUERY(va, flush) \ - do { \ - if(va->query) \ - { \ - flush; \ - startquery(va->query); \ - } \ - } while(0) - - - #define ENDVAQUERY(va, flush) \ - do { \ - if(va->query) \ - { \ - flush; \ - endquery(); \ - } \ - } while(0) - - VAR(batchgeom, 0, 1, 1); - - void renderva(renderstate &cur, vtxarray *va, int pass = RenderPass_GBuffer, bool doquery = false) - { - switch(pass) - { - case RenderPass_GBuffer: - if(!cur.alphaing) - { - vverts += va->verts; - } - if(doquery) - { - STARTVAQUERY(va, { if(geombatches.length()) renderbatches(cur, pass); }); - } - mergetexs(cur, va); - if(doquery) - { - ENDVAQUERY(va, { if(geombatches.length()) renderbatches(cur, pass); }); - } - else if(!batchgeom && geombatches.length()) - { - renderbatches(cur, pass); - } - break; - - case RenderPass_GBufferBlend: - if(doquery) - { - STARTVAQUERY(va, { if(geombatches.length()) renderbatches(cur, RenderPass_GBuffer); }); - } - mergetexs(cur, va, &va->texelems[va->texs], 3*va->tris); - if(doquery) - { - ENDVAQUERY(va, { if(geombatches.length()) renderbatches(cur, RenderPass_GBuffer); }); - } - else if(!batchgeom && geombatches.length()) - { - renderbatches(cur, RenderPass_GBuffer); - } - break; - - case RenderPass_Caustics: - if(!cur.vattribs) - { - enablevattribs(cur, false); - } - if(cur.vbuf!=va->vbuf) - { - changevbuf(cur, pass, va); - } - drawvatris(va, 3*va->tris, 0); - xtravertsva += va->verts; - break; - - case RenderPass_Z: - if(doquery) - { - STARTVAQUERY(va, ); - } - renderzpass(cur, va); - if(doquery) - { - ENDVAQUERY(va, ); - } - break; - - case RenderPass_ReflectiveShadowMap: - mergetexs(cur, va); - if(!batchgeom && geombatches.length()) - { - renderbatches(cur, pass); - } - break; - - case RenderPass_ReflectiveShadowMapBlend: - mergetexs(cur, va, &va->texelems[va->texs], 3*va->tris); - if(!batchgeom && geombatches.length()) - { - renderbatches(cur, RenderPass_ReflectiveShadowMap); - } - break; - } - } - - #undef STARTVAQUERY - #undef ENDVAQUERY -//============================================================================== void setupgeom() { glActiveTexture_(GL_TEXTURE0); @@ -1402,23 +934,6 @@ namespace CVARP(explicitskycolor, 0x800080); - struct decalrenderer - { - GLuint vbuf; - vec colorscale; - int globals, tmu; - GLuint textures[7]; - DecalSlot *slot; - - decalrenderer() : vbuf(0), colorscale(1, 1, 1), globals(-1), tmu(-1), slot(nullptr) - { - for(int i = 0; i < 7; ++i) - { - textures[i] = 0; - } - } - }; - struct decalbatch { const elementset &es; @@ -1480,113 +995,13 @@ namespace std::vector decalbatches; - void mergedecals(vtxarray *va) - { - elementset *texs = va->decalelems; - int numtexs = va->decaltexs, - offset = 0; - - if(firstbatch < 0) - { - firstbatch = decalbatches.size(); - numbatches = numtexs; - for(int i = 0; i < numtexs-1; ++i) - { - decalbatches.emplace_back(decalbatch(texs[i], offset, va)); - decalbatches.back().next = i+1; - offset += texs[i].length; - } - decalbatches.emplace_back(decalbatch(texs[numtexs-1], offset, va)); - return; - } - - int prevbatch = -1, - curbatch = firstbatch, - curtex = 0; - do - { - decalbatch b = decalbatch(texs[curtex], offset, va); - offset += texs[curtex].length; - int dir = -1; - while(curbatch >= 0) - { - dir = b.compare(decalbatches[curbatch]); - if(dir <= 0) - { - break; - } - prevbatch = curbatch; - curbatch = decalbatches[curbatch].next; - } - if(!dir) - { - int last = curbatch, next; - for(;;) - { - next = decalbatches[last].batch; - if(next < 0) - { - break; - } - last = next; - } - if(last==curbatch) - { - b.batch = curbatch; - b.next = decalbatches[curbatch].next; - if(prevbatch < 0) - { - firstbatch = decalbatches.size()-1; - } - else - { - decalbatches[prevbatch].next = decalbatches.size()-1; - } - curbatch = decalbatches.size()-1; - } - else - { - b.batch = next; - decalbatches[last].batch = decalbatches.size()-1; - } - } - else - { - numbatches++; - b.next = curbatch; - if(prevbatch < 0) - { - firstbatch = decalbatches.size()-1; - } - else - { - decalbatches[prevbatch].next = decalbatches.size()-1; - } - prevbatch = decalbatches.size()-1; - } - decalbatches.push_back(b); - } while(++curtex < numtexs); - } - - void resetdecalbatches() + void resetdecalbatches() { decalbatches.clear(); firstbatch = -1; numbatches = 0; } - void changevbuf(decalrenderer &cur, vtxarray *va) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->decalbuf); - cur.vbuf = va->vbuf; - vertex *vdata = nullptr; - gle::vertexpointer(sizeof(vertex), vdata->pos.v); - gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE, 4); - gle::texcoord0pointer(sizeof(vertex), vdata->tc.v, GL_FLOAT, 3); - gle::tangentpointer(sizeof(vertex), vdata->tangent.v, GL_BYTE); - } - void changebatchtmus(decalrenderer &cur) { if(cur.tmu != 0) @@ -1706,7 +1121,7 @@ namespace } if(cur.vbuf != b.va->vbuf) { - changevbuf(cur, b.va); + b.va->changevbuf(cur); } changebatchtmus(cur); if(cur.slot != &b.slot) @@ -2271,7 +1686,7 @@ bool cubeworld::bboccluded(const ivec &bo, const ivec &br) if(c->ext && c->ext->va) { vtxarray *va = c->ext->va; - if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && bbinsideva(bo, br, va))) + if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && va->bbinsideva(bo, br))) { return true; } @@ -2283,7 +1698,7 @@ bool cubeworld::bboccluded(const ivec &bo, const ivec &br) if(c->ext && c->ext->va) { vtxarray *va = c->ext->va; - if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && bbinsideva(bo, br, va))) + if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && va->bbinsideva(bo, br))) { return true; } @@ -2472,7 +1887,7 @@ void rendermapmodels() } } -void renderoutline() +void vtxarray::renderoutline() { ldrnotextureshader->set(); @@ -2488,7 +1903,7 @@ void renderoutline() glDisable(GL_DEPTH_TEST); } vtxarray *prev = nullptr; - for(vtxarray *va = visibleva; va; va = va->next) + for(vtxarray *va = this; va; va = va->next) { if(va->occluded < Occlude_BB) { @@ -2505,12 +1920,12 @@ void renderoutline() } if(va->texs && va->occluded < Occlude_Geom) { - drawvatris(va, 3*va->tris, 0); + va->drawvatris(3*va->tris, 0); xtravertsva += va->verts; } if(va->alphaback || va->alphafront || va->refract) { - drawvatris(va, 3*(va->alphabacktris + va->alphafronttris + va->refracttris), 3*(va->tris)); + va->drawvatris(3*(va->alphabacktris + va->alphafronttris + va->refracttris), 3*(va->tris)); xtravertsva += 3*(va->alphabacktris + va->alphafronttris + va->refracttris); } prev = va; @@ -2527,10 +1942,10 @@ void renderoutline() gle::disablevertex(); } -bool renderexplicitsky(bool outline) +bool vtxarray::renderexplicitsky(bool outline) { vtxarray *prev = nullptr; - for(vtxarray *va = visibleva; va; va = va->next) + for(vtxarray *va = this; va; va = va->next) { if(va->sky && va->occluded < Occlude_BB && ((va->skymax.x >= 0 && view.isvisiblebb(va->skymin, ivec(va->skymax).sub(va->skymin)) != ViewFrustumCull_NotVisible) || @@ -2565,7 +1980,7 @@ bool renderexplicitsky(bool outline) const vertex *ptr = 0; gle::vertexpointer(sizeof(vertex), ptr->pos.v); } - drawvaskytris(va); + va->drawvaskytris(); xtraverts += va->sky; prev = va; } @@ -2686,7 +2101,7 @@ int calctrisidemask(const vec &p1, const vec &p2, const vec &p3, float bias) return mask; } -int findalphavas() +int vtxarray::findalphavas() { alphavas.clear(); alphafrontsx1 = alphafrontsy1 = alphabacksx1 = alphabacksy1 = alpharefractsx1 = alpharefractsy1 = 1; @@ -2763,7 +2178,7 @@ void renderrefractmask() const vertex *ptr = 0; gle::vertexpointer(sizeof(vertex), ptr->pos.v); } - drawvatris(va, 3*va->refracttris, 3*(va->tris + va->alphabacktris + va->alphafronttris)); + va->drawvatris(3*va->refracttris, 3*(va->tris + va->alphabacktris + va->alphafronttris)); xtravertsva += 3*va->refracttris; prev = va; } @@ -2787,7 +2202,7 @@ void renderalphageom(int side) { for(uint i = 0; i < alphavas.size(); i++) { - renderva(cur, alphavas[i], RenderPass_GBuffer); + alphavas[i]->renderva(cur, RenderPass_GBuffer); } if(geombatches.length()) { @@ -2801,7 +2216,7 @@ void renderalphageom(int side) { if(alphavas[i]->alphabacktris) { - renderva(cur, alphavas[i], RenderPass_GBuffer); + alphavas[i]->renderva(cur, RenderPass_GBuffer); } } if(geombatches.length()) @@ -2814,7 +2229,8 @@ void renderalphageom(int side) cleanupgeom(cur); } -void rendergeom() +//starting from `this`, and looping through all va->next entries for `this`, render geometry to the world +void vtxarray::rendergeom() { bool doOQ = oqfrags && oqgeom && !drawtex, multipassing = false; @@ -2822,7 +2238,7 @@ void rendergeom() if(doOQ) { - for(vtxarray *va = visibleva; va; va = va->next) + for(vtxarray *va = this; va; va = va->next) { if(va->texs) { @@ -2853,7 +2269,7 @@ void rendergeom() { disablevbuf(cur); } - renderquery(cur, va->query, va); + va->renderquery(cur); } continue; } @@ -2867,7 +2283,7 @@ void rendergeom() continue; } } - renderva(cur, va, RenderPass_Z, true); + va->renderva(cur, RenderPass_Z, true); } } @@ -2913,11 +2329,11 @@ void rendergeom() cur.texgenorient = -1; setupgeom(); resetbatches(); - for(vtxarray *va = visibleva; va; va = va->next) + for(vtxarray *va = this; va; va = va->next) { if(va->texs && va->occluded < Occlude_Geom) { - renderva(cur, va, RenderPass_GBuffer); + va->renderva(cur, RenderPass_GBuffer); } } if(geombatches.length()) @@ -2925,7 +2341,7 @@ void rendergeom() renderbatches(cur, RenderPass_GBuffer); glFlush(); } - for(vtxarray *va = visibleva; va; va = va->next) + for(vtxarray *va = this; va; va = va->next) { if(va->texs && va->occluded >= Occlude_Geom) { @@ -2943,7 +2359,7 @@ void rendergeom() } } - renderva(cur, va, RenderPass_GBuffer); + va->renderva(cur, RenderPass_GBuffer); } } if(geombatches.length()) @@ -2955,7 +2371,7 @@ void rendergeom() { setupgeom(); resetbatches(); - for(vtxarray *va = visibleva; va; va = va->next) + for(vtxarray *va = this; va; va = va->next) { if(va->texs) { @@ -2965,7 +2381,7 @@ void rendergeom() { continue; } - renderva(cur, va, RenderPass_GBuffer); + va->renderva(cur, RenderPass_GBuffer); } } if(geombatches.length()) @@ -3032,7 +2448,7 @@ void renderdecals() { if(va->decaltris && va->occluded < Occlude_BB) { - mergedecals(va); + va->mergedecals(); if(!batchdecals && decalbatches.size()) { renderdecalbatches(cur, 0); @@ -3058,7 +2474,7 @@ void renderdecals() { if(va->decaltris && va->occluded < Occlude_BB) { - mergedecals(va); + va->mergedecals(); if(!batchdecals && decalbatches.size()) { renderdecalbatches(cur, 1); @@ -3079,7 +2495,7 @@ void renderdecals() { if(va->decaltris && va->occluded < Occlude_BB) { - mergedecals(va); + va->mergedecals(); if(!batchdecals && decalbatches.size()) { renderdecalbatches(cur, 0); @@ -3373,21 +2789,20 @@ int vfc::cullfrustumsides(const vec &lightpos, float lightradius, float size, fl return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5]; } -void findshadowvas(vector &vas) +void vtxarray::findshadowvas() { - for(int i = 0; i < vas.length(); i++) + float dist = vadist(shadoworigin); + if(dist < shadowradius || !smdistcull) { - vtxarray &v = *vas[i]; - float dist = vadist(&v, shadoworigin); - if(dist < shadowradius || !smdistcull) + shadowmask = !smbbcull ? 0x3F : (children.length() || mapmodels.length() ? + calcbbsidemask(bbmin, bbmax, shadoworigin, shadowradius, shadowbias) : + calcbbsidemask(geommin, geommax, shadoworigin, shadowradius, shadowbias)); + addshadowva(dist); + if(children.length()) { - v.shadowmask = !smbbcull ? 0x3F : (v.children.length() || v.mapmodels.length() ? - calcbbsidemask(v.bbmin, v.bbmax, shadoworigin, shadowradius, shadowbias) : - calcbbsidemask(v.geommin, v.geommax, shadoworigin, shadowradius, shadowbias)); - addshadowva(&v, dist); - if(v.children.length()) + for(int i = 0; i < children.length(); ++i) { - findshadowvas(v.children); + children[i]->findshadowvas(); } } } @@ -3417,7 +2832,7 @@ void renderrsmgeom(bool dyntex) const vertex *ptr = 0; gle::vertexpointer(sizeof(vertex), ptr->pos.v); } - drawvaskytris(va); + va->drawvaskytris(); xtravertsva += va->sky/3; prev = va; } @@ -3432,7 +2847,7 @@ void renderrsmgeom(bool dyntex) { if(va->texs) { - renderva(cur, va, RenderPass_ReflectiveShadowMap); + va->renderva(cur, RenderPass_ReflectiveShadowMap); } } if(geombatches.length()) @@ -3528,7 +2943,7 @@ void rendershadowmapworld() } if(!smnodraw) { - drawvatris(va, 3*va->tris, 0); + va->drawvatris(3*va->tris, 0); } xtravertsva += va->verts; prev = va; @@ -3550,7 +2965,7 @@ void rendershadowmapworld() } if(!smnodraw) { - drawvaskytris(va); + va->drawvaskytris(); } xtravertsva += va->sky/3; prev = va; @@ -3602,6 +3017,581 @@ void batchshadowmapmodels(bool skipmesh) } } +//renderstate methods + +renderstate::renderstate() : colormask(true), depthmask(true), alphaing(0), vbuf(0), vattribs(false), + vquery(false), colorscale(1, 1, 1), alphascale(0), refractscale(0), + refractcolor(1, 1, 1), globals(-1), tmu(-1), slot(nullptr), + texgenslot(nullptr), vslot(nullptr), texgenvslot(nullptr), + texgenscroll(0, 0), texgenorient(-1), texgenmillis(lastmillis) +{ + for(int k = 0; k < 7; ++k) + { + textures[k] = 0; + } +} + +//vertex array object methods + +void vtxarray::renderquery(renderstate &cur, bool full) +{ + if(!cur.vquery) + { + enablevquery(cur); + } + startquery(query); + if(full) + { + drawbb(ivec(bbmin).sub(1), ivec(bbmax).sub(bbmin).add(2)); + } + else + { + drawbb(geommin, ivec(geommax).sub(geommin)); + } + endquery(); +} + +void vtxarray::drawvaskytris() +{ + drawtris(sky, (ushort *)0 + skyoffset, minvert, maxvert); +} + +void vtxarray::drawvatris(GLsizei numindices, int offset) +{ + drawtris(numindices, (ushort *)0 + eoffset + offset, minvert, maxvert); +} + +float vtxarray::vadist(const vec &p) +{ + return p.dist_to_bb(bbmin, bbmax); +} + +template +void vtxarray::findvisiblevas() +{ + int prevvfc = curvfc; + curvfc = fullvis ? ViewFrustumCull_FullyVisible : view.isvisiblecube(o, size); + if(curvfc != ViewFrustumCull_NotVisible) + { + bool resetchildren = prevvfc >= ViewFrustumCull_NotVisible || resetocclude; + if(resetchildren) + { + occluded = !texs ? Occlude_Geom : Occlude_Nothing; + query = nullptr; + } + addvisibleva(); + if(children.length()) + { + if(fullvis || curvfc == ViewFrustumCull_FullyVisible) + { + if(resetchildren) + { + for(int i = 0; i < children.length(); ++i) + { + children[i]->findvisiblevas(); + } + } + else + { + for(int i = 0; i < children.length(); ++i) + { + children[i]->findvisiblevas(); + } + } + } + else if(resetchildren) + { + for(int i = 0; i < children.length(); ++i) + { + children[i]->findvisiblevas(); + } + } + else + { + for(int i = 0; i < children.length(); ++i) + { + children[i]->findvisiblevas(); + } + } + } + } +} + +void vtxarray::findrsmshadowvas() +{ + ivec bbmin, bbmax; + if(children.length() || mapmodels.length()) + { + bbmin = bbmin; + bbmax = bbmax; + } + else + { + bbmin = geommin; + bbmax = geommax; + } + shadowmask = calcbbrsmsplits(bbmin, bbmax); + if(shadowmask) + { + float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias; + addshadowva(dist); + for(int i = 0; i < children.length(); ++i) + { + children[i]->findrsmshadowvas(); + } + } +} + +void vtxarray::findcsmshadowvas() +{ + ivec bbmin, bbmax; + if(children.length() || mapmodels.length()) + { + bbmin = bbmin; + bbmax = bbmax; + } + else + { + bbmin = geommin; + bbmax = geommax; + } + shadowmask = calcbbcsmsplits(bbmin, bbmax); + if(shadowmask) + { + float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias; + addshadowva(dist); + for(int i = 0; i < children.length(); ++i) + { + children[i]->findcsmshadowvas(); + } + } +} + +void vtxarray::addvisibleva() +{ + float dist = vadist(camera1->o); + distance = static_cast(dist); /*cv.dist(camera1->o) - size*SQRT3/2*/ + + int hash = std::clamp(static_cast(dist*vasortsize/worldsize), 0, vasortsize-1); + vtxarray **prev = &vasort[hash], + *cur = vasort[hash]; + + while(cur && distance >= cur->distance) + { + prev = &cur->next; + cur = cur->next; + } + + next = cur; + *prev = this; +} + +void vtxarray::findspotshadowvas() +{ + float dist = vadist(shadoworigin); + if(dist < shadowradius || !smdistcull) + { + shadowmask = !smbbcull || (children.length() || mapmodels.length() ? + bbinsidespot(shadoworigin, shadowdir, shadowspot, bbmin, bbmax) : + bbinsidespot(shadoworigin, shadowdir, shadowspot, geommin, geommax)) ? 1 : 0; + addshadowva(dist); + for(int i = 0; i < children.length(); ++i) + { + children[i]->findspotshadowvas(); + } + } +} + +bool vtxarray::bbinsideva(const ivec &bo, const ivec &br) +{ + return bo.x >= bbmin.x && bo.y >= bbmin.y && bo.z >= bbmin.z && + br.x <= bbmax.x && br.y <= bbmax.y && br.z <= bbmax.z; +} + +void vtxarray::mergedecals() +{ + elementset *texs = decalelems; + int numtexs = decaltexs, + offset = 0; + + if(firstbatch < 0) + { + firstbatch = decalbatches.size(); + numbatches = numtexs; + for(int i = 0; i < numtexs-1; ++i) + { + decalbatches.emplace_back(decalbatch(texs[i], offset, this)); + decalbatches.back().next = i+1; + offset += texs[i].length; + } + decalbatches.emplace_back(decalbatch(texs[numtexs-1], offset, this)); + return; + } + + int prevbatch = -1, + curbatch = firstbatch, + curtex = 0; + do + { + decalbatch b = decalbatch(texs[curtex], offset, this); + offset += texs[curtex].length; + int dir = -1; + while(curbatch >= 0) + { + dir = b.compare(decalbatches[curbatch]); + if(dir <= 0) + { + break; + } + prevbatch = curbatch; + curbatch = decalbatches[curbatch].next; + } + if(!dir) + { + int last = curbatch, next; + for(;;) + { + next = decalbatches[last].batch; + if(next < 0) + { + break; + } + last = next; + } + if(last==curbatch) + { + b.batch = curbatch; + b.next = decalbatches[curbatch].next; + if(prevbatch < 0) + { + firstbatch = decalbatches.size()-1; + } + else + { + decalbatches[prevbatch].next = decalbatches.size()-1; + } + curbatch = decalbatches.size()-1; + } + else + { + b.batch = next; + decalbatches[last].batch = decalbatches.size()-1; + } + } + else + { + numbatches++; + b.next = curbatch; + if(prevbatch < 0) + { + firstbatch = decalbatches.size()-1; + } + else + { + decalbatches[prevbatch].next = decalbatches.size()-1; + } + prevbatch = decalbatches.size()-1; + } + decalbatches.push_back(b); + } while(++curtex < numtexs); +} + +void vtxarray::mergetexs(renderstate &cur, elementset *texin, int offset) +{ + int numtexs; + if(!texin) + { + texin = texelems; + numtexs = texs; + if(cur.alphaing) + { + texin += texs; + offset += 3*(tris); + numtexs = alphaback; + if(cur.alphaing > 1) + { + numtexs += alphafront + refract; + } + } + } + + if(firstbatch < 0) + { + firstbatch = geombatches.length(); + numbatches = numtexs; + for(int i = 0; i < numtexs-1; ++i) + { + geombatches.add(geombatch(texin[i], offset, this)).next = i+1; + offset += texin[i].length; + } + geombatches.add(geombatch(texin[numtexs-1], offset, this)); + return; + } + + int prevbatch = -1, + curbatch = firstbatch, + curtex = 0; + do + { + geombatch &b = geombatches.add(geombatch(texin[curtex], offset, this)); + offset += texin[curtex].length; + int dir = -1; + while(curbatch >= 0) + { + dir = b.compare(geombatches[curbatch]); + if(dir <= 0) + { + break; + } + prevbatch = curbatch; + curbatch = geombatches[curbatch].next; + } + if(!dir) + { + int last = curbatch, next; + for(;;) + { + next = geombatches[last].batch; + if(next < 0) + { + break; + } + last = next; + } + if(last==curbatch) + { + b.batch = curbatch; + b.next = geombatches[curbatch].next; + if(prevbatch < 0) + { + firstbatch = geombatches.length()-1; + } + else + { + geombatches[prevbatch].next = geombatches.length()-1; + } + curbatch = geombatches.length()-1; + } + else + { + b.batch = next; + geombatches[last].batch = geombatches.length()-1; + } + } + else + { + numbatches++; + b.next = curbatch; + if(prevbatch < 0) + { + firstbatch = geombatches.length()-1; + } + else + { + geombatches[prevbatch].next = geombatches.length()-1; + } + prevbatch = geombatches.length()-1; + } + } while(++curtex < numtexs); +} + +void vtxarray::changevbuf(decalrenderer &cur) +{ + gle::bindvbo(vbuf); + gle::bindebo(decalbuf); + cur.vbuf = vbuf; + vertex *vdata = nullptr; + gle::vertexpointer(sizeof(vertex), vdata->pos.v); + gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE, 4); + gle::texcoord0pointer(sizeof(vertex), vdata->tc.v, GL_FLOAT, 3); + gle::tangentpointer(sizeof(vertex), vdata->tangent.v, GL_BYTE); +} + +void vtxarray::changevbuf(renderstate &cur, int pass) +{ + gle::bindvbo(vbuf); + gle::bindebo(ebuf); + cur.vbuf = vbuf; + + vertex *vdata = nullptr; + gle::vertexpointer(sizeof(vertex), vdata->pos.v); + + if(pass==RenderPass_GBuffer || pass==RenderPass_ReflectiveShadowMap) + { + gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE); + gle::texcoord0pointer(sizeof(vertex), vdata->tc.v); + gle::tangentpointer(sizeof(vertex), vdata->tangent.v, GL_BYTE); + } +} + +void vtxarray::renderzpass(renderstate &cur) +{ + if(!cur.vattribs) + { + if(cur.vquery) + { + disablevquery(cur); + } + enablevattribs(cur, false); + } + if(cur.vbuf!=vbuf) + { + changevbuf(cur, RenderPass_Z); + } + if(!cur.depthmask) + { + cur.depthmask = true; + glDepthMask(GL_TRUE); + } + if(cur.colormask) + { + cur.colormask = false; + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } + int firsttex = 0, + numtris = tris, + offset = 0; + if(cur.alphaing) + { + firsttex += texs; + offset += 3*(tris); + numtris = alphabacktris + alphafronttris + refracttris; + xtravertsva += 3*numtris; + } + else + { + xtravertsva += verts; + } + nocolorshader->set(); + drawvatris(3*numtris, offset); +} + +void vtxarray::addshadowva(float dist) +{ + rdistance = static_cast(dist); + + int hash = std::clamp(static_cast(dist*vasortsize/shadowradius), 0, vasortsize-1); + vtxarray **prev = &vasort[hash], *cur = vasort[hash]; + + while(cur && rdistance > cur->rdistance) + { + prev = &cur->rnext; + cur = cur->rnext; + } + + rnext = cur; + *prev = this; +} + +//====================================================== STARTVAQUERY ENDVAQUERY +#define STARTVAQUERY(flush) \ + do { \ + if(query) \ + { \ + flush; \ + startquery(query); \ + } \ + } while(0) + + +#define ENDVAQUERY(flush) \ + do { \ + if(query) \ + { \ + flush; \ + endquery(); \ + } \ + } while(0) + +VAR(batchgeom, 0, 1, 1); + +void vtxarray::renderva(renderstate &cur, int pass, bool doquery) +{ + switch(pass) + { + case RenderPass_GBuffer: + if(!cur.alphaing) + { + vverts += this->verts; + } + if(doquery) + { + STARTVAQUERY( { if(geombatches.length()) renderbatches(cur, pass); }); + } + mergetexs(cur); + if(doquery) + { + ENDVAQUERY( { if(geombatches.length()) renderbatches(cur, pass); }); + } + else if(!batchgeom && geombatches.length()) + { + renderbatches(cur, pass); + } + break; + + case RenderPass_GBufferBlend: + if(doquery) + { + STARTVAQUERY( { if(geombatches.length()) renderbatches(cur, RenderPass_GBuffer); }); + } + mergetexs(cur, &this->texelems[this->texs], 3*this->tris); + if(doquery) + { + ENDVAQUERY( { if(geombatches.length()) renderbatches(cur, RenderPass_GBuffer); }); + } + else if(!batchgeom && geombatches.length()) + { + renderbatches(cur, RenderPass_GBuffer); + } + break; + + case RenderPass_Caustics: + if(!cur.vattribs) + { + enablevattribs(cur, false); + } + if(cur.vbuf!=this->vbuf) + { + changevbuf(cur, pass); + } + drawvatris(3*this->tris, 0); + xtravertsva += this->verts; + break; + + case RenderPass_Z: + if(doquery) + { + STARTVAQUERY(); + } + renderzpass(cur); + if(doquery) + { + ENDVAQUERY(); + } + break; + + case RenderPass_ReflectiveShadowMap: + mergetexs(cur); + if(!batchgeom && geombatches.length()) + { + renderbatches(cur, pass); + } + break; + + case RenderPass_ReflectiveShadowMapBlend: + mergetexs(cur, &this->texelems[this->texs], 3*this->tris); + if(!batchgeom && geombatches.length()) + { + renderbatches(cur, RenderPass_ReflectiveShadowMap); + } + break; + } +} + +#undef STARTVAQUERY +#undef ENDVAQUERY +//============================================================================== + void findshadowvas() { memset(vasort, 0, sizeof(vasort)); @@ -3609,22 +3599,34 @@ void findshadowvas() { case ShadowMap_Reflect: { - findrsmshadowvas(varoot); + for(int i = 0; i < varoot.length(); ++i) + { + varoot[i]->findrsmshadowvas(); + } break; } case ShadowMap_CubeMap: { - findshadowvas(varoot); + for(int i = 0; i < varoot.length(); ++i) + { + varoot[i]->findshadowvas(); + } break; } case ShadowMap_Cascade: { - findcsmshadowvas(varoot); + for(int i = 0; i < varoot.length(); ++i) + { + varoot[i]->findcsmshadowvas(); + } break; } case ShadowMap_Spot: { - findspotshadowvas(varoot); + for(int i = 0; i < varoot.length(); ++i) + { + varoot[i]->findspotshadowvas(); + } break; } } diff --git a/src/engine/render/renderva.h b/src/engine/render/renderva.h index 790c92c5c..55402268a 100644 --- a/src/engine/render/renderva.h +++ b/src/engine/render/renderva.h @@ -36,13 +36,9 @@ extern float alphafrontsx1, alphafrontsx2, alphafrontsy1, alphafrontsy2, alphaba extern uint alphatiles[]; extern vtxarray *visibleva; -extern void rendergeom(); -extern int findalphavas(); extern void renderrefractmask(); extern void renderalphageom(int side); extern void rendermapmodels(); -extern void renderoutline(); -extern bool renderexplicitsky(bool outline = false); extern bvec outlinecolor; extern int deferquery; diff --git a/src/engine/world/material.cpp b/src/engine/world/material.cpp index bd1923d04..752e45cc9 100644 --- a/src/engine/world/material.cpp +++ b/src/engine/world/material.cpp @@ -740,10 +740,10 @@ void genmatsurfs(const cube &c, const ivec &co, int size, std::vector &matsurfs) +void vtxarray::calcmatbb(const ivec &co, int size, std::vector &matsurfs) { - va->watermax = va->glassmax = co; - va->watermin = va->glassmin = ivec(co).add(size); + watermax = glassmax = co; + watermin = glassmin = ivec(co).add(size); for(uint i = 0; i < matsurfs.size(); i++) { materialsurface &m = matsurfs[i]; @@ -755,12 +755,12 @@ void calcmatbb(vtxarray *va, const ivec &co, int size, std::vectorwatermin, va->watermax, m); + addmatbb(watermin, watermax, m); break; } case Mat_Glass: { - addmatbb(va->glassmin, va->glassmax, m); + addmatbb(glassmin, glassmax, m); break; } default: diff --git a/src/engine/world/material.h b/src/engine/world/material.h index 18405dad8..8d31e7755 100644 --- a/src/engine/world/material.h +++ b/src/engine/world/material.h @@ -25,7 +25,6 @@ extern int findmaterial(const char *name); extern const char *findmaterialname(int mat); extern const char *getmaterialdesc(int mat, const char *prefix = ""); extern void genmatsurfs(const cube &c, const ivec &co, int size, std::vector &matsurfs); -extern void calcmatbb(vtxarray *va, const ivec &co, int size, std::vector &matsurfs); extern int optimizematsurfs(materialsurface *matbuf, int matsurfs); extern void setupmaterials(int start = 0, int len = 0); extern int findmaterials(); diff --git a/src/engine/world/octaedit.cpp b/src/engine/world/octaedit.cpp index 9c2270896..7725102e3 100644 --- a/src/engine/world/octaedit.cpp +++ b/src/engine/world/octaedit.cpp @@ -489,7 +489,7 @@ void readychanges(const ivec &bbmin, const ivec &bbmax, cube *c, const ivec &cor 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->destroyva(); c[i].ext->va = nullptr; if(hasmerges) { diff --git a/src/engine/world/octaworld.cpp b/src/engine/world/octaworld.cpp index 62ca49c9f..b358bf5bf 100644 --- a/src/engine/world/octaworld.cpp +++ b/src/engine/world/octaworld.cpp @@ -181,7 +181,7 @@ void cube::discardchildren(bool fixtex, int depth) { if(ext->va) { - destroyva(ext->va); + ext->va->destroyva(); } ext->va = nullptr; ext->tjoints = -1; @@ -2558,7 +2558,7 @@ void invalidatemerges(cube &c) { return; } - destroyva(c.ext->va); + c.ext->va->destroyva(); c.ext->va = nullptr; } if(c.ext->tjoints >= 0) diff --git a/src/engine/world/world.cpp b/src/engine/world/world.cpp index 54a64e48a..ea7449118 100644 --- a/src/engine/world/world.cpp +++ b/src/engine/world/world.cpp @@ -412,7 +412,7 @@ void modifyoctaentity(int flags, int id, extentity &e, cube *c, const ivec &cor, } else if(flags&ModOctaEnt_UpdateBB) { - updatevabb(va); + va->updatevabb(); } } }