/* ** hw_flatvertices.cpp ** Creates flat vertex data for hardware rendering. ** **--------------------------------------------------------------------------- ** Copyright 2010-2020 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** */ #include "doomtype.h" #include "p_local.h" #include "r_state.h" #include "c_cvars.h" #include "g_levellocals.h" #include "flatvertices.h" #include "v_video.h" #include "cmdlib.h" #include "hwrenderer/data/buffers.h" #include "hw_renderstate.h" //========================================================================== // // // //========================================================================== FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) { vbo_shadowdata.Resize(NUM_RESERVED); // the first quad is reserved for handling coordinates through uniforms. vbo_shadowdata[0].Set(0, 0, 0, 0, 0); vbo_shadowdata[1].Set(1, 0, 0, 0, 0); vbo_shadowdata[2].Set(2, 0, 0, 0, 0); vbo_shadowdata[3].Set(3, 0, 0, 0, 0); // and the second one for the fullscreen quad used for blend overlays. vbo_shadowdata[4].Set(0, 0, 0, 0, 0); vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1); vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0); vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1); // and this is for the postprocessing copy operation vbo_shadowdata[8].Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); vbo_shadowdata[9].Set(-1.0f, 1.0f, 0, 0.0f, 1.f); vbo_shadowdata[10].Set(1.0f, -1.0f, 0, 1.f, 0.0f); vbo_shadowdata[11].Set(1.0f, 1.0f, 0, 1.f, 1.f); // The next two are the stencil caps. vbo_shadowdata[12].Set(-32767.0f, 32767.0f, -32767.0f, 0, 0); vbo_shadowdata[13].Set(-32767.0f, 32767.0f, 32767.0f, 0, 0); vbo_shadowdata[14].Set(32767.0f, 32767.0f, 32767.0f, 0, 0); vbo_shadowdata[15].Set(32767.0f, 32767.0f, -32767.0f, 0, 0); vbo_shadowdata[16].Set(-32767.0f, -32767.0f, -32767.0f, 0, 0); vbo_shadowdata[17].Set(-32767.0f, -32767.0f, 32767.0f, 0, 0); vbo_shadowdata[18].Set(32767.0f, -32767.0f, 32767.0f, 0, 0); vbo_shadowdata[19].Set(32767.0f, -32767.0f, -32767.0f, 0, 0); mVertexBuffer = screen->CreateVertexBuffer(); mIndexBuffer = screen->CreateIndexBuffer(); unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex); mVertexBuffer->SetData(bytesize, nullptr, false); static const FVertexBufferAttribute format[] = { { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FFlatVertex, x) }, { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) } }; mVertexBuffer->SetFormat(1, 2, sizeof(FFlatVertex), format); mIndex = mCurIndex = 0; mNumReserved = NUM_RESERVED; Copy(0, NUM_RESERVED); } //========================================================================== // // // //========================================================================== FFlatVertexBuffer::~FFlatVertexBuffer() { delete mIndexBuffer; delete mVertexBuffer; mIndexBuffer = nullptr; mVertexBuffer = nullptr; } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::OutputResized(int width, int height) { vbo_shadowdata[4].Set(0, 0, 0, 0, 0); vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1); vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0); vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1); Copy(4, 4); } //========================================================================== // // Initialize a single vertex // //========================================================================== void FFlatVertex::SetFlatVertex(vertex_t *vt, const secplane_t & plane) { x = (float)vt->fX(); y = (float)vt->fY(); z = (float)plane.ZatPoint(vt); u = (float)vt->fX()/64.f; v = -(float)vt->fY()/64.f; } //========================================================================== // // Find a 3D floor // //========================================================================== static F3DFloor *Find3DFloor(sector_t *target, sector_t *model) { for(unsigned i=0; ie->XFloor.ffloors.Size(); i++) { F3DFloor *ffloor = target->e->XFloor.ffloors[i]; if (ffloor->model == model && !(ffloor->flags & FF_THISINSIDE)) return ffloor; } return NULL; } //========================================================================== // // Creates the vertices for one plane in one subsector // //========================================================================== int FFlatVertexBuffer::CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, VertexContainer &verts) { unsigned vi = vbo_shadowdata.Reserve(verts.vertices.Size()); float diff; // Create the actual vertices. if (sec->transdoor && floor) diff = -1.f; else diff = 0.f; for (unsigned i = 0; i < verts.vertices.Size(); i++) { vbo_shadowdata[vi + i].SetFlatVertex(verts.vertices[i].vertex, plane); vbo_shadowdata[vi + i].z += diff; } unsigned rt = ibo_data.Reserve(verts.indices.Size()); for (unsigned i = 0; i < verts.indices.Size(); i++) { ibo_data[rt + i] = vi + verts.indices[i]; } return (int)rt; } //========================================================================== // // // //========================================================================== int FFlatVertexBuffer::CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, VertexContainers &verts) { sec->vboindex[h] = vbo_shadowdata.Size(); // First calculate the vertices for the sector itself sec->vboheight[h] = sec->GetPlaneTexZ(h); sec->ibocount = verts[sec->Index()].indices.Size(); sec->iboindex[h] = CreateIndexedSectorVertices(sec, plane, floor, verts[sec->Index()]); // Next are all sectors using this one as heightsec TArray &fakes = sec->e->FakeFloor.Sectors; for (unsigned g = 0; g < fakes.Size(); g++) { sector_t *fsec = fakes[g]; fsec->iboindex[2 + h] = CreateIndexedSectorVertices(fsec, plane, false, verts[fsec->Index()]); } // and finally all attached 3D floors TArray &xf = sec->e->XFloor.attached; for (unsigned g = 0; g < xf.Size(); g++) { sector_t *fsec = xf[g]; F3DFloor *ffloor = Find3DFloor(fsec, sec); if (ffloor != NULL && ffloor->flags & 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, verts[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->iboindex[h]; } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::CreateIndexedFlatVertices(TArray §ors) { auto verts = BuildVertices(sectors); int i = 0; /* for (auto &vert : verts) { Printf(PRINT_LOG, "Sector %d\n", i); Printf(PRINT_LOG, "%d vertices, %d indices\n", vert.vertices.Size(), vert.indices.Size()); int j = 0; for (auto &v : vert.vertices) { Printf(PRINT_LOG, " %d: (%2.3f, %2.3f)\n", j++, v.vertex->fX(), v.vertex->fY()); } for (unsigned i=0;iXFloor.ffloors) { if (ff->top.model == &sec) { ff->top.vindex = sec.iboindex[ff->top.isceiling]; } if (ff->bottom.model == &sec) { ff->bottom.vindex = sec.iboindex[ff->top.isceiling]; } } } } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) { int startvt = sec->vboindex[plane]; int countvt = sec->vbocount[plane]; secplane_t &splane = sec->GetSecPlane(plane); FFlatVertex *vt = &vbo_shadowdata[startvt]; FFlatVertex *mapvt = GetBuffer(startvt); for(int i=0; iz = (float)splane.ZatPoint(vt->x, vt->y); if (plane == sector_t::floor && sec->transdoor) vt->z -= 1; mapvt->z = vt->z; } } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::CreateVertices(TArray §ors) { vbo_shadowdata.Resize(NUM_RESERVED); CreateIndexedFlatVertices(sectors); } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::CheckPlanes(sector_t *sector) { if (sector->GetPlaneTexZ(sector_t::ceiling) != sector->vboheight[sector_t::ceiling]) { UpdatePlaneVertices(sector, sector_t::ceiling); sector->vboheight[sector_t::ceiling] = sector->GetPlaneTexZ(sector_t::ceiling); } if (sector->GetPlaneTexZ(sector_t::floor) != sector->vboheight[sector_t::floor]) { UpdatePlaneVertices(sector, sector_t::floor); sector->vboheight[sector_t::floor] = sector->GetPlaneTexZ(sector_t::floor); } } //========================================================================== // // checks the validity of all planes attached to this sector // and updates them if possible. // //========================================================================== void FFlatVertexBuffer::CheckUpdate(sector_t *sector) { CheckPlanes(sector); sector_t *hs = sector->GetHeightSec(); if (hs != NULL) CheckPlanes(hs); for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++) CheckPlanes(sector->e->XFloor.ffloors[i]->model); } //========================================================================== // // // //========================================================================== std::pair FFlatVertexBuffer::AllocVertices(unsigned int count) { FFlatVertex *p = GetBuffer(); auto index = mCurIndex.fetch_add(count); auto offset = index; if (index + count >= BUFFER_SIZE_TO_USE) { // If a single scene needs 2'000'000 vertices there must be something very wrong. I_FatalError("Out of vertex memory. Tried to allocate more than %u vertices for a single frame", index + count); } return std::make_pair(p, index); } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::Copy(int start, int count) { Map(); memcpy(GetBuffer(start), &vbo_shadowdata[0], count * sizeof(FFlatVertex)); Unmap(); } //========================================================================== // // // //========================================================================== void FFlatVertexBuffer::CreateVBO(TArray §ors) { vbo_shadowdata.Resize(mNumReserved); FFlatVertexBuffer::CreateVertices(sectors); mCurIndex = mIndex = vbo_shadowdata.Size(); Copy(0, mIndex); mIndexBuffer->SetData(ibo_data.Size() * sizeof(uint32_t), &ibo_data[0]); }