gzdoom-gles/src/gl/dynlights/gl_lightbsp.cpp

168 lines
4.1 KiB
C++
Raw Normal View History

2017-03-01 01:46:03 +00:00
//
//---------------------------------------------------------------------------
// 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<GPUNode> 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<GPUSeg> 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;
}
}