diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2cd811b67..31ff9f470 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -939,7 +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/dynlights/gl_aabbtree.cpp gl/dynlights/gl_shadowmap.cpp gl/shaders/gl_shader.cpp gl/shaders/gl_texshader.cpp diff --git a/src/gl/dynlights/gl_lightbsp.cpp b/src/gl/dynlights/gl_aabbtree.cpp similarity index 80% rename from src/gl/dynlights/gl_lightbsp.cpp rename to src/gl/dynlights/gl_aabbtree.cpp index 0b954ffca..7108a7278 100644 --- a/src/gl/dynlights/gl_lightbsp.cpp +++ b/src/gl/dynlights/gl_aabbtree.cpp @@ -1,6 +1,6 @@ // //--------------------------------------------------------------------------- -// 2D collision tree for 1D shadowmap lights +// AABB-tree used for ray testing // Copyright(C) 2017 Magnus Norddahl // All rights reserved. // @@ -22,106 +22,11 @@ #include "gl/system/gl_system.h" #include "gl/shaders/gl_shader.h" -#include "gl/dynlights/gl_lightbsp.h" +#include "gl/dynlights/gl_aabbtree.h" #include "gl/system/gl_interface.h" #include "r_state.h" #include "g_levellocals.h" -int FLightBSP::GetNodesBuffer() -{ - UpdateBuffers(); - return NodesBuffer; -} - -int FLightBSP::GetLinesBuffer() -{ - UpdateBuffers(); - return LinesBuffer; -} - -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() -{ - if (!Shape) - Shape.reset(new LevelAABBTree()); - UploadNodes(); - UploadSegs(); -} - -void FLightBSP::UploadNodes() -{ -#if 0 - if (Shape->nodes.Size() > 0) - { - FILE *file = fopen("nodes.txt", "wb"); - fwrite(&Shape->nodes[0], sizeof(AABBTreeNode) * Shape->nodes.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(AABBTreeNode) * Shape->nodes.Size(), &Shape->nodes[0], GL_STATIC_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); - - NumNodes = numnodes; -} - -void FLightBSP::UploadSegs() -{ -#if 0 - if (Shape->lines.Size() > 0) - { - FILE *file = fopen("lines.txt", "wb"); - fwrite(&Shape->lines[0], sizeof(AABBTreeLine) * Shape->lines.Size(), 1, file); - fclose(file); - } -#endif - - int oldBinding = 0; - glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); - - glGenBuffers(1, (GLuint*)&LinesBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, LinesBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(AABBTreeLine) * Shape->lines.Size(), &Shape->lines[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 (LinesBuffer != 0) - { - glDeleteBuffers(1, (GLuint*)&LinesBuffer); - LinesBuffer = 0; - } - Shape.reset(); -} - -bool FLightBSP::ShadowTest(const DVector3 &light, const DVector3 &pos) -{ - return Shape->RayTest(light, pos) >= 1.0f; -} - -///////////////////////////////////////////////////////////////////////////// - LevelAABBTree::LevelAABBTree() { // Calculate the center of all lines diff --git a/src/gl/dynlights/gl_lightbsp.h b/src/gl/dynlights/gl_aabbtree.h similarity index 73% rename from src/gl/dynlights/gl_lightbsp.h rename to src/gl/dynlights/gl_aabbtree.h index 14728905d..0de075be5 100644 --- a/src/gl/dynlights/gl_lightbsp.h +++ b/src/gl/dynlights/gl_aabbtree.h @@ -2,7 +2,6 @@ #pragma once #include "vectors.h" -#include // Node in a binary AABB tree struct AABBTreeNode @@ -14,7 +13,7 @@ struct AABBTreeNode float aabb_left, aabb_top; float aabb_right, aabb_bottom; - // Children node indices + // Child node indices int left_node; int right_node; @@ -45,7 +44,7 @@ public: // Line segments for the leaf nodes in the tree. TArray lines; - // Shoot a ray from ray_start to ray_end and return the first hit as a fractional value between 0 and 1. Returns 1 if no line was hit. + // Shoot a ray from ray_start to ray_end and return the closest hit as a fractional value between 0 and 1. Returns 1 if no line was hit. double RayTest(const DVector3 &ray_start, const DVector3 &ray_end); private: @@ -58,32 +57,3 @@ private: // Generate a tree node and its children recursively int GenerateTreeNode(int *lines, int num_lines, const FVector2 *centroids, int *work_buffer); }; - -class FLightBSP -{ -public: - FLightBSP() { } - ~FLightBSP() { Clear(); } - - int GetNodesBuffer(); - int GetLinesBuffer(); - void Clear(); - - bool ShadowTest(const DVector3 &light, const DVector3 &pos); - -private: - void UpdateBuffers(); - void GenerateBuffers(); - void UploadNodes(); - void UploadSegs(); - - FLightBSP(const FLightBSP &) = delete; - FLightBSP &operator=(FLightBSP &) = delete; - - int NodesBuffer = 0; - int LinesBuffer = 0; - int NumNodes = 0; - int NumSegs = 0; - - std::unique_ptr Shape; -}; diff --git a/src/gl/dynlights/gl_shadowmap.cpp b/src/gl/dynlights/gl_shadowmap.cpp index d7215e9b4..8f8b74f44 100644 --- a/src/gl/dynlights/gl_shadowmap.cpp +++ b/src/gl/dynlights/gl_shadowmap.cpp @@ -32,19 +32,9 @@ #include "gl/shaders/gl_shadowmapshader.h" #include "r_state.h" -void FShadowMap::Clear() -{ - if (mLightList != 0) - { - glDeleteBuffers(1, (GLuint*)&mLightList); - mLightList = 0; - } - - mLightBSP.Clear(); -} - void FShadowMap::Update() { + UploadAABBTree(); UploadLights(); FGLDebug::PushGroup("ShadowMap"); @@ -54,8 +44,8 @@ void FShadowMap::Update() GLRenderer->mShadowMapShader->Bind(); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, mLightList); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, mLightBSP.GetNodesBuffer()); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, mLightBSP.GetLinesBuffer()); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, mNodesBuffer); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, mLinesBuffer); glViewport(0, 0, 1024, 1024); GLRenderer->RenderScreenQuad(); @@ -72,6 +62,14 @@ void FShadowMap::Update() FGLDebug::PopGroup(); } +bool FShadowMap::ShadowTest(ADynamicLight *light, const DVector3 &pos) +{ + if (mAABBTree) + return mAABBTree->RayTest(light->Pos(), pos) >= 1.0f; + else + return true; +} + void FShadowMap::UploadLights() { mLights.Clear(); @@ -107,7 +105,52 @@ void FShadowMap::UploadLights() glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); } -bool FShadowMap::ShadowTest(ADynamicLight *light, const DVector3 &pos) +void FShadowMap::UploadAABBTree() { - return mLightBSP.ShadowTest(light->Pos(), pos); + if (numnodes != mLastNumNodes || numsegs != mLastNumSegs) // To do: there is probably a better way to detect a map change than this.. + Clear(); + + if (mAABBTree) + return; + + mAABBTree.reset(new LevelAABBTree()); + + int oldBinding = 0; + glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); + + glGenBuffers(1, (GLuint*)&mNodesBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, mNodesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(AABBTreeNode) * mAABBTree->nodes.Size(), &mAABBTree->nodes[0], GL_STATIC_DRAW); + + glGenBuffers(1, (GLuint*)&mLinesBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, mLinesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(AABBTreeLine) * mAABBTree->lines.Size(), &mAABBTree->lines[0], GL_STATIC_DRAW); + + glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); +} + +void FShadowMap::Clear() +{ + if (mLightList != 0) + { + glDeleteBuffers(1, (GLuint*)&mLightList); + mLightList = 0; + } + + if (mNodesBuffer != 0) + { + glDeleteBuffers(1, (GLuint*)&mNodesBuffer); + mNodesBuffer = 0; + } + + if (mLinesBuffer != 0) + { + glDeleteBuffers(1, (GLuint*)&mLinesBuffer); + mLinesBuffer = 0; + } + + mAABBTree.reset(); + + mLastNumNodes = numnodes; + mLastNumSegs = numsegs; } diff --git a/src/gl/dynlights/gl_shadowmap.h b/src/gl/dynlights/gl_shadowmap.h index a8cc70129..b999a550f 100644 --- a/src/gl/dynlights/gl_shadowmap.h +++ b/src/gl/dynlights/gl_shadowmap.h @@ -1,8 +1,9 @@ #pragma once -#include "gl/dynlights/gl_lightbsp.h" +#include "gl/dynlights/gl_aabbtree.h" #include "tarray.h" +#include class ADynamicLight; @@ -20,13 +21,21 @@ public: bool ShadowTest(ADynamicLight *light, const DVector3 &pos); private: + void UploadAABBTree(); void UploadLights(); - FLightBSP mLightBSP; int mLightList = 0; TArray mLights; TMap mLightToShadowmap; + int mNodesBuffer = 0; + int mLinesBuffer = 0; + + int mLastNumNodes = 0; + int mLastNumSegs = 0; + + std::unique_ptr mAABBTree; + FShadowMap(const FShadowMap &) = delete; FShadowMap &operator=(FShadowMap &) = delete; };