diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 44422ad2d..e81f67731 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -273,7 +273,6 @@ sector_t *FGLRenderer::RenderView(player_t* player) fovratio = ratio; } - UpdateShadowMap(); retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true); } All.Unclock(); diff --git a/src/gl/renderer/gl_scene.cpp b/src/gl/renderer/gl_scene.cpp index 5d54b57c9..b5f2c7b92 100644 --- a/src/gl/renderer/gl_scene.cpp +++ b/src/gl/renderer/gl_scene.cpp @@ -152,6 +152,8 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came { R_SetupFrame (mainvp, r_viewwindow, camera); + UpdateShadowMap(); + // Render (potentially) multiple views for stereo 3d // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. auto vrmode = VRMode::GetVRMode(mainview && toscreen); diff --git a/src/gl/system/gl_buffers.cpp b/src/gl/system/gl_buffers.cpp index 9ca935269..39535fd03 100644 --- a/src/gl/system/gl_buffers.cpp +++ b/src/gl/system/gl_buffers.cpp @@ -65,7 +65,7 @@ void GLBuffer::Bind() } -void GLBuffer::SetData(size_t size, void *data, bool staticdata) +void GLBuffer::SetData(size_t size, const void *data, bool staticdata) { assert(nomap); // once it's mappable, it cannot be recreated anymore. Bind(); @@ -92,6 +92,12 @@ void GLBuffer::SetData(size_t size, void *data, bool staticdata) InvalidateBufferState(); } +void GLBuffer::SetSubData(size_t offset, size_t size, const void *data) +{ + Bind(); + glBufferSubData(mUseType, offset, size, data); +} + void GLBuffer::Map() { assert(nomap == false); // do not allow mapping of static buffers. Vulkan cannot do that so it should be blocked in OpenGL, too. diff --git a/src/gl/system/gl_buffers.h b/src/gl/system/gl_buffers.h index f2d636cf1..8231855b8 100644 --- a/src/gl/system/gl_buffers.h +++ b/src/gl/system/gl_buffers.h @@ -22,7 +22,8 @@ protected: GLBuffer(int usetype); ~GLBuffer(); - void SetData(size_t size, void *data, bool staticdata) override; + void SetData(size_t size, const void *data, bool staticdata) override; + void SetSubData(size_t offset, size_t size, const void *data) override; void Map() override; void Unmap() override; void Resize(size_t newsize) override; diff --git a/src/hwrenderer/data/buffers.h b/src/hwrenderer/data/buffers.h index 9707a6eea..b5707c229 100644 --- a/src/hwrenderer/data/buffers.h +++ b/src/hwrenderer/data/buffers.h @@ -47,7 +47,8 @@ public: IBuffer &operator=(const IBuffer &) = delete; virtual ~IBuffer() = default; - virtual void SetData(size_t size, void *data, bool staticdata = true) = 0; + virtual void SetData(size_t size, const void *data, bool staticdata = true) = 0; + virtual void SetSubData(size_t offset, size_t size, const void *data) = 0; virtual void *Lock(unsigned int size) = 0; virtual void Unlock() = 0; virtual void Resize(size_t newsize) = 0; diff --git a/src/hwrenderer/dynlights/hw_aabbtree.cpp b/src/hwrenderer/dynlights/hw_aabbtree.cpp index 919ed3ded..2d533f9b9 100644 --- a/src/hwrenderer/dynlights/hw_aabbtree.cpp +++ b/src/hwrenderer/dynlights/hw_aabbtree.cpp @@ -38,35 +38,36 @@ LevelAABBTree::LevelAABBTree() centroids.Push((v1 + v2) * 0.5f); } - // Create a list of level lines we want to add: - TArray line_elements; - for (unsigned int i = 0; i < level.lines.Size(); i++) + // Create the static subtree + if (!GenerateTree(¢roids[0], false)) + return; + + int staticroot = nodes.Size() - 1; + + dynamicStartNode = nodes.Size(); + dynamicStartLine = lines.Size(); + + // Create the dynamic subtree + if (GenerateTree(¢roids[0], true)) { - if (!level.lines[i].backsector) - { -#ifdef USE_POLYOBJ_SHADOWS - if (level.lines[i].sidedef[0] && (level.lines[i].sidedef[0]->Flags & WALLF_POLYOBJ)) - polylines.Push(i); - line_elements.Push(i); -#else - if (!level.lines[i].sidedef[0] || !(level.lines[i].sidedef[0]->Flags & WALLF_POLYOBJ)) - line_elements.Push(i); -#endif - } + int dynamicroot = nodes.Size() - 1; + + // Create a shared root node + FVector2 aabb_min, aabb_max; + const auto &left = nodes[staticroot]; + const auto &right = nodes[dynamicroot]; + aabb_min.X = MIN(left.aabb_left, right.aabb_left); + aabb_min.Y = MIN(left.aabb_top, right.aabb_top); + aabb_max.X = MAX(left.aabb_right, right.aabb_right); + aabb_max.Y = MAX(left.aabb_bottom, right.aabb_bottom); + nodes.Push({ aabb_min, aabb_max, staticroot, dynamicroot }); } - // GenerateTreeNode needs a buffer where it can store line indices temporarily when sorting lines into the left and right child AABB buckets - TArray work_buffer; - work_buffer.Resize(line_elements.Size() * 2); - - // Generate the AABB tree - GenerateTreeNode(&line_elements[0], (int)line_elements.Size(), ¢roids[0], &work_buffer[0]); - // Add the lines referenced by the leaf nodes - lines.Resize(level.lines.Size()); - for (unsigned int i = 0; i < level.lines.Size(); i++) + lines.Resize(mapLines.Size()); + for (unsigned int i = 0; i < mapLines.Size(); i++) { - const auto &line = level.lines[i]; + const auto &line = level.lines[mapLines[i]]; auto &treeline = lines[i]; treeline.x = (float)line.v1->fX(); @@ -76,13 +77,46 @@ LevelAABBTree::LevelAABBTree() } } +bool LevelAABBTree::GenerateTree(const FVector2 *centroids, bool dynamicsubtree) +{ + // Create a list of level lines we want to add: + TArray line_elements; + for (unsigned int i = 0; i < level.lines.Size(); i++) + { + if (!level.lines[i].backsector) + { + bool isPolyLine = level.lines[i].sidedef[0] && (level.lines[i].sidedef[0]->Flags & WALLF_POLYOBJ); + if (isPolyLine && dynamicsubtree) + { + line_elements.Push(mapLines.Size()); + mapLines.Push(i); + } + else if (!isPolyLine && !dynamicsubtree) + { + line_elements.Push(mapLines.Size()); + mapLines.Push(i); + } + } + } + + if (line_elements.Size() == 0) + return false; + + // GenerateTreeNode needs a buffer where it can store line indices temporarily when sorting lines into the left and right child AABB buckets + TArray work_buffer; + work_buffer.Resize(line_elements.Size() * 2); + + // Generate the AABB tree + GenerateTreeNode(&line_elements[0], (int)line_elements.Size(), centroids, &work_buffer[0]); + return true; +} + bool LevelAABBTree::Update() { bool modified = false; - for (unsigned int ii = 0; ii < polylines.Size(); ii++) + for (unsigned int i = dynamicStartLine; i < mapLines.Size(); i++) { - int i = polylines[ii]; - const auto &line = level.lines[i]; + const auto &line = level.lines[mapLines[i]]; AABBTreeLine treeline; treeline.x = (float)line.v1->fX(); @@ -95,10 +129,10 @@ bool LevelAABBTree::Update() TArray path = FindNodePath(i, nodes.Size() - 1); if (path.Size()) { - float x1 = (float)level.lines[i].v1->fX(); - float y1 = (float)level.lines[i].v1->fY(); - float x2 = (float)level.lines[i].v2->fX(); - float y2 = (float)level.lines[i].v2->fY(); + float x1 = (float)line.v1->fX(); + float y1 = (float)line.v1->fY(); + float x2 = (float)line.v2->fX(); + float y2 = (float)line.v2->fY(); int nodeIndex = path[0]; nodes[nodeIndex].aabb_left = MIN(x1, x2); @@ -122,7 +156,7 @@ bool LevelAABBTree::Update() } } } - return !modified; + return modified; } TArray LevelAABBTree::FindNodePath(unsigned int line, unsigned int node) @@ -165,7 +199,7 @@ double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end double hit_fraction = 1.0; // Walk the tree nodes - int stack[16]; + int stack[32]; int stack_pos = 1; stack[0] = nodes.Size() - 1; // root node is the last node in the list while (stack_pos > 0) @@ -183,7 +217,7 @@ double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end hit_fraction = MIN(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction); stack_pos--; } - else if (stack_pos == 16) + else if (stack_pos == 32) { stack_pos--; // stack overflow - tree is too deep! } @@ -269,15 +303,15 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c // Find bounding box and median of the lines FVector2 median = FVector2(0.0f, 0.0f); FVector2 aabb_min, aabb_max; - aabb_min.X = (float)level.lines[lines[0]].v1->fX(); - aabb_min.Y = (float)level.lines[lines[0]].v1->fY(); + aabb_min.X = (float)level.lines[mapLines[lines[0]]].v1->fX(); + aabb_min.Y = (float)level.lines[mapLines[lines[0]]].v1->fY(); aabb_max = aabb_min; for (int i = 0; i < num_lines; i++) { - float x1 = (float)level.lines[lines[i]].v1->fX(); - float y1 = (float)level.lines[lines[i]].v1->fY(); - float x2 = (float)level.lines[lines[i]].v2->fX(); - float y2 = (float)level.lines[lines[i]].v2->fY(); + float x1 = (float)level.lines[mapLines[lines[i]]].v1->fX(); + float y1 = (float)level.lines[mapLines[lines[i]]].v1->fY(); + float x2 = (float)level.lines[mapLines[lines[i]]].v2->fX(); + float y2 = (float)level.lines[mapLines[lines[i]]].v2->fY(); aabb_min.X = MIN(aabb_min.X, x1); aabb_min.X = MIN(aabb_min.X, x2); @@ -288,7 +322,7 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c aabb_max.Y = MAX(aabb_max.Y, y1); aabb_max.Y = MAX(aabb_max.Y, y2); - median += centroids[lines[i]]; + median += centroids[mapLines[lines[i]]]; } median /= (float)num_lines; @@ -324,7 +358,7 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c { int line_index = lines[i]; - float side = FVector3(centroids[lines[i]], 1.0f) | plane; + float side = FVector3(centroids[mapLines[lines[i]]], 1.0f) | plane; if (side >= 0.0f) { work_buffer[left_count] = line_index; diff --git a/src/hwrenderer/dynlights/hw_aabbtree.h b/src/hwrenderer/dynlights/hw_aabbtree.h index 5e6978d21..e00c702c0 100644 --- a/src/hwrenderer/dynlights/hw_aabbtree.h +++ b/src/hwrenderer/dynlights/hw_aabbtree.h @@ -42,18 +42,26 @@ public: // Constructs a tree for the current level LevelAABBTree(); - // Nodes in the AABB tree. Last node is the root node. - TArray nodes; - - // Line segments for the leaf nodes in the tree. - TArray lines; - // 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); bool Update(); + const void *Nodes() const { return nodes.Data(); } + const void *Lines() const { return lines.Data(); } + size_t NodesSize() const { return nodes.Size() * sizeof(AABBTreeNode); } + size_t LinesSize() const { return lines.Size() * sizeof(AABBTreeLine); } + + const void *DynamicNodes() const { return nodes.Data() + dynamicStartNode; } + const void *DynamicLines() const { return lines.Data() + dynamicStartLine; } + size_t DynamicNodesSize() const { return (nodes.Size() - dynamicStartNode) * sizeof(AABBTreeNode); } + size_t DynamicLinesSize() const { return (lines.Size() - dynamicStartLine) * sizeof(AABBTreeLine); } + size_t DynamicNodesOffset() const { return dynamicStartNode * sizeof(AABBTreeNode); } + size_t DynamicLinesOffset() const { return dynamicStartLine * sizeof(AABBTreeLine); } + private: + bool GenerateTree(const FVector2 *centroids, bool dynamicsubtree); + // Test if a ray overlaps an AABB node or not bool OverlapRayAABB(const DVector2 &ray_start2d, const DVector2 &ray_end2d, const AABBTreeNode &node); @@ -65,7 +73,16 @@ private: TArray FindNodePath(unsigned int line, unsigned int node); - TArray polylines; + // Nodes in the AABB tree. Last node is the root node. + TArray nodes; + + // Line segments for the leaf nodes in the tree. + TArray lines; + + int dynamicStartNode = 0; + int dynamicStartLine = 0; + + TArray mapLines; }; } // namespace diff --git a/src/hwrenderer/dynlights/hw_shadowmap.cpp b/src/hwrenderer/dynlights/hw_shadowmap.cpp index e43f73b24..453953639 100644 --- a/src/hwrenderer/dynlights/hw_shadowmap.cpp +++ b/src/hwrenderer/dynlights/hw_shadowmap.cpp @@ -155,7 +155,7 @@ bool IShadowMap::ValidateAABBTree() } if (mAABBTree) - return mAABBTree->Update(); + return true; mAABBTree.reset(new hwrenderer::LevelAABBTree()); return false; @@ -198,11 +198,16 @@ void IShadowMap::UploadAABBTree() { if (!mNodesBuffer) mNodesBuffer = screen->CreateDataBuffer(2, true); - mNodesBuffer->SetData(sizeof(hwrenderer::AABBTreeNode) * mAABBTree->nodes.Size(), &mAABBTree->nodes[0]); + mNodesBuffer->SetData(mAABBTree->NodesSize(), mAABBTree->Nodes()); if (!mLinesBuffer) mLinesBuffer = screen->CreateDataBuffer(3, true); - mLinesBuffer->SetData(sizeof(hwrenderer::AABBTreeLine) * mAABBTree->lines.Size(), &mAABBTree->lines[0]); + mLinesBuffer->SetData(mAABBTree->LinesSize(), mAABBTree->Lines()); + } + else if (mAABBTree->Update()) + { + mNodesBuffer->SetSubData(mAABBTree->DynamicNodesOffset(), mAABBTree->DynamicNodesSize(), mAABBTree->DynamicNodes()); + mLinesBuffer->SetSubData(mAABBTree->DynamicLinesOffset(), mAABBTree->DynamicLinesSize(), mAABBTree->DynamicLines()); } } diff --git a/wadsrc/static/shaders/glsl/shadowmap.fp b/wadsrc/static/shaders/glsl/shadowmap.fp index 4bc507c3d..036ff0836 100644 --- a/wadsrc/static/shaders/glsl/shadowmap.fp +++ b/wadsrc/static/shaders/glsl/shadowmap.fp @@ -109,7 +109,7 @@ float rayTest(vec2 ray_start, vec2 ray_end) // Walk the AABB binary tree searching for nodes touching the ray line segment's AABB box. // When it reaches a leaf node, use a line segment intersection test to see if we got a hit. - int stack[16]; + int stack[32]; int stack_pos = 1; stack[0] = nodes.length() - 1; while (stack_pos > 0) @@ -125,7 +125,7 @@ float rayTest(vec2 ray_start, vec2 ray_end) t = min(intersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), t); stack_pos--; } - else if (stack_pos == 16) + else if (stack_pos == 32) { stack_pos--; // stack overflow }