summaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
Diffstat (limited to 'game')
-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
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};