diff --git a/src/gl/compatibility/gl_20.cpp b/src/gl/compatibility/gl_20.cpp index 5ff6c7710..84ecfc31d 100644 --- a/src/gl/compatibility/gl_20.cpp +++ b/src/gl/compatibility/gl_20.cpp @@ -588,6 +588,7 @@ bool FDrawInfo::PutFlatCompat(GLFlat *flat, bool fog) int list = list_indices[masked][foggy]; auto newflat = gl_drawinfo->dldrawlists[list].NewFlat(); *newflat = *flat; + newflat->vboindex = -1; // don't use the vertex buffer with legacy lights to ensure all passes use the same render logic. return true; } diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index ce32b3ab4..301b6bc1c 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -125,6 +125,8 @@ void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count) FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) : FVertexBuffer(!gl.legacyMode), FFlatVertexGenerator(width, height) { + ibo_id = 0; + if (gl.buffermethod != BM_LEGACY) glGenBuffers(1, &ibo_id); switch (gl.buffermethod) { case BM_PERSISTENT: @@ -170,6 +172,11 @@ FFlatVertexBuffer::~FFlatVertexBuffer() glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); } + if (ibo_id != 0) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &ibo_id); + } if (gl.legacyMode) { delete[] map; @@ -188,6 +195,7 @@ void FFlatVertexBuffer::OutputResized(int width, int height) void FFlatVertexBuffer::BindVBO() { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); if (!gl.legacyMode) { glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); @@ -245,4 +253,9 @@ void FFlatVertexBuffer::CreateVBO() Map(); memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); Unmap(); + if (ibo_id > 0) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo_data.Size() * sizeof(uint32_t), &ibo_data[0], GL_STATIC_DRAW); + } } diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 28fe8f45c..b21fcd2d3 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -95,6 +95,7 @@ public: class FFlatVertexBuffer : public FVertexBuffer, public FFlatVertexGenerator { + unsigned int ibo_id; FFlatVertex *map; unsigned int mIndex; std::atomic mCurIndex; @@ -177,6 +178,11 @@ public: #endif + uint32_t *GetIndexPointer() const + { + return ibo_id == 0 ? &ibo_data[0] : nullptr; + } + void CheckPlanes(sector_t *sector) { FFlatVertexGenerator::CheckPlanes(sector, map); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index ff55d1161..41e4e0e69 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -186,7 +186,8 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool { if (processlights) SetupSubsectorLights(flat, GLPASS_ALL, sub, &dli); drawcalls.Clock(); - glDrawArrays(GL_TRIANGLE_FAN, index, sub->numlines); + //glDrawArrays(GL_TRIANGLE_FAN, index, sub->numlines); + glDrawElements(GL_TRIANGLE_FAN, sub->numlines, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); drawcalls.Unclock(); flatvertices += sub->numlines; flatprimitives++; diff --git a/src/hwrenderer/data/flatvertices.cpp b/src/hwrenderer/data/flatvertices.cpp index 86bf78261..a5149a60e 100644 --- a/src/hwrenderer/data/flatvertices.cpp +++ b/src/hwrenderer/data/flatvertices.cpp @@ -181,10 +181,9 @@ int FFlatVertexGenerator::CreateVertices(int h, sector_t *sec, const secplane_t if (dotop || dobottom) { - if (dotop) ffloor->top.vindex = vbo_shadowdata.Size(); - if (dobottom) ffloor->bottom.vindex = vbo_shadowdata.Size(); - - CreateSectorVertices(fsec, plane, false); + auto ndx = CreateSectorVertices(fsec, plane, false); + if (dotop) ffloor->top.vindex = ndx; + if (dobottom) ffloor->bottom.vindex = ndx; } } } @@ -227,6 +226,147 @@ void FFlatVertexGenerator::CreateFlatVertices() } } +//========================================================================== +// +// Creates the vertices for one plane in one subsector +// +//========================================================================== + +int FFlatVertexGenerator::CreateIndexedSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor, int vi, FFlatVertexGenerator::FIndexGenerationInfo &gen) +{ + int idx = ibo_data.Reserve(sub->numlines); + for (unsigned int k = 0; knumlines; k++) + { + auto ndx = gen.GetIndex(sub->firstline[k].v1); + ibo_data[idx + k] = vi + ndx; + } + return idx; +} + +//========================================================================== +// +// Creates the vertices for one plane in one subsector +// +//========================================================================== + +int FFlatVertexGenerator::CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, FFlatVertexGenerator::FIndexGenerationInfo &gen) +{ + int rt = ibo_data.Size(); + int vi = vbo_shadowdata.Reserve(gen.vertices.Size()); + float diff; + + // Create the actual vertices. + if (sec->transdoor && floor) diff = -1.f; + else diff = 0.f; + for (unsigned i = 0; i < gen.vertices.Size(); i++) + { + vbo_shadowdata[vi + i].SetFlatVertex(gen.vertices[i], plane); + vbo_shadowdata[vi + i].z += diff; + } + + // Create the indices for the subsectors + for (int j = 0; jsubsectorcount; j++) + { + subsector_t *sub = sec->subsectors[j]; + CreateIndexedSubsectorVertices(sub, plane, floor, vi, gen); + } + return rt; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FFlatVertexGenerator::CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, TArray &gen) +{ + // First calculate the vertices for the sector itself + sec->vboheight[h] = sec->GetPlaneTexZ(h); + sec->vboindex[h] = CreateIndexedSectorVertices(sec, plane, floor, gen[sec->Index()]); + + // Next are all sectors using this one as heightsec + TArray &fakes = sec->e->FakeFloor.Sectors; + for (unsigned g = 0; gvboindex[2 + h] = CreateIndexedSectorVertices(fsec, plane, false, gen[fsec->Index()]); + } + + // and finally all attached 3D floors + TArray &xf = sec->e->XFloor.attached; + for (unsigned g = 0; gflags & FF_RENDERPLANES) + { + bool dotop = (ffloor->top.model == sec) && (ffloor->top.isceiling == h); + bool dobottom = (ffloor->bottom.model == sec) && (ffloor->bottom.isceiling == h); + + if (dotop || dobottom) + { + auto ndx = CreateIndexedSectorVertices(fsec, plane, false, gen[fsec->Index()]); + if (dotop) ffloor->top.vindex = ndx; + if (dobottom) ffloor->bottom.vindex = ndx; + } + } + } + sec->vbocount[h] = vbo_shadowdata.Size() - sec->vboindex[h]; + return sec->vboindex[h]; +} + + +//========================================================================== +// +// +// +//========================================================================== + +void FFlatVertexGenerator::CreateIndexedFlatVertices() +{ + TArray gen; + gen.Resize(level.sectors.Size()); + // This must be generated up front so that the following code knows how many vertices a sector contains. + for (unsigned i = 0; i < level.sectors.Size(); i++) + { + for (int j = 0; j < level.sectors[i].subsectorcount; j++) + { + auto sub = level.sectors[i].subsectors[j]; + for (unsigned k = 0; k < sub->numlines; k++) + { + auto vert = sub->firstline[k].v1; + gen[i].AddVertex(vert); + } + } + } + for (int h = sector_t::floor; h <= sector_t::ceiling; h++) + { + for (auto &sec : level.sectors) + { + CreateIndexedVertices(h, &sec, sec.GetSecPlane(h), h == sector_t::floor, gen); + } + } + + // We need to do a final check for Vavoom water and FF_FIX sectors. + // No new vertices are needed here. The planes come from the actual sector + for (auto &sec : level.sectors) + { + for (auto ff : sec.e->XFloor.ffloors) + { + if (ff->top.model == &sec) + { + ff->top.vindex = sec.vboindex[ff->top.isceiling]; + } + if (ff->bottom.model == &sec) + { + ff->bottom.vindex = sec.vboindex[ff->top.isceiling]; + } + } + } +} + //========================================================================== // // @@ -257,7 +397,7 @@ void FFlatVertexGenerator::UpdatePlaneVertices(sector_t *sec, int plane, FFlatVe void FFlatVertexGenerator::CreateVertices() { vbo_shadowdata.Resize(NUM_RESERVED); - CreateFlatVertices(); + CreateIndexedFlatVertices(); } //========================================================================== diff --git a/src/hwrenderer/data/flatvertices.h b/src/hwrenderer/data/flatvertices.h index 9a45558b5..2f0b1d5f4 100644 --- a/src/hwrenderer/data/flatvertices.h +++ b/src/hwrenderer/data/flatvertices.h @@ -45,9 +45,31 @@ class FFlatVertexGenerator { protected: TArray vbo_shadowdata; + TArray ibo_data; + // Temporary data for creating an indexed buffer + struct FIndexGenerationInfo + { + TArray vertices; + TMap vertexmap; + + uint32_t AddVertex(vertex_t *vert) + { + auto check = vertexmap.CheckKey(vert); + if (check != nullptr) return *check; + auto index = vertices.Push(vert); + vertexmap[vert] = index; + return index; + } + + uint32_t GetIndex(vertex_t *vert) + { + auto check = vertexmap.CheckKey(vert); + if (check != nullptr) return *check; + return ~0; + } + }; - void CheckPlanes(sector_t *sector); public: enum @@ -70,6 +92,12 @@ private: int CreateSectorVertices(sector_t *sec, const secplane_t &plane, int floor); int CreateVertices(int h, sector_t *sec, const secplane_t &plane, int floor); void CreateFlatVertices(); + + int CreateIndexedSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor, int vi, FIndexGenerationInfo &gen); + int CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, FIndexGenerationInfo &gen); + int CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, TArray &gen); + void CreateIndexedFlatVertices(); + void UpdatePlaneVertices(sector_t *sec, int plane, FFlatVertex *map); protected: void CreateVertices(); diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 4254c92d4..5c6096f84 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -120,6 +120,7 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag ffloor->top.copied = ffloor->bottom.copied = false; ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2; ffloor->target = sec; + ffloor->top.vindex = ffloor->bottom.vindex = -1; if (!(flags&FF_THINFLOOR)) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 56850f6a0..dba5a109e 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1510,6 +1510,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->friction = ORIG_FRICTION; ss->movefactor = ORIG_FRICTION_FACTOR; ss->sectornum = i; + ss->ibocount = -1; } delete[] msp; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 24a7fd5fd..ef2b08b8f 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1375,6 +1375,7 @@ public: sec->sectornum = index; sec->damageinterval = 32; sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; + sec->ibocount = -1; memset(sec->SpecialColors, -1, sizeof(sec->SpecialColors)); if (floordrop) sec->Flags = SECF_FLOORDROP; // killough 3/7/98: end changes diff --git a/src/r_defs.h b/src/r_defs.h index a9e7e57c7..b3ee3e96b 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1087,9 +1087,10 @@ public: vbo_fakeceiling = ceiling+2, }; - int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering + int vboindex[4]; // VBO/IBO indices of the 4 planes this sector uses during rendering double vboheight[2]; // Last calculated height for the 2 planes of this actual sector - int vbocount[2]; // Total count of vertices belonging to this sector's planes + int vbocount[2]; // Total count of vertices belonging to this sector's planes. This is used when a sector height changes and also contains all attached planes. + int ibocount; // number of indices per plane (identical for all planes.) If this is -1 the index buffer is not in use. float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; } bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); }