diff options
Diffstat (limited to 'game')
-rw-r--r-- | game/geoData.cpp | 21 | ||||
-rw-r--r-- | game/geoData.h | 7 | ||||
-rw-r--r-- | game/network/rail.cpp | 2 | ||||
-rw-r--r-- | game/network/rail.h | 2 | ||||
-rw-r--r-- | game/scenary/foliage.cpp | 4 | ||||
-rw-r--r-- | game/scenary/foliage.h | 4 | ||||
-rw-r--r-- | game/scenary/illuminator.cpp | 2 | ||||
-rw-r--r-- | game/scenary/illuminator.h | 2 | ||||
-rw-r--r-- | game/terrain.cpp | 65 | ||||
-rw-r--r-- | game/terrain.h | 14 | ||||
-rw-r--r-- | game/vehicles/railVehicleClass.cpp | 4 | ||||
-rw-r--r-- | game/vehicles/railVehicleClass.h | 4 | ||||
-rw-r--r-- | game/water.cpp | 4 | ||||
-rw-r--r-- | game/water.h | 2 |
14 files changed, 90 insertions, 47 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}; |