diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ff73e32c8..0918229d3c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -939,6 +939,7 @@ set( FASTMATH_SOURCES gl/dynlights/gl_glow.cpp gl/dynlights/gl_dynlight1.cpp gl/dynlights/gl_lightbuffer.cpp + gl/dynlights/gl_lightbsp.cpp gl/shaders/gl_shader.cpp gl/shaders/gl_texshader.cpp gl/shaders/gl_shaderprogram.cpp diff --git a/src/gl/dynlights/gl_lightbsp.cpp b/src/gl/dynlights/gl_lightbsp.cpp new file mode 100644 index 0000000000..7cb25acd4e --- /dev/null +++ b/src/gl/dynlights/gl_lightbsp.cpp @@ -0,0 +1,167 @@ +// +//--------------------------------------------------------------------------- +// Doom BSP tree on the GPU +// Copyright(C) 2017 Magnus Norddahl +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "gl/system/gl_system.h" +#include "gl/shaders/gl_shader.h" +#include "gl/dynlights/gl_lightbsp.h" +#include "gl/system/gl_interface.h" +#include "r_state.h" + +int FLightBSP::GetNodesBuffer() +{ + UpdateBuffers(); + return NodesBuffer; +} + +int FLightBSP::GetSegsBuffer() +{ + UpdateBuffers(); + return SegsBuffer; +} + +void FLightBSP::UpdateBuffers() +{ + if (numnodes != NumNodes || numsegs != NumSegs) // To do: there is probably a better way to detect a map change than this.. + Clear(); + + if (NodesBuffer == 0) + GenerateBuffers(); +} + +void FLightBSP::GenerateBuffers() +{ + UploadNodes(); + UploadSegs(); +} + +void FLightBSP::UploadNodes() +{ + TArray gpunodes; + gpunodes.Resize(numnodes); + for (int i = 0; i < numnodes; i++) + { + const auto &node = nodes[i]; + auto &gpunode = gpunodes[i]; + + float a = -FIXED2FLOAT(node.dy); + float b = FIXED2FLOAT(node.dx); + float c = 0.0f; + float d = -(a * FIXED2FLOAT(node.x) + b * FIXED2FLOAT(node.y)); + + gpunode.plane[0] = a; + gpunode.plane[1] = b; + gpunode.plane[2] = c; + gpunode.plane[3] = d; + + for (int j = 0; j < 2; j++) + { + bool isNode = (!((size_t)node.children[j] & 1)); + if (isNode) + { + node_t *bsp = (node_t *)node.children[j]; + gpunode.children[j] = (int)(ptrdiff_t)(bsp - nodes); + gpunode.linecount[j] = -1; + } + else + { + subsector_t *sub = (subsector_t *)((BYTE *)node.children[j] - 1); + if (sub->numlines > 0) + gpunode.children[j] = (int)(ptrdiff_t)(sub->firstline - segs); + else + gpunode.children[j] = 0; + gpunode.linecount[j] = sub->numlines; + } + } + } + +#if 0 + if (gpunodes.Size() > 0) + { + FILE *file = fopen("nodes.txt", "wb"); + fwrite(&gpunodes[0], sizeof(GPUNode) * gpunodes.Size(), 1, file); + fclose(file); + } +#endif + + int oldBinding = 0; + glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); + + glGenBuffers(1, (GLuint*)&NodesBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, NodesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GPUNode) * gpunodes.Size(), &gpunodes[0], GL_STATIC_DRAW); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); + + NumNodes = numnodes; +} + +void FLightBSP::UploadSegs() +{ + TArray gpusegs; + gpusegs.Resize(numsegs); + for (int i = 0; i < numsegs; i++) + { + const auto &seg = segs[i]; + auto &gpuseg = gpusegs[i]; + + gpuseg.x = (float)seg.v1->fX(); + gpuseg.y = (float)seg.v1->fY(); + gpuseg.dx = (float)seg.v2->fX() - gpuseg.x; + gpuseg.dy = (float)seg.v2->fY() - gpuseg.y; + gpuseg.bSolid = (seg.backsector == nullptr) ? 1.0f : 0.0f; + gpuseg.padding1 = 0.0f; + gpuseg.padding2 = 0.0f; + gpuseg.padding3 = 0.0f; + } + +#if 0 + if (gpusegs.Size() > 0) + { + FILE *file = fopen("segs.txt", "wb"); + fwrite(&gpusegs[0], sizeof(GPUSeg) * gpusegs.Size(), 1, file); + fclose(file); + } +#endif + + int oldBinding = 0; + glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); + + glGenBuffers(1, (GLuint*)&SegsBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, SegsBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GPUSeg) * gpusegs.Size(), &gpusegs[0], GL_STATIC_DRAW); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); + + NumSegs = numsegs; +} + +void FLightBSP::Clear() +{ + if (NodesBuffer != 0) + { + glDeleteBuffers(1, (GLuint*)&NodesBuffer); + NodesBuffer = 0; + } + if (SegsBuffer != 0) + { + glDeleteBuffers(1, (GLuint*)&SegsBuffer); + SegsBuffer = 0; + } +} diff --git a/src/gl/dynlights/gl_lightbsp.h b/src/gl/dynlights/gl_lightbsp.h new file mode 100644 index 0000000000..42cc6fee2c --- /dev/null +++ b/src/gl/dynlights/gl_lightbsp.h @@ -0,0 +1,42 @@ + +#pragma once + +struct GPUNode +{ + float plane[4]; + int children[2]; + int linecount[2]; +}; + +struct GPUSeg +{ + float x, y; + float dx, dy; + float bSolid; + float padding1, padding2, padding3; +}; + +class FLightBSP +{ +public: + FLightBSP() { } + ~FLightBSP() { Clear(); } + + int GetNodesBuffer(); + int GetSegsBuffer(); + void Clear(); + +private: + void UpdateBuffers(); + void GenerateBuffers(); + void UploadNodes(); + void UploadSegs(); + + FLightBSP(const FLightBSP &) = delete; + FLightBSP &operator=(FLightBSP &) = delete; + + int NodesBuffer = 0; + int SegsBuffer = 0; + int NumNodes = 0; + int NumSegs = 0; +}; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index ed2c523f28..2ba1cbc4d4 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -6,6 +6,7 @@ #include "vectors.h" #include "r_renderer.h" #include "gl/data/gl_matrix.h" +#include "gl/dynlights/gl_lightbsp.h" struct particle_t; class FCanvasTexture; @@ -123,6 +124,8 @@ public: FPresent3DColumnShader *mPresent3dColumnShader; FPresent3DRowShader *mPresent3dRowShader; + FLightBSP mLightBSP; + FTexture *gllight; FTexture *glpart2; FTexture *glpart;