summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--game/geoData.cpp21
-rw-r--r--game/geoData.h7
-rw-r--r--game/network/rail.cpp2
-rw-r--r--game/network/rail.h2
-rw-r--r--game/scenary/foliage.cpp4
-rw-r--r--game/scenary/foliage.h4
-rw-r--r--game/scenary/illuminator.cpp2
-rw-r--r--game/scenary/illuminator.h2
-rw-r--r--game/terrain.cpp65
-rw-r--r--game/terrain.h14
-rw-r--r--game/vehicles/railVehicleClass.cpp4
-rw-r--r--game/vehicles/railVehicleClass.h4
-rw-r--r--game/water.cpp4
-rw-r--r--game/water.h2
-rw-r--r--gfx/aabb.h41
-rw-r--r--gfx/camera.cpp2
-rw-r--r--gfx/camera.h7
-rw-r--r--gfx/frustum.cpp43
-rw-r--r--gfx/frustum.h16
-rw-r--r--gfx/gl/sceneProvider.cpp2
-rw-r--r--gfx/gl/sceneProvider.h5
-rw-r--r--gfx/gl/sceneRenderer.cpp2
-rw-r--r--gfx/gl/shadowMapper.cpp40
-rw-r--r--gfx/renderable.cpp2
-rw-r--r--gfx/renderable.h5
-rw-r--r--lib/collections.h8
-rw-r--r--test/Jamfile.jam3
-rw-r--r--test/perf-terrain.cpp17
-rw-r--r--test/test-assetFactory.cpp8
-rw-r--r--test/test-geoData.cpp8
-rw-r--r--test/test-lib.cpp12
-rw-r--r--test/test-network.cpp2
-rw-r--r--test/test-render.cpp38
-rw-r--r--ui/editNetwork.cpp8
-rw-r--r--ui/editNetwork.h4
-rw-r--r--ui/gameMainSelector.cpp6
-rw-r--r--ui/gameMainSelector.h4
-rw-r--r--ui/gameMainWindow.cpp14
-rw-r--r--ui/gameMainWindow.h4
-rw-r--r--ui/worldOverlay.h3
40 files changed, 302 insertions, 139 deletions
diff --git a/game/geoData.cpp b/game/geoData.cpp
index 4291a64..5cea4dd 100644
--- a/game/geoData.cpp
+++ b/game/geoData.cpp
@@ -35,16 +35,16 @@ GeoData::loadFromAsciiGrid(const std::filesystem::path & input)
std::vector<VertexHandle> vertices;
vertices.reserve(ncols * nrows);
GeoData mesh;
- mesh.lowerExtent = {xllcorner, yllcorner, std::numeric_limits<GlobalDistance>::max()};
- mesh.upperExtent = {xllcorner + (cellsize * (ncols - 1)), yllcorner + (cellsize * (nrows - 1)),
- std::numeric_limits<GlobalDistance>::min()};
+ mesh.extents = {{xllcorner, yllcorner, std::numeric_limits<GlobalDistance>::max()},
+ {xllcorner + (cellsize * (ncols - 1)), yllcorner + (cellsize * (nrows - 1)),
+ std::numeric_limits<GlobalDistance>::min()}};
for (size_t row = 0; row < nrows; ++row) {
for (size_t col = 0; col < ncols; ++col) {
float heightf = 0;
f >> heightf;
const auto height = static_cast<GlobalDistance>(std::round(heightf * 1000.F));
- mesh.upperExtent.z = std::max(mesh.upperExtent.z, height);
- mesh.lowerExtent.z = std::min(mesh.lowerExtent.z, height);
+ mesh.extents.max.z = std::max(mesh.extents.max.z, height);
+ mesh.extents.min.z = std::min(mesh.extents.min.z, height);
vertices.push_back(mesh.add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height}));
}
}
@@ -78,8 +78,7 @@ GeoData::createFlat(GlobalPosition2D lower, GlobalPosition2D upper, GlobalDistan
assert((upper - lower) % GRID_SIZE == GlobalPosition2D {});
GeoData mesh;
- mesh.lowerExtent = {lower, h};
- mesh.upperExtent = {upper, h};
+ mesh.extents = {{lower, h}, {upper, h}};
std::vector<VertexHandle> vertices;
for (GlobalDistance row = lower.x; row <= upper.x; row += GRID_SIZE) {
@@ -120,7 +119,7 @@ GeoData::intersectRay(const Ray<GlobalPosition3D> & ray, FaceHandle face) const
{
GeoData::IntersectionResult out;
walkUntil(PointFace {ray.start, face},
- ray.start.xy() + (ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())),
+ ray.start.xy() + (ray.direction.xy() * ::difference(extents.max.xy(), extents.min.xy())),
[&out, &ray, this](const auto & step) {
BaryPosition bari {};
RelativeDistance dist {};
@@ -325,9 +324,9 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
if (triangleStrip.size() < 3) {
return {};
}
- const auto stripMinMax = std::ranges::minmax(triangleStrip, {}, &GlobalPosition3D::z);
- lowerExtent.z = std::min(upperExtent.z, stripMinMax.min.z);
- upperExtent.z = std::max(upperExtent.z, stripMinMax.max.z);
+ for (const auto & vertex : triangleStrip) {
+ extents += vertex;
+ }
class SetHeights {
public:
diff --git a/game/geoData.h b/game/geoData.h
index b2a75bd..0ff0c42 100644
--- a/game/geoData.h
+++ b/game/geoData.h
@@ -2,6 +2,7 @@
#include "collections.h" // IWYU pragma: keep IterableCollection
#include "geoDataMesh.h"
+#include "gfx/aabb.h"
#include "surface.h"
#include <filesystem>
#include <glm/vec2.hpp>
@@ -57,10 +58,10 @@ public:
std::set<FaceHandle> setHeights(std::span<const GlobalPosition3D> triangleStrip, const SetHeightsOpts &);
- [[nodiscard]] auto
+ [[nodiscard]] auto &
getExtents() const
{
- return std::tie(lowerExtent, upperExtent);
+ return extents;
}
template<typename HandleT>
@@ -80,5 +81,5 @@ protected:
virtual void afterChange();
private:
- GlobalPosition3D lowerExtent {}, upperExtent {};
+ AxisAlignedBoundingBox<GlobalDistance> extents;
};
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index d7de231..2a18b9a 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -166,7 +166,7 @@ namespace {
}
void
-RailLinks::render(const SceneShader & shader) const
+RailLinks::render(const SceneShader & shader, const Frustum &) const
{
if (!links.objects.empty()) {
texture->bind();
diff --git a/game/network/rail.h b/game/network/rail.h
index fa64eda..4aef9e3 100644
--- a/game/network/rail.h
+++ b/game/network/rail.h
@@ -75,7 +75,7 @@ public:
RailLinks();
std::shared_ptr<RailLink> addLinksBetween(GlobalPosition3D start, GlobalPosition3D end);
- void render(const SceneShader &) const override;
+ void render(const SceneShader &, const Frustum &) const override;
[[nodiscard]] const Surface * getBaseSurface() const override;
[[nodiscard]] RelativeDistance getBaseWidth() const override;
diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp
index a0ec576..159a078 100644
--- a/game/scenary/foliage.cpp
+++ b/game/scenary/foliage.cpp
@@ -29,7 +29,7 @@ Foliage::updateStencil(const ShadowStenciller & ss) const
}
void
-Foliage::render(const SceneShader & shader) const
+Foliage::render(const SceneShader & shader, const Frustum &) const
{
if (const auto count = instances.size()) {
shader.basicInst.use();
@@ -41,7 +41,7 @@ Foliage::render(const SceneShader & shader) const
}
void
-Foliage::shadows(const ShadowMapper & mapper) const
+Foliage::shadows(const ShadowMapper & mapper, const Frustum &) const
{
if (const auto count = instances.size()) {
const auto dimensions = bodyMesh->getDimensions();
diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h
index 5da63f0..71bc734 100644
--- a/game/scenary/foliage.h
+++ b/game/scenary/foliage.h
@@ -24,8 +24,8 @@ public:
};
mutable InstanceVertices<LocationVertex> instances;
- void render(const SceneShader &) const override;
- void shadows(const ShadowMapper &) const override;
+ void render(const SceneShader &, const Frustum &) const override;
+ void shadows(const ShadowMapper &, const Frustum &) const override;
void updateStencil(const ShadowStenciller &) const override;
glTexture shadowStencil = ShadowStenciller::createStencilTexture(256, 256);
diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp
index e3810ec..f1a02b2 100644
--- a/game/scenary/illuminator.cpp
+++ b/game/scenary/illuminator.cpp
@@ -59,7 +59,7 @@ Illuminator::postLoad()
}
void
-Illuminator::render(const SceneShader & shader) const
+Illuminator::render(const SceneShader & shader, const Frustum &) const
{
if (const auto count = instances.size()) {
shader.basicInst.use();
diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h
index 44bd583..47ce337 100644
--- a/game/scenary/illuminator.h
+++ b/game/scenary/illuminator.h
@@ -45,7 +45,7 @@ public:
mutable InstanceVertices<LocationVertex> instances;
mutable InstanceVertices<SpotLightVertex> instancesSpotLight;
mutable InstanceVertices<PointLightVertex> instancesPointLight;
- void render(const SceneShader &) const override;
+ void render(const SceneShader &, const Frustum &) const override;
void lights(const SceneShader &) const override;
protected:
diff --git a/game/terrain.cpp b/game/terrain.cpp
index f7de6fd..f10aac6 100644
--- a/game/terrain.cpp
+++ b/game/terrain.cpp
@@ -1,4 +1,5 @@
#include "terrain.h"
+#include "gfx/frustum.h"
#include <algorithm>
#include <gfx/gl/sceneShader.h>
#include <gfx/gl/shadowMapper.h>
@@ -13,6 +14,7 @@
#include <vector>
static constexpr RGB OPEN_SURFACE {-1};
+static constexpr GlobalDistance TILE_SIZE = 1024 * 1024; // ~1km, power of 2, fast divide
template<>
VertexArrayObject &
@@ -28,21 +30,26 @@ Terrain::SurfaceKey::operator<(const SurfaceKey & other) const
< std::tie(other.surface, other.basePosition.x, other.basePosition.y);
}
-void
-Terrain::generateMeshes()
+inline void
+Terrain::copyVerticesToBuffer() const
{
- constexpr GlobalDistance TILE_SIZE = 1024 * 1024; // ~1km, power of 2, fast divide
-
std::ranges::transform(all_vertices(), glMappedBufferWriter<Vertex> {GL_ARRAY_BUFFER, verticesBuffer, n_vertices()},
[this](const auto & vertex) {
return Vertex {point(vertex), normal(vertex)};
});
+}
+
+inline GlobalPosition2D
+Terrain::getTile(const FaceHandle & face) const
+{
+ return point(*cfv_begin(face)).xy() / TILE_SIZE;
+};
- std::map<SurfaceKey, std::vector<GLuint>> surfaceIndices;
- const auto getTile = [this](FaceHandle face) {
- return point(*fv_begin(face)).xy() / TILE_SIZE;
- };
- const auto indexBySurfaceAndTile = std::views::transform([this, &getTile](const auto & faceItr) {
+Terrain::SurfaceIndices
+Terrain::mapSurfaceFacesToIndices() const
+{
+ SurfaceIndices surfaceIndices;
+ const auto indexBySurfaceAndTile = std::views::transform([this](const auto & faceItr) {
return std::pair<SurfaceKey, FaceHandle> {{getSurface(*faceItr), getTile(*faceItr)}, *faceItr};
});
const auto chunkBySurfaceAndTile = std::views::chunk_by([](const auto & face1, const auto & face2) {
@@ -61,7 +68,12 @@ Terrain::generateMeshes()
std::ranges::transform(fv_range(face), push, &OpenMesh::VertexHandle::idx);
}
}
+ return surfaceIndices;
+}
+void
+Terrain::copyIndicesToBuffers(const SurfaceIndices & surfaceIndices)
+{
for (const auto & [surfaceKey, indices] : surfaceIndices) {
auto meshItr = meshes.find(surfaceKey);
if (meshItr == meshes.end()) {
@@ -77,7 +89,16 @@ Terrain::generateMeshes()
.data(verticesBuffer, GL_ARRAY_BUFFER);
}
meshItr->second.count = static_cast<GLsizei>(indices.size());
+ meshItr->second.aabb = AxisAlignedBoundingBox<GlobalDistance>::fromPoints(
+ indices | std::views::transform([this](const auto vertex) {
+ return this->point(VertexHandle {static_cast<int>(vertex)});
+ }));
}
+}
+
+void
+Terrain::pruneOrphanMeshes(const SurfaceIndices & surfaceIndices)
+{
if (meshes.size() > surfaceIndices.size()) {
std::erase_if(meshes, [&surfaceIndices](const auto & mesh) {
return !surfaceIndices.contains(mesh.first);
@@ -86,6 +107,15 @@ Terrain::generateMeshes()
}
void
+Terrain::generateMeshes()
+{
+ copyVerticesToBuffer();
+ const auto surfaceIndices = mapSurfaceFacesToIndices();
+ copyIndicesToBuffers(surfaceIndices);
+ pruneOrphanMeshes(surfaceIndices);
+}
+
+void
Terrain::tick(TickDuration)
{
}
@@ -97,9 +127,10 @@ Terrain::afterChange()
}
void
-Terrain::render(const SceneShader & shader) const
+Terrain::render(const SceneShader & shader, const Frustum & frustum) const
{
grass->bind();
+
const auto chunkBySurface = std::views::chunk_by([](const auto & itr1, const auto & itr2) {
return itr1.first.surface == itr2.first.surface;
});
@@ -107,20 +138,24 @@ Terrain::render(const SceneShader & shader) const
const auto surface = surfaceRange.front().first.surface;
shader.landmass.use(surface ? surface->colorBias : OPEN_SURFACE);
for (const auto & sab : surfaceRange) {
- glBindVertexArray(sab.second.vertexArray);
- glDrawElements(GL_TRIANGLES, sab.second.count, GL_UNSIGNED_INT, nullptr);
+ if (frustum.contains(sab.second.aabb)) {
+ glBindVertexArray(sab.second.vertexArray);
+ glDrawElements(GL_TRIANGLES, sab.second.count, GL_UNSIGNED_INT, nullptr);
+ }
}
}
glBindVertexArray(0);
}
void
-Terrain::shadows(const ShadowMapper & shadowMapper) const
+Terrain::shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const
{
shadowMapper.landmess.use();
for (const auto & [surface, sab] : meshes) {
- glBindVertexArray(sab.vertexArray);
- glDrawElements(GL_TRIANGLES, sab.count, GL_UNSIGNED_INT, nullptr);
+ if (frustum.shadedBy(sab.aabb)) {
+ glBindVertexArray(sab.vertexArray);
+ glDrawElements(GL_TRIANGLES, sab.count, GL_UNSIGNED_INT, nullptr);
+ }
}
glBindVertexArray(0);
}
diff --git a/game/terrain.h b/game/terrain.h
index f5b1b32..1a63296 100644
--- a/game/terrain.h
+++ b/game/terrain.h
@@ -16,8 +16,8 @@ public:
generateMeshes();
}
- void render(const SceneShader & shader) const override;
- void shadows(const ShadowMapper &) const override;
+ void render(const SceneShader & shader, const Frustum &) const override;
+ void shadows(const ShadowMapper &, const Frustum &) const override;
void tick(TickDuration) override;
@@ -35,14 +35,22 @@ private:
glVertexArray vertexArray;
glBuffer indicesBuffer;
GLsizei count;
+ AxisAlignedBoundingBox<GlobalDistance> aabb;
};
struct SurfaceKey {
const Surface * surface;
GlobalPosition2D basePosition;
- bool operator<(const SurfaceKey &) const;
+ inline bool operator<(const SurfaceKey &) const;
};
+ using SurfaceIndices = std::map<SurfaceKey, std::vector<GLuint>>;
+ void copyVerticesToBuffer() const;
+ [[nodiscard]] SurfaceIndices mapSurfaceFacesToIndices() const;
+ void copyIndicesToBuffers(const SurfaceIndices &);
+ void pruneOrphanMeshes(const SurfaceIndices &);
+ [[nodiscard]] inline GlobalPosition2D getTile(const FaceHandle &) const;
+
glBuffer verticesBuffer;
std::map<SurfaceKey, SurfaceArrayBuffer> meshes;
Texture::Ptr grass = std::make_shared<Texture>("grass.png");
diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp
index 34c1359..162a29a 100644
--- a/game/vehicles/railVehicleClass.cpp
+++ b/game/vehicles/railVehicleClass.cpp
@@ -33,7 +33,7 @@ RailVehicleClass::postLoad()
}
void
-RailVehicleClass::render(const SceneShader & shader) const
+RailVehicleClass::render(const SceneShader & shader, const Frustum &) const
{
if (const auto count = static_cast<GLsizei>(instances.size())) {
if (texture) {
@@ -47,7 +47,7 @@ RailVehicleClass::render(const SceneShader & shader) const
}
void
-RailVehicleClass::shadows(const ShadowMapper & mapper) const
+RailVehicleClass::shadows(const ShadowMapper & mapper, const Frustum &) const
{
if (const auto count = static_cast<GLsizei>(instances.size())) {
mapper.dynamicPointInst.use();
diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h
index 88f08c5..6eb4ca5 100644
--- a/game/vehicles/railVehicleClass.h
+++ b/game/vehicles/railVehicleClass.h
@@ -14,8 +14,8 @@ class Location;
class RailVehicleClass : public Renderable, public Asset {
public:
- void render(const SceneShader & shader) const override;
- void shadows(const ShadowMapper & shadowMapper) const override;
+ void render(const SceneShader & shader, const Frustum &) const override;
+ void shadows(const ShadowMapper & shadowMapper, const Frustum &) const override;
struct LocationVertex {
glm::mat3 body, front, back;
diff --git a/game/water.cpp b/game/water.cpp
index f720e3e..527e85a 100644
--- a/game/water.cpp
+++ b/game/water.cpp
@@ -82,7 +82,7 @@ Water::generateMeshes()
const auto pos = (p * TILE_SIZE) + GlobalPosition2D {x, y};
const auto v = vertexIndex.emplace(pos, vertices.size());
if (v.second) {
- const auto cpos = glm::clamp(pos, std::get<0>(extents).xy(), std::get<1>(extents).xy());
+ const auto cpos = glm::clamp(pos, extents.min.xy(), extents.max.xy());
vertices.emplace_back(geoData->positionAt(cpos));
}
*out++ = static_cast<unsigned int>(v.first->second);
@@ -102,7 +102,7 @@ Water::tick(TickDuration dur)
}
void
-Water::render(const SceneShader & shader) const
+Water::render(const SceneShader & shader, const Frustum &) const
{
shader.water.use(waveCycle);
water->bind();
diff --git a/game/water.h b/game/water.h
index ba46703..f9fe080 100644
--- a/game/water.h
+++ b/game/water.h
@@ -16,7 +16,7 @@ class Water : public WorldObject, public Renderable {
public:
explicit Water(std::shared_ptr<GeoData>);
- void render(const SceneShader & shader) const override;
+ void render(const SceneShader & shader, const Frustum &) const override;
void tick(TickDuration) override;
float waveCycle {0.F};
diff --git a/gfx/aabb.h b/gfx/aabb.h
new file mode 100644
index 0000000..ce15a0f
--- /dev/null
+++ b/gfx/aabb.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "maths.h"
+#include <algorithm>
+#include <tuple>
+
+template<Arithmetic T, glm::qualifier Q = glm::defaultp> class AxisAlignedBoundingBox {
+public:
+ using V = glm::vec<3, T, Q>;
+ AxisAlignedBoundingBox() = default;
+
+ AxisAlignedBoundingBox(const V & min, const V & max) : min {min}, max {max} { }
+
+ AxisAlignedBoundingBox &
+ operator+=(const V & point)
+ {
+ min = glm::min(min, point);
+ max = glm::max(max, point);
+ return *this;
+ }
+
+ AxisAlignedBoundingBox
+ operator-(const V & viewPoint) const
+ {
+ return {min - viewPoint, max - viewPoint};
+ }
+
+ [[nodiscard]] static AxisAlignedBoundingBox
+ fromPoints(auto && points)
+ {
+ using Limits = std::numeric_limits<T>;
+ static constexpr const auto INITIAL = std::make_pair(V {Limits::max()}, V {Limits::min()});
+ return std::make_from_tuple<AxisAlignedBoundingBox<T, Q>>(
+ std::ranges::fold_left(points, INITIAL, [](const auto & prev, const auto & point) {
+ auto & [min, max] = prev;
+ return std::make_pair(glm::min(min, point), glm::max(max, point));
+ }));
+ }
+
+ V min {}, max {};
+};
diff --git a/gfx/camera.cpp b/gfx/camera.cpp
index cc6a2dd..f01054a 100644
--- a/gfx/camera.cpp
+++ b/gfx/camera.cpp
@@ -12,7 +12,7 @@ Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance nea
Camera::Camera(GlobalPosition3D pos, GlobalDistance near, GlobalDistance far, const glm::mat4 & view,
const glm::mat4 & projection) :
- Frustum {view, projection}, position {pos}, forward {::north}, up {::up}, near {near}, far {far}
+ Frustum {pos, view, projection}, forward {::north}, up {::up}, near {near}, far {far}
{
}
diff --git a/gfx/camera.h b/gfx/camera.h
index a52ec8b..d1bfc82 100644
--- a/gfx/camera.h
+++ b/gfx/camera.h
@@ -59,12 +59,6 @@ public:
return forward;
}
- [[nodiscard]] auto
- getPosition() const
- {
- return position;
- }
-
[[nodiscard]] std::array<GlobalPosition4D, 4> extentsAtDist(GlobalDistance) const;
[[nodiscard]] static Direction3D upFromForward(const Direction3D & forward);
@@ -74,7 +68,6 @@ private:
const glm::mat4 & projection);
void updateView();
- GlobalPosition3D position;
Direction3D forward;
Direction3D up;
GlobalDistance near, far;
diff --git a/gfx/frustum.cpp b/gfx/frustum.cpp
index 9e046f6..faa676d 100644
--- a/gfx/frustum.cpp
+++ b/gfx/frustum.cpp
@@ -3,10 +3,10 @@
#include <collections.h>
#include <glm/ext/matrix_transform.hpp>
-static constexpr auto PLANES = std::array {0, 1, 2} * std::array {1.F, -1.F};
+static constexpr auto PLANES = std::array {0, 1, 2} * std::array {-1.F, 1.F};
-Frustum::Frustum(const glm::mat4 & view, const glm::mat4 & projection) :
- view {view}, projection {projection}, viewProjection {}, inverseViewProjection {}, planes {}
+Frustum::Frustum(const GlobalPosition3D & pos, const glm::mat4 & view, const glm::mat4 & projection) :
+ position {pos}, view {view}, projection {projection}, viewProjection {}, inverseViewProjection {}, planes {}
{
updateCache();
}
@@ -18,6 +18,43 @@ Frustum::updateView(const glm::mat4 & newView)
updateCache();
}
+bool
+Frustum::contains(const BoundingBox & aabb) const
+{
+ return boundByPlanes(aabb, FACES);
+}
+
+bool
+Frustum::shadedBy(const BoundingBox & aabb) const
+{
+ return boundByPlanes(aabb, FACES - 1);
+}
+
+bool
+Frustum::boundByPlanes(const BoundingBox & aabb, size_t nplanes) const
+{
+ static constexpr auto EXTENT_CORNER_IDXS = [] {
+ using Extent = GlobalPosition3D BoundingBox::*;
+ constexpr auto EXTENTS = std::array {&BoundingBox::min, &BoundingBox::max};
+ std::array<glm::vec<3, Extent>, 2ZU * 2ZU * 2ZU> out {};
+ std::ranges::copy(std::views::cartesian_product(EXTENTS, EXTENTS, EXTENTS)
+ | std::views::transform(
+ std::make_from_tuple<glm::vec<3, Extent>, std::tuple<Extent, Extent, Extent>>),
+ out.begin());
+ return out;
+ }();
+
+ const std::array<RelativePosition4D, 8> corners
+ = EXTENT_CORNER_IDXS * [relativeAabb = aabb - position](auto idxs) -> glm::vec4 {
+ return {(relativeAabb.*(idxs.x)).x, (relativeAabb.*(idxs.y)).y, (relativeAabb.*(idxs.z)).z, 1.F};
+ };
+ return std::ranges::none_of(std::span(planes).subspan(0, nplanes), [&corners](const auto & frustumPlane) {
+ return (std::ranges::all_of(corners, [&frustumPlane](const auto & corner) {
+ return glm::dot(frustumPlane, corner) < 0.F;
+ }));
+ });
+}
+
void
Frustum::updateCache()
{
diff --git a/gfx/frustum.h b/gfx/frustum.h
index 25dcc18..a2d90e9 100644
--- a/gfx/frustum.h
+++ b/gfx/frustum.h
@@ -1,11 +1,13 @@
#pragma once
+#include "aabb.h"
+#include "config/types.h"
#include <array>
#include <glm/mat4x4.hpp>
class Frustum {
public:
- Frustum(const glm::mat4 & view, const glm::mat4 & projection);
+ Frustum(const GlobalPosition3D & pos, const glm::mat4 & view, const glm::mat4 & projection);
[[nodiscard]] auto &
getFrustumPlanes() const
@@ -19,12 +21,24 @@ public:
return viewProjection;
}
+ [[nodiscard]] auto
+ getPosition() const
+ {
+ return position;
+ }
+
void updateView(const glm::mat4 & view);
+ using BoundingBox = AxisAlignedBoundingBox<GlobalDistance>;
+ [[nodiscard]] bool contains(const BoundingBox &) const;
+ [[nodiscard]] bool shadedBy(const BoundingBox &) const;
+
protected:
static constexpr size_t FACES = 6;
void updateCache();
+ [[nodiscard]] bool boundByPlanes(const BoundingBox &, size_t nplanes) const;
+ GlobalPosition3D position;
glm::mat4 view, projection;
glm::mat4 viewProjection, inverseViewProjection;
std::array<glm::vec4, FACES> planes;
diff --git a/gfx/gl/sceneProvider.cpp b/gfx/gl/sceneProvider.cpp
index 4e271db..e01532e 100644
--- a/gfx/gl/sceneProvider.cpp
+++ b/gfx/gl/sceneProvider.cpp
@@ -9,6 +9,6 @@ SceneProvider::environment(const SceneShader &, const SceneRenderer & renderer)
}
void
-SceneProvider::shadows(const ShadowMapper &) const
+SceneProvider::shadows(const ShadowMapper &, const Frustum &) const
{
}
diff --git a/gfx/gl/sceneProvider.h b/gfx/gl/sceneProvider.h
index f5e8e99..f6b7009 100644
--- a/gfx/gl/sceneProvider.h
+++ b/gfx/gl/sceneProvider.h
@@ -5,6 +5,7 @@
class SceneRenderer;
class ShadowMapper;
class SceneShader;
+class Frustum;
class SceneProvider {
public:
@@ -12,8 +13,8 @@ public:
virtual ~SceneProvider() = default;
DEFAULT_MOVE_COPY(SceneProvider);
- virtual void content(const SceneShader &) const = 0;
+ virtual void content(const SceneShader &, const Frustum &) const = 0;
virtual void environment(const SceneShader &, const SceneRenderer &) const;
virtual void lights(const SceneShader &) const = 0;
- virtual void shadows(const ShadowMapper &) const;
+ virtual void shadows(const ShadowMapper &, const Frustum &) const;
};
diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp
index b2a7d78..188c4fd 100644
--- a/gfx/gl/sceneRenderer.cpp
+++ b/gfx/gl/sceneRenderer.cpp
@@ -71,7 +71,7 @@ SceneRenderer::render(const SceneProvider & scene) const
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- scene.content(shader);
+ scene.content(shader, camera);
// Environment pass -
// * ambient - clears illumination texture - see setAmbientLight
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index 908dbdb..6525f76 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -1,6 +1,7 @@
#include "shadowMapper.h"
#include "collections.h"
#include "game/gamestate.h"
+#include "gfx/aabb.h"
#include "gfx/gl/shaders/fs-shadowDynamicPointInstWithTextures.h"
#include "gfx/gl/shaders/fs-shadowDynamicPointStencil.h"
#include "gfx/gl/shaders/gs-commonShadowPoint.h"
@@ -19,7 +20,6 @@
#include "maths.h"
#include "sceneProvider.h"
#include "sceneShader.h"
-#include "sorting.h"
#include <gfx/camera.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
@@ -56,7 +56,7 @@ constexpr auto shadowBands
= []<GlobalDistance... ints>(const float scaleFactor, std::integer_sequence<GlobalDistance, ints...>) {
const auto base = 10'000'000 / pow(scaleFactor, sizeof...(ints) - 1);
return std::array {1, static_cast<GlobalDistance>((base * pow(scaleFactor, ints)))...};
- }(6.6F, std::make_integer_sequence<GlobalDistance, ShadowMapper::SHADOW_BANDS>());
+ }(4.6F, std::make_integer_sequence<GlobalDistance, ShadowMapper::SHADOW_BANDS>());
static_assert(shadowBands.front() == 1);
static_assert(shadowBands.back() == 10'000'000);
@@ -102,30 +102,30 @@ ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, co
const auto bandViewExtents = getBandViewExtents(camera, lightViewDir);
Definitions out;
Sizes sizes;
- std::transform(bandViewExtents.begin(), std::prev(bandViewExtents.end()), std::next(bandViewExtents.begin()),
- std::back_inserter(out),
- [bands = bandViewExtents.size() - 2, &lightViewDir, &sizes](const auto & near, const auto & far) mutable {
- const auto extents_minmax
- = [extents = std::span {near.begin(), far.end()}](auto && comp, RelativeDistance extra) {
- const auto mm = std::minmax_element(extents.begin(), extents.end(), comp);
- return std::make_pair(comp.get(*mm.first) - extra, comp.get(*mm.second) + extra);
- };
- const std::array extents = {extents_minmax(CompareBy {0}, 0), extents_minmax(CompareBy {1}, 0),
- extents_minmax(CompareBy {2}, 10'000)};
-
- const auto lightProjection = [](const auto & x, const auto & y, const auto & z) {
- return glm::ortho(x.first, x.second, y.first, y.second, -z.second, -z.first);
- }(extents[0], extents[1], extents[2]);
-
- sizes.emplace_back(extents[0].second - extents[0].first, extents[1].second - extents[1].first,
- extents[2].second - extents[2].first);
+ using ExtentsBoundingBox = AxisAlignedBoundingBox<RelativeDistance>;
+ std::ranges::transform(bandViewExtents | std::views::pairwise, std::back_inserter(out),
+ [&lightViewDir, &sizes](const auto & band) mutable {
+ const auto & [near, far] = band;
+ auto extents = ExtentsBoundingBox::fromPoints(std::span {near.begin(), far.end()});
+ extents.min.z -= 10'000.F;
+ extents.max.z += 10'000.F;
+ const auto lightProjection = glm::ortho(
+ extents.min.x, extents.max.x, extents.min.y, extents.max.y, -extents.max.z, -extents.min.z);
+ sizes.emplace_back(extents.max - extents.min);
return lightProjection * lightViewDir;
});
for (const auto p : std::initializer_list<const ShadowProgram *> {
&landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures, &stencilShadowProgram}) {
p->setView(out, sizes, lightViewPoint);
}
- scene.shadows(*this);
+ ExtentsBoundingBox extents {lightViewPoint, lightViewPoint};
+ for (const auto & point : bandViewExtents.back()) {
+ extents += point;
+ }
+ const auto lightProjection
+ = glm::ortho(extents.min.x, extents.max.x, extents.min.y, extents.max.y, -extents.max.z, -extents.min.z);
+ Frustum frustum {lightViewPoint, lightViewDir, lightProjection};
+ scene.shadows(*this, frustum);
glCullFace(GL_BACK);
diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp
index 3594968..27f2459 100644
--- a/gfx/renderable.cpp
+++ b/gfx/renderable.cpp
@@ -6,7 +6,7 @@ Renderable::lights(const SceneShader &) const
}
void
-Renderable::shadows(const ShadowMapper &) const
+Renderable::shadows(const ShadowMapper &, const Frustum &) const
{
}
diff --git a/gfx/renderable.h b/gfx/renderable.h
index 83522e3..140c570 100644
--- a/gfx/renderable.h
+++ b/gfx/renderable.h
@@ -3,6 +3,7 @@
#include <special_members.h>
class SceneShader;
+class Frustum;
class ShadowMapper;
class ShadowStenciller;
@@ -12,9 +13,9 @@ public:
virtual ~Renderable() = default;
DEFAULT_MOVE_COPY(Renderable);
- virtual void render(const SceneShader & shader) const = 0;
+ virtual void render(const SceneShader & shader, const Frustum &) const = 0;
virtual void lights(const SceneShader & shader) const;
- virtual void shadows(const ShadowMapper & shadowMapper) const;
+ virtual void shadows(const ShadowMapper & shadowMapper, const Frustum &) const;
virtual void updateStencil(const ShadowStenciller & lightDir) const;
};
diff --git a/lib/collections.h b/lib/collections.h
index b921424..e182af5 100644
--- a/lib/collections.h
+++ b/lib/collections.h
@@ -140,16 +140,16 @@ vectorOfN(std::integral auto N, T start = {}, T step = 1)
template<template<typename...> typename Rtn = std::vector, typename In>
[[nodiscard]] auto
-materializeRange(const In begin, const In end)
+materializeRange(In && begin, In && end)
{
- return Rtn(begin, end);
+ return Rtn(std::forward<In>(begin), std::forward<In>(end));
}
template<template<typename...> typename Rtn = std::vector, IterableCollection In>
[[nodiscard]] auto
-materializeRange(const In & in)
+materializeRange(In && in)
{
- return materializeRange<Rtn>(in.begin(), in.end());
+ return materializeRange<Rtn>(std::forward<In>(in).begin(), std::forward<In>(in).end());
}
template<template<typename...> typename Rtn = std::vector, typename In>
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index 8219398..bedc2ad 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -71,5 +71,6 @@ explicit perf-assetFactory ;
explicit perf-persistence ;
explicit perf-geoData ;
explicit perf-instancing ;
-alias perf : perf-assetFactory perf-persistence perf-geoData perf-instancing ;
+explicit perf-terrain ;
+alias perf : perf-assetFactory perf-persistence perf-geoData perf-instancing perf-terrain ;
explicit perf ;
diff --git a/test/perf-terrain.cpp b/test/perf-terrain.cpp
index 81cb16c..e75f80b 100644
--- a/test/perf-terrain.cpp
+++ b/test/perf-terrain.cpp
@@ -1,4 +1,7 @@
#include "game/terrain.h"
+#include "gfx/camera.h"
+#include "gfx/frustum.h"
+#include "gfx/gl/sceneShader.h"
#include "testMainWindow.h"
#include <benchmark/benchmark.h>
@@ -14,8 +17,22 @@ namespace {
terrain.generateMeshes();
}
}
+
+ void
+ terrainRender(benchmark::State & state)
+ {
+ Terrain terrain {GeoData::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")};
+ SceneShader shader;
+ Camera cam {terrain.getExtents().min + GlobalPosition3D {0, 0, 10000}, 45.F, 1.F, 1, 10000};
+ cam.setForward(::north + ::east);
+
+ for (auto _ : state) {
+ terrain.render(shader, cam);
+ }
+ }
}
BENCHMARK(terrainMeshgen);
+BENCHMARK(terrainRender);
BENCHMARK_MAIN();
diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp
index 6036721..9bade82 100644
--- a/test/test-assetFactory.cpp
+++ b/test/test-assetFactory.cpp
@@ -38,10 +38,10 @@ public:
}
void
- content(const SceneShader & shader) const override
+ content(const SceneShader & shader, const Frustum & frustum) const override
{
shader.basic.use(Location {{0, 0, 0}, {0, 0, 0}});
- objects.apply(&Renderable::render, shader);
+ objects.apply(&Renderable::render, shader, frustum);
}
void
@@ -58,10 +58,10 @@ public:
}
void
- shadows(const ShadowMapper & mapper) const override
+ shadows(const ShadowMapper & mapper, const Frustum & frustum) const override
{
mapper.dynamicPoint.use(Location {{0, 0, 0}, {0, 0, 0}});
- objects.apply(&Renderable::shadows, mapper);
+ objects.apply(&Renderable::shadows, mapper, frustum);
}
void
diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp
index 2332513..e3ef9ad 100644
--- a/test/test-geoData.cpp
+++ b/test/test-geoData.cpp
@@ -255,9 +255,9 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson<DeformTerrainData>("geoData/deform/
const Terrain terrain;
void
- content(const SceneShader & shader) const override
+ content(const SceneShader & shader, const Frustum & frustum) const override
{
- terrain.render(shader);
+ terrain.render(shader, frustum);
}
void
@@ -273,9 +273,9 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson<DeformTerrainData>("geoData/deform/
}
void
- shadows(const ShadowMapper & shadowMapper) const override
+ shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const override
{
- terrain.shadows(shadowMapper);
+ terrain.shadows(shadowMapper, frustum);
}
};
diff --git a/test/test-lib.cpp b/test/test-lib.cpp
index 17c0f63..ec91f6e 100644
--- a/test/test-lib.cpp
+++ b/test/test-lib.cpp
@@ -6,6 +6,7 @@
#include <stream_support.h>
#include <collections.h>
+#include <gfx/aabb.h>
#include <glArrays.h>
#include <glad/gl.h>
#include <set>
@@ -110,3 +111,14 @@ BOOST_DATA_TEST_CASE(mergeCloseInts,
tolerance)));
BOOST_CHECK_EQUAL_COLCOL(mutableCollection, expected);
}
+
+BOOST_AUTO_TEST_CASE(aabb_from_points)
+{
+ const auto aabb = AxisAlignedBoundingBox<GlobalDistance>::fromPoints(std::vector<GlobalPosition3D> {
+ {1, 2, 3},
+ {4, 2, 1},
+ {9, 1, 7},
+ });
+ BOOST_CHECK_EQUAL(aabb.min, GlobalPosition3D(1, 1, 1));
+ BOOST_CHECK_EQUAL(aabb.max, GlobalPosition3D(9, 2, 7));
+}
diff --git a/test/test-network.cpp b/test/test-network.cpp
index e7419b5..51fea8b 100644
--- a/test/test-network.cpp
+++ b/test/test-network.cpp
@@ -70,7 +70,7 @@ struct TestNetwork : public NetworkOf<TestLink, TestLinkS> {
}
void
- render(const SceneShader &) const override
+ render(const SceneShader &, const Frustum &) const override
{
}
diff --git a/test/test-render.cpp b/test/test-render.cpp
index 3c453bd..8390d25 100644
--- a/test/test-render.cpp
+++ b/test/test-render.cpp
@@ -38,6 +38,8 @@ class TestScene : public SceneProvider {
public:
TestScene()
{
+ terrain->point(GeoData::VertexHandle {517}).z = 100'000;
+ terrain->generateMeshes();
gameState->assets = AssetFactory::loadAll(RESDIR);
brush47rvc = std::dynamic_pointer_cast<RailVehicleClass>(gameState->assets.at("brush-47"));
std::random_device randomdev {};
@@ -68,14 +70,14 @@ public:
}
void
- content(const SceneShader & shader) const override
+ content(const SceneShader & shader, const Frustum & frustum) const override
{
- terrain->render(shader);
- water.render(shader);
- rail.render(shader);
- std::ranges::for_each(gameState->assets, [&shader](const auto & asset) {
+ terrain->render(shader, frustum);
+ water.render(shader, frustum);
+ rail.render(shader, frustum);
+ std::ranges::for_each(gameState->assets, [&shader, &frustum](const auto & asset) {
if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) {
- renderable->render(shader);
+ renderable->render(shader, frustum);
}
});
}
@@ -92,12 +94,12 @@ public:
}
void
- shadows(const ShadowMapper & shadowMapper) const override
+ shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const override
{
- terrain->shadows(shadowMapper);
- std::ranges::for_each(gameState->assets, [&shadowMapper](const auto & asset) {
+ terrain->shadows(shadowMapper, frustum);
+ std::ranges::for_each(gameState->assets, [&shadowMapper, &frustum](const auto & asset) {
if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) {
- renderable->shadows(shadowMapper);
+ renderable->shadows(shadowMapper, frustum);
}
});
}
@@ -171,10 +173,10 @@ BOOST_AUTO_TEST_CASE(terrain)
Water water {terrain};
void
- content(const SceneShader & shader) const override
+ content(const SceneShader & shader, const Frustum & frustum) const override
{
- terrain->render(shader);
- water.render(shader);
+ terrain->render(shader, frustum);
+ water.render(shader, frustum);
}
void
@@ -190,9 +192,9 @@ BOOST_AUTO_TEST_CASE(terrain)
}
void
- shadows(const ShadowMapper & shadowMapper) const override
+ shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const override
{
- terrain->shadows(shadowMapper);
+ terrain->shadows(shadowMapper, frustum);
}
};
@@ -219,9 +221,9 @@ BOOST_AUTO_TEST_CASE(railnet)
}
void
- content(const SceneShader & shader) const override
+ content(const SceneShader & shader, const Frustum & frustum) const override
{
- net.render(shader);
+ net.render(shader, frustum);
}
void
@@ -237,7 +239,7 @@ BOOST_AUTO_TEST_CASE(railnet)
}
void
- shadows(const ShadowMapper &) const override
+ shadows(const ShadowMapper &, const Frustum &) const override
{
}
};
diff --git a/ui/editNetwork.cpp b/ui/editNetwork.cpp
index c4c0297..2887491 100644
--- a/ui/editNetwork.cpp
+++ b/ui/editNetwork.cpp
@@ -48,19 +48,19 @@ EditNetwork::handleInput(const SDL_Event & e, const UIComponent::Position & pare
}
void
-EditNetwork::render(const SceneShader & shader) const
+EditNetwork::render(const SceneShader & shader, const Frustum & frustum) const
{
if (builder) {
blue.bind();
shader.absolute.use();
- builder->render(shader);
+ builder->render(shader, frustum);
}
}
void
-EditNetwork::Builder::render(const SceneShader & shader) const
+EditNetwork::Builder::render(const SceneShader & shader, const Frustum & frustum) const
{
- candidateLinks.apply<const Renderable>(&Renderable::render, shader);
+ candidateLinks.apply<const Renderable>(&Renderable::render, shader, frustum);
}
void
diff --git a/ui/editNetwork.h b/ui/editNetwork.h
index 2ae467d..ae887bd 100644
--- a/ui/editNetwork.h
+++ b/ui/editNetwork.h
@@ -18,7 +18,7 @@ public:
bool click(const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> &) override;
bool move(const SDL_MouseMotionEvent & e, const Ray<GlobalPosition3D> &) override;
bool handleInput(const SDL_Event & e, const UIComponent::Position &) override;
- void render(const SceneShader &) const override;
+ void render(const SceneShader &, const Frustum &) const override;
void render(const UIShader & shader, const UIComponent::Position & pos) const override;
using NetworkClickPos = std::variant<GlobalPosition3D, Node::Ptr>;
@@ -26,7 +26,7 @@ public:
class Builder {
public:
virtual ~Builder() = default;
- virtual void render(const SceneShader & shader) const;
+ virtual void render(const SceneShader & shader, const Frustum &) const;
virtual std::string hint() const = 0;
virtual void click(Network *, const GeoData *, const SDL_MouseButtonEvent &, const Ray<GlobalPosition3D> &) = 0;
virtual void move(Network *, const GeoData *, const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> &) = 0;
diff --git a/ui/gameMainSelector.cpp b/ui/gameMainSelector.cpp
index a817f69..23ae8c0 100644
--- a/ui/gameMainSelector.cpp
+++ b/ui/gameMainSelector.cpp
@@ -33,10 +33,10 @@ GameMainSelector::render(const UIShader & shader, const Position & parentPos) co
}
void
-GameMainSelector::render(const SceneShader & shader) const
+GameMainSelector::render(const SceneShader & shader, const Frustum & frustum) const
{
if (target) {
- target->render(shader);
+ target->render(shader, frustum);
}
}
@@ -115,6 +115,6 @@ GameMainSelector::Component::render(const UIShader &, const UIComponent::Positio
}
void
-GameMainSelector::Component::render(const SceneShader &) const
+GameMainSelector::Component::render(const SceneShader &, const Frustum &) const
{
}
diff --git a/ui/gameMainSelector.h b/ui/gameMainSelector.h
index ccf0fa0..e715823 100644
--- a/ui/gameMainSelector.h
+++ b/ui/gameMainSelector.h
@@ -24,13 +24,13 @@ public:
virtual bool move(const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> &);
virtual bool handleInput(const SDL_Event &, const Position & pos);
virtual void render(const UIShader & shader, const Position & pos) const;
- virtual void render(const SceneShader &) const;
+ virtual void render(const SceneShader &, const Frustum &) const;
};
GameMainSelector(const Camera * c, ScreenAbsCoord size);
void render(const UIShader & shader, const Position & pos) const override;
- void render(const SceneShader & shader) const override;
+ void render(const SceneShader & shader, const Frustum &) const override;
bool handleInput(const SDL_Event & e, const Position &) override;
diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp
index c53300b..f63137c 100644
--- a/ui/gameMainWindow.cpp
+++ b/ui/gameMainWindow.cpp
@@ -54,15 +54,15 @@ GameMainWindow::render() const
}
void
-GameMainWindow::content(const SceneShader & shader) const
+GameMainWindow::content(const SceneShader & shader, const Frustum & frustum) const
{
for (const auto & [id, asset] : gameState->assets) {
if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) {
- r->render(shader);
+ r->render(shader, frustum);
}
}
- gameState->world.apply<Renderable>(&Renderable::render, shader);
- uiComponents.apply<WorldOverlay>(&WorldOverlay::render, shader);
+ gameState->world.apply<Renderable>(&Renderable::render, shader, frustum);
+ uiComponents.apply<WorldOverlay>(&WorldOverlay::render, shader, frustum);
}
void
@@ -78,12 +78,12 @@ GameMainWindow::lights(const SceneShader & shader) const
}
void
-GameMainWindow::shadows(const ShadowMapper & shadowMapper) const
+GameMainWindow::shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const
{
for (const auto & [id, asset] : gameState->assets) {
if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) {
- r->shadows(shadowMapper);
+ r->shadows(shadowMapper, frustum);
}
}
- gameState->world.apply<Renderable>(&Renderable::shadows, shadowMapper);
+ gameState->world.apply<Renderable>(&Renderable::shadows, shadowMapper, frustum);
}
diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h
index fcbd135..43980e8 100644
--- a/ui/gameMainWindow.h
+++ b/ui/gameMainWindow.h
@@ -17,8 +17,8 @@ public:
void render() const override;
private:
- void content(const SceneShader &) const override;
+ void content(const SceneShader &, const Frustum &) const override;
void environment(const SceneShader &, const SceneRenderer &) const override;
void lights(const SceneShader &) const override;
- void shadows(const ShadowMapper &) const override;
+ void shadows(const ShadowMapper &, const Frustum &) const override;
};
diff --git a/ui/worldOverlay.h b/ui/worldOverlay.h
index 18fab3f..a0f3b65 100644
--- a/ui/worldOverlay.h
+++ b/ui/worldOverlay.h
@@ -1,9 +1,10 @@
#pragma once
class SceneShader;
+class Frustum;
class WorldOverlay {
public:
virtual ~WorldOverlay() = default;
- virtual void render(const SceneShader &) const = 0;
+ virtual void render(const SceneShader &, const Frustum &) const = 0;
};