summaryrefslogtreecommitdiff
path: root/gfx
diff options
context:
space:
mode:
Diffstat (limited to 'gfx')
-rw-r--r--gfx/aabb.h41
-rw-r--r--gfx/camera.cpp (renamed from gfx/gl/camera.cpp)33
-rw-r--r--gfx/camera.h (renamed from gfx/gl/camera.h)26
-rw-r--r--gfx/followCameraController.cpp4
-rw-r--r--gfx/frustum.cpp67
-rw-r--r--gfx/frustum.h45
-rw-r--r--gfx/gl/gldebug.cpp20
-rw-r--r--gfx/gl/gldebug.h52
-rw-r--r--gfx/gl/program.cpp22
-rw-r--r--gfx/gl/program.h16
-rw-r--r--gfx/gl/sceneProvider.cpp4
-rw-r--r--gfx/gl/sceneProvider.h5
-rw-r--r--gfx/gl/sceneRenderer.cpp139
-rw-r--r--gfx/gl/sceneRenderer.h12
-rw-r--r--gfx/gl/sceneShader.cpp63
-rw-r--r--gfx/gl/sceneShader.h12
-rw-r--r--gfx/gl/shader.cpp85
-rw-r--r--gfx/gl/shader.h8
-rw-r--r--gfx/gl/shaders/commonPoint.glsl15
-rw-r--r--gfx/gl/shaders/commonShadowPoint.geom (renamed from gfx/gl/shaders/commonShadowPoint.gs)11
-rw-r--r--gfx/gl/shaders/commonShadowPoint.glsl5
-rw-r--r--gfx/gl/shaders/directionalLight.frag60
-rw-r--r--gfx/gl/shaders/directionalLight.fs50
-rw-r--r--gfx/gl/shaders/dynamicPoint.vert (renamed from gfx/gl/shaders/dynamicPoint.vs)5
-rw-r--r--gfx/gl/shaders/dynamicPointInst.vert (renamed from gfx/gl/shaders/dynamicPointInst.vs)5
-rw-r--r--gfx/gl/shaders/fixedPoint.vert (renamed from gfx/gl/shaders/fixedPoint.vs)5
-rw-r--r--gfx/gl/shaders/getMaterialDetail.glsl12
-rw-r--r--gfx/gl/shaders/landmass.frag (renamed from gfx/gl/shaders/landmass.fs)8
-rw-r--r--gfx/gl/shaders/landmass.vert (renamed from gfx/gl/shaders/landmass.vs)6
-rw-r--r--gfx/gl/shaders/lighting.frag (renamed from gfx/gl/shaders/lighting.fs)3
-rw-r--r--gfx/gl/shaders/lighting.vert (renamed from gfx/gl/shaders/lighting.vs)2
-rw-r--r--gfx/gl/shaders/material.frag18
-rw-r--r--gfx/gl/shaders/material.fs49
-rw-r--r--gfx/gl/shaders/materialCommon.glsl33
-rw-r--r--gfx/gl/shaders/materialDetail.glsl5
-rw-r--r--gfx/gl/shaders/materialInterface.glsl20
-rw-r--r--gfx/gl/shaders/network.frag (renamed from gfx/gl/shaders/network.fs)3
-rw-r--r--gfx/gl/shaders/networkCommon.glsl10
-rw-r--r--gfx/gl/shaders/networkCurve.geom17
-rw-r--r--gfx/gl/shaders/networkCurve.gs47
-rw-r--r--gfx/gl/shaders/networkCurve.tesc37
-rw-r--r--gfx/gl/shaders/networkCurve.tese45
-rw-r--r--gfx/gl/shaders/networkCurve.vert23
-rw-r--r--gfx/gl/shaders/networkCurve.vs29
-rw-r--r--gfx/gl/shaders/networkStraight.geom (renamed from gfx/gl/shaders/networkStraight.gs)12
-rw-r--r--gfx/gl/shaders/networkStraight.vert (renamed from gfx/gl/shaders/networkStraight.vs)13
-rw-r--r--gfx/gl/shaders/pointLight.frag (renamed from gfx/gl/shaders/pointLight.fs)3
-rw-r--r--gfx/gl/shaders/pointLight.geom (renamed from gfx/gl/shaders/pointLight.gs)4
-rw-r--r--gfx/gl/shaders/pointLight.vert (renamed from gfx/gl/shaders/pointLight.vs)2
-rw-r--r--gfx/gl/shaders/shadowDynamicPoint.vert (renamed from gfx/gl/shaders/shadowDynamicPoint.vs)2
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInst.vert (renamed from gfx/gl/shaders/shadowDynamicPointInst.vs)2
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInstWithTextures.frag18
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs15
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInstWithTextures.geom3
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInstWithTextures.gs3
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert14
-rw-r--r--gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs3
-rw-r--r--gfx/gl/shaders/shadowDynamicPointStencil.frag15
-rw-r--r--gfx/gl/shaders/shadowDynamicPointStencil.geom35
-rw-r--r--gfx/gl/shaders/shadowDynamicPointStencil.vert16
-rw-r--r--gfx/gl/shaders/shadowLandmass.vert (renamed from gfx/gl/shaders/shadowLandmass.vs)2
-rw-r--r--gfx/gl/shaders/shadowStencil.frag17
-rw-r--r--gfx/gl/shaders/shadowStencil.geom27
-rw-r--r--gfx/gl/shaders/shadowStencil.vert19
-rw-r--r--gfx/gl/shaders/spotLight.frag (renamed from gfx/gl/shaders/spotLight.fs)3
-rw-r--r--gfx/gl/shaders/spotLight.geom (renamed from gfx/gl/shaders/spotLight.gs)4
-rw-r--r--gfx/gl/shaders/spotLight.vert (renamed from gfx/gl/shaders/spotLight.vs)2
-rw-r--r--gfx/gl/shaders/uiShader.fs11
-rw-r--r--gfx/gl/shaders/uiShader.vs13
-rw-r--r--gfx/gl/shaders/uiShaderFont.fs12
-rw-r--r--gfx/gl/shaders/water.frag (renamed from gfx/gl/shaders/water.fs)3
-rw-r--r--gfx/gl/shaders/water.vert (renamed from gfx/gl/shaders/water.vs)2
-rw-r--r--gfx/gl/shadowMapper.cpp125
-rw-r--r--gfx/gl/shadowMapper.h21
-rw-r--r--gfx/gl/shadowStenciller.cpp76
-rw-r--r--gfx/gl/shadowStenciller.h27
-rw-r--r--gfx/gl/uiShader.cpp27
-rw-r--r--gfx/gl/uiShader.h47
-rw-r--r--gfx/gl/vertexArrayObject.h12
-rw-r--r--gfx/lightDirection.cpp12
-rw-r--r--gfx/lightDirection.h39
-rw-r--r--gfx/models/mesh.cpp28
-rw-r--r--gfx/models/mesh.h30
-rw-r--r--gfx/models/texture.cpp19
-rw-r--r--gfx/models/texture.h7
-rw-r--r--gfx/renderable.cpp7
-rw-r--r--gfx/renderable.h8
87 files changed, 1338 insertions, 599 deletions
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/gl/camera.cpp b/gfx/camera.cpp
index 82b11a6..3bb785d 100644
--- a/gfx/gl/camera.cpp
+++ b/gfx/camera.cpp
@@ -4,28 +4,39 @@
#include <maths.h>
#include <ray.h>
-Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance zNear, GlobalDistance zFar) :
- position {pos}, forward {::north}, up {::up}, near {zNear}, far {zFar},
- projection {
- glm::perspective(fov, aspect, static_cast<RelativeDistance>(zNear), static_cast<RelativeDistance>(zFar))},
- viewProjection {}, inverseViewProjection {}
+Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance near, GlobalDistance far) :
+ Camera {pos, fov, aspect, near, far, glm::lookAt({}, ::north, ::up),
+ glm::perspective(fov, aspect, static_cast<RelativeDistance>(near), static_cast<RelativeDistance>(far))}
{
- updateView();
+}
+
+Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance near, GlobalDistance far,
+ const glm::mat4 & view, const glm::mat4 & projection) :
+ Frustum {pos, view, projection}, fov {fov}, aspect {aspect}, forward {::north}, up {::up}, near {near}, far {far}
+{
+}
+
+void
+Camera::setAspect(Angle aspect)
+{
+ projection = glm::perspective(fov, aspect, static_cast<RelativeDistance>(near), static_cast<RelativeDistance>(far));
+ Frustum::updateCache();
}
Ray<GlobalPosition3D>
Camera::unProject(const ScreenRelCoord & mouse) const
{
- static constexpr const glm::vec4 screen {0, 0, 1, 1};
- const auto mouseProjection = glm::lookAt({}, forward, up);
- return {position, glm::normalize(glm::unProject(mouse || 1.F, mouseProjection, projection, screen))};
+ static constexpr const glm::vec4 SCREEN {0, 0, 1, 1};
+ return {
+ .start = position,
+ .direction = glm::normalize(glm::unProject(mouse || 1.F, view, projection, SCREEN)),
+ };
}
void
Camera::updateView()
{
- viewProjection = projection * glm::lookAt({}, forward, up);
- inverseViewProjection = glm::inverse(viewProjection);
+ Frustum::updateView(glm::lookAt({}, forward, up));
}
Direction3D
diff --git a/gfx/gl/camera.h b/gfx/camera.h
index 8d53261..b17bcbb 100644
--- a/gfx/gl/camera.h
+++ b/gfx/camera.h
@@ -1,22 +1,19 @@
#pragma once
#include "config/types.h"
+#include "frustum.h"
#include <glm/glm.hpp>
#include <maths.h>
#include <ray.h>
-class Camera {
+class Camera : public Frustum {
public:
- Camera(GlobalPosition3D, Angle fov, Angle aspect, GlobalDistance zNear, GlobalDistance zFar);
-
- [[nodiscard]] glm::mat4
- getViewProjection() const
- {
- return viewProjection;
- }
+ Camera(GlobalPosition3D position, Angle fov, Angle aspect, GlobalDistance near, GlobalDistance far);
[[nodiscard]] Ray<GlobalPosition3D> unProject(const ScreenRelCoord &) const;
+ void setAspect(Angle aspect);
+
void
setPosition(const GlobalPosition3D & p)
{
@@ -64,24 +61,17 @@ public:
return forward;
}
- [[nodiscard]] auto
- getPosition() const
- {
- return position;
- }
-
[[nodiscard]] std::array<GlobalPosition4D, 4> extentsAtDist(GlobalDistance) const;
[[nodiscard]] static Direction3D upFromForward(const Direction3D & forward);
private:
+ Camera(GlobalPosition3D position, Angle fov, Angle aspect, GlobalDistance near, GlobalDistance far,
+ const glm::mat4 & view, const glm::mat4 & projection);
void updateView();
- GlobalPosition3D position;
+ Angle fov, aspect;
Direction3D forward;
Direction3D up;
-
GlobalDistance near, far;
- glm::mat4 projection;
- glm::mat4 viewProjection, inverseViewProjection;
};
diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp
index 52dfb35..d7bbc0b 100644
--- a/gfx/followCameraController.cpp
+++ b/gfx/followCameraController.cpp
@@ -1,6 +1,6 @@
#include "followCameraController.h"
#include "game/vehicles/vehicle.h"
-#include <gfx/gl/camera.h>
+#include <gfx/camera.h>
#include <glm/glm.hpp>
#include <location.h>
#include <maths.h>
@@ -24,7 +24,7 @@ FollowCameraController::updateCamera(Camera * camera) const
break;
case Mode::Ride:
- camera->setView(pos + (up * 4.8F), -sincosf(rot.y) || 0.F);
+ camera->setView(pos + (up * 4.8F), -sincos(rot.y) || 0.F);
break;
case Mode::ISO:
diff --git a/gfx/frustum.cpp b/gfx/frustum.cpp
new file mode 100644
index 0000000..faa676d
--- /dev/null
+++ b/gfx/frustum.cpp
@@ -0,0 +1,67 @@
+#include "frustum.h"
+#include <algorithm>
+#include <collections.h>
+#include <glm/ext/matrix_transform.hpp>
+
+static constexpr auto PLANES = std::array {0, 1, 2} * std::array {-1.F, 1.F};
+
+Frustum::Frustum(const GlobalPosition3D & pos, const glm::mat4 & view, const glm::mat4 & projection) :
+ position {pos}, view {view}, projection {projection}, viewProjection {}, inverseViewProjection {}, planes {}
+{
+ updateCache();
+}
+
+void
+Frustum::updateView(const glm::mat4 & newView)
+{
+ view = 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()
+{
+ viewProjection = projection * view;
+ inverseViewProjection = glm::inverse(viewProjection);
+ std::ranges::transform(PLANES, planes.begin(), [vpt = glm::transpose(viewProjection)](const auto & idxs) {
+ const auto [idx, sgn] = idxs;
+ return vpt[3] + (vpt[idx] * sgn);
+ });
+}
diff --git a/gfx/frustum.h b/gfx/frustum.h
new file mode 100644
index 0000000..a2d90e9
--- /dev/null
+++ b/gfx/frustum.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "aabb.h"
+#include "config/types.h"
+#include <array>
+#include <glm/mat4x4.hpp>
+
+class Frustum {
+public:
+ Frustum(const GlobalPosition3D & pos, const glm::mat4 & view, const glm::mat4 & projection);
+
+ [[nodiscard]] auto &
+ getFrustumPlanes() const
+ {
+ return planes;
+ }
+
+ [[nodiscard]] auto &
+ getViewProjection() const
+ {
+ 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/gldebug.cpp b/gfx/gl/gldebug.cpp
new file mode 100644
index 0000000..518d4fb
--- /dev/null
+++ b/gfx/gl/gldebug.cpp
@@ -0,0 +1,20 @@
+#if GLDEBUG == 2
+// Level 2 is out of line because its "complex"
+
+# include "gldebug.h"
+# include <format>
+
+glDebugScope::glDebugScope(GLuint id, const std::source_location & location)
+{
+ const auto fullMsg = std::format("{} ({}:{})", location.function_name(), location.file_name(), location.line());
+ glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, id, static_cast<GLsizei>(fullMsg.length()), fullMsg.c_str());
+}
+
+glDebugScope::glDebugScope(GLuint id, const std::string_view msg, const std::source_location & location)
+{
+ const auto fullMsg
+ = std::format("{} @ {} ({}:{})", msg, location.function_name(), location.file_name(), location.line());
+ glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, id, static_cast<GLsizei>(fullMsg.length()), fullMsg.c_str());
+}
+
+#endif
diff --git a/gfx/gl/gldebug.h b/gfx/gl/gldebug.h
new file mode 100644
index 0000000..5cfd099
--- /dev/null
+++ b/gfx/gl/gldebug.h
@@ -0,0 +1,52 @@
+#pragma once
+#ifndef GLDEBUG
+# define GLDEBUG 0
+#endif
+
+#include "special_members.h"
+#include <glad/gl.h>
+#include <source_location>
+#include <string_view>
+
+class [[nodiscard]] glDebugScope {
+public:
+ explicit glDebugScope(GLuint id, const std::source_location & = std::source_location::current());
+ explicit glDebugScope(
+ GLuint id, std::string_view msg, const std::source_location & = std::source_location::current());
+
+ ~glDebugScope();
+
+ constexpr
+ operator bool() const
+ {
+ return true;
+ }
+
+ NO_MOVE(glDebugScope);
+ NO_COPY(glDebugScope);
+};
+
+#if GLDEBUG > 0
+inline glDebugScope::~glDebugScope()
+{
+ glPopDebugGroup();
+}
+# if GLDEBUG == 1
+// Level 1 is inlined for performance because they're thin wrappers
+inline glDebugScope::glDebugScope(GLuint id, const std::source_location & location) :
+ glDebugScope {id, location.function_name()}
+{
+}
+
+inline glDebugScope::glDebugScope(GLuint id, const std::string_view msg, const std::source_location &)
+{
+ glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, id, static_cast<GLsizei>(msg.length()), msg.data());
+}
+# endif
+#else
+inline glDebugScope::glDebugScope(GLuint, const std::source_location &) { }
+
+inline glDebugScope::glDebugScope(GLuint, const std::string_view, const std::source_location &) { }
+
+inline glDebugScope::~glDebugScope() = default;
+#endif
diff --git a/gfx/gl/program.cpp b/gfx/gl/program.cpp
index 7287fde..da85456 100644
--- a/gfx/gl/program.cpp
+++ b/gfx/gl/program.cpp
@@ -1,5 +1,5 @@
#include "program.h"
-#include "shader.h"
+#include "gldebug.h"
#include <format>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
@@ -9,11 +9,12 @@
void
Program::linkAndValidate() const
{
+ glDebugScope _ {m_program};
glLinkProgram(m_program);
- Shader::CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");
+ checkProgramError(m_program, GL_LINK_STATUS, "Error linking shader program");
glValidateProgram(m_program);
- Shader::CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
+ checkProgramError(m_program, GL_VALIDATE_STATUS, "Invalid shader program");
}
void
@@ -22,6 +23,21 @@ Program::use() const
glUseProgram(m_program);
}
+void
+Program::checkProgramError(GLuint program, GLuint flag, std::string_view errorMessage) const
+{
+ GLint success = 0;
+
+ glGetProgramiv(program, flag, &success);
+
+ if (success == GL_FALSE) {
+ std::array<GLchar, 1024> error {};
+ glGetProgramInfoLog(program, error.size(), nullptr, error.data());
+
+ throw std::runtime_error {std::format("{}: '{}'", errorMessage, error.data())};
+ }
+}
+
Program::UniformLocation::UniformLocation(GLuint program, const char * name) :
location {glGetUniformLocation(program, name)}
{
diff --git a/gfx/gl/program.h b/gfx/gl/program.h
index 1a1c306..2b06d2d 100644
--- a/gfx/gl/program.h
+++ b/gfx/gl/program.h
@@ -1,6 +1,7 @@
#pragma once
-#include "shader.h"
+#include "gldebug.h"
+#include "shader.h" // IWYU pragma: export
#include <glRef.h>
#include <glad/gl.h>
#include <glm/mat4x4.hpp>
@@ -12,7 +13,11 @@ using ProgramRef = glRef<GLuint, &glCreateProgram, &glDeleteProgram>;
class Program {
public:
- template<typename... S> explicit Program(const S &... srcs)
+ Program() = delete;
+
+ template<typename... S> explicit Program(const S &... srcs) : Program {glDebugScope {0}, srcs...} { }
+
+ template<typename... S> explicit Program(glDebugScope, const S &... srcs)
{
(glAttachShader(m_program, srcs.compile()), ...);
linkAndValidate();
@@ -31,6 +36,12 @@ public:
return location;
}
+ explicit
+ operator bool() const
+ {
+ return location >= 0;
+ }
+
protected:
GLint location;
};
@@ -47,6 +58,7 @@ public:
}
protected:
+ void checkProgramError(GLuint program, GLuint flag, std::string_view errorMessage) const;
void use() const;
void linkAndValidate() const;
ProgramRef m_program;
diff --git a/gfx/gl/sceneProvider.cpp b/gfx/gl/sceneProvider.cpp
index 2e8604c..3681c60 100644
--- a/gfx/gl/sceneProvider.cpp
+++ b/gfx/gl/sceneProvider.cpp
@@ -5,10 +5,10 @@ void
SceneProvider::environment(const SceneShader &, const SceneRenderer & renderer) const
{
renderer.setAmbientLight({0.5F, 0.5F, 0.5F});
- renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {-1, 1, -1}, *this);
+ renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {{-quarter_pi, quarter_pi}}, *this);
}
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 e0938f2..5e8241f 100644
--- a/gfx/gl/sceneRenderer.cpp
+++ b/gfx/gl/sceneRenderer.cpp
@@ -1,9 +1,9 @@
#include "sceneRenderer.h"
#include "maths.h"
#include "vertexArrayObject.h"
-#include <gfx/gl/shaders/fs-directionalLight.h>
-#include <gfx/gl/shaders/fs-lighting.h>
-#include <gfx/gl/shaders/vs-lighting.h>
+#include <gfx/gl/shaders/directionalLight-frag.h>
+#include <gfx/gl/shaders/lighting-frag.h>
+#include <gfx/gl/shaders/lighting-vert.h>
#include <glm/gtc/type_ptr.hpp>
static constexpr const std::array<const glm::i8vec4, 4> displayVAOdata {{
@@ -14,9 +14,11 @@ static constexpr const std::array<const glm::i8vec4, 4> displayVAOdata {{
{1, -1, 1, 0},
}};
-SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) :
+SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : SceneRenderer {s, o, glDebugScope {o}} { }
+
+SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o, glDebugScope) :
camera {{-1250000, -1250000, 35.0F}, quarter_pi, ratio(s), 100, 10000000}, size {s}, output {o},
- lighting {lighting_vs, lighting_fs}, shadowMapper {{2048, 2048}}
+ lighting {lighting_vert, lighting_frag}, shadowMapper {{2048, 2048}}
{
shader.setViewPort({0, 0, size.x, size.y});
VertexArrayObject {displayVAO}.addAttribs<glm::i8vec4>(displayVBO, displayVAOdata);
@@ -39,7 +41,7 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) :
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
configuregdata(gPosition, {GL_RGB32I}, GL_RGB_INTEGER, GL_COLOR_ATTACHMENT0);
- configuregdata(gNormal, {GL_RGB8_SNORM, GL_RGB16F}, GL_RGB, GL_COLOR_ATTACHMENT1);
+ normaliFormat = configuregdata(gNormal, {GL_RGB8_SNORM, GL_RGB16F}, GL_RGB, GL_COLOR_ATTACHMENT1);
configuregdata(gAlbedoSpec, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT2);
constexpr std::array<unsigned int, 3> attachments {
GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
@@ -57,66 +59,110 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) :
}
void
+SceneRenderer::resize(ScreenAbsCoord newSize)
+{
+ glDebugScope _ {output};
+ size = newSize;
+ camera.setAspect(ratio(size));
+ const auto configuregdata = [this](const GLuint data, const GLint iformat, const GLenum format) {
+ glBindTexture(GL_TEXTURE_2D, data);
+ glTexImage2D(GL_TEXTURE_2D, 0, iformat, size.x, size.y, 0, format, GL_BYTE, nullptr);
+ };
+ configuregdata(gPosition, GL_RGB32I, GL_RGB_INTEGER);
+ configuregdata(gNormal, normaliFormat, GL_RGB);
+ configuregdata(gAlbedoSpec, GL_RGB8, GL_RGB);
+ configuregdata(gIllumination, GL_RGB8, GL_RGB);
+ glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y);
+ shader.setViewPort({0, 0, size.x, size.y});
+}
+
+void
SceneRenderer::render(const SceneProvider & scene) const
{
+ glDebugScope _ {output};
shader.setViewProjection(camera.getPosition(), camera.getViewProjection());
glViewport(0, 0, size.x, size.y);
- // Geometry pass
- glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
- glEnable(GL_BLEND);
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_DEPTH_TEST);
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- scene.content(shader);
-
- // Illumination pass
- glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll);
- glBlendFunc(GL_ONE, GL_ONE);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gPosition);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, gNormal);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMapper);
- scene.environment(shader, *this);
- glDisable(GL_DEPTH_TEST);
- scene.lights(shader);
-
- // Lighting pass
- glBindFramebuffer(GL_FRAMEBUFFER, output);
- glViewport(0, 0, size.x, size.y);
- glCullFace(GL_BACK);
- glDisable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, gAlbedoSpec);
- glActiveTexture(GL_TEXTURE3);
- glBindTexture(GL_TEXTURE_2D, gIllumination);
- lighting.use();
- renderQuad();
+ if (glDebugScope _ {gBuffer, "Geometry/colour pass"}) {
+ // Geometry/colour pass - writes albedo, normal and position textures
+ glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
+ glEnable(GL_BLEND);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ scene.content(shader, camera);
+ }
+
+ if (glDebugScope _ {gBufferIll, "Environment pass"}) {
+ // Environment pass -
+ // * ambient - clears illumination texture - see setAmbientLight
+ // * directional - updates shadowMapper, reads normal and position, writes illumination - see
+ // setDirectionalLight
+ scene.environment(shader, *this);
+ }
+
+ if (glDebugScope _ {gBufferIll, "Scene lighting pass"}) {
+ // Scene lights pass -
+ // * per light - reads normal and position, writes illumination
+ glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll);
+ glBlendFunc(GL_ONE, GL_ONE);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gPosition);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, gNormal);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMapper);
+ glDisable(GL_DEPTH_TEST);
+ scene.lights(shader);
+ }
+
+ if (glDebugScope _ {output, "Composition pass"}) {
+ // Composition pass - reads albedo and illumination, writes output
+ glBindFramebuffer(GL_FRAMEBUFFER, output);
+ glViewport(0, 0, size.x, size.y);
+ glCullFace(GL_BACK);
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, gAlbedoSpec);
+ glActiveTexture(GL_TEXTURE3);
+ glBindTexture(GL_TEXTURE_2D, gIllumination);
+ lighting.use();
+ renderQuad();
+ }
}
void
SceneRenderer::setAmbientLight(const RGB & colour) const
{
+ glDebugScope _ {output};
glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll);
glClearColor(colour.r, colour.g, colour.b, 1.0F);
glClear(GL_COLOR_BUFFER_BIT);
}
void
-SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider & scene) const
+SceneRenderer::setDirectionalLight(
+ const RGB & colour, const LightDirection & direction, const SceneProvider & scene) const
{
if (colour.r > 0 || colour.g > 0 || colour.b > 0) {
+ glDebugScope _ {output};
const auto lvp = shadowMapper.update(scene, direction, camera);
glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll);
+ glBlendFunc(GL_ONE, GL_ONE);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gPosition);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, gNormal);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMapper);
glViewport(0, 0, size.x, size.y);
dirLight.use();
- dirLight.setDirectionalLight(colour, direction, camera.getPosition(), lvp);
+ dirLight.setDirectionalLight(colour, direction.vector(), camera.getPosition(), lvp);
renderQuad();
}
}
@@ -129,7 +175,7 @@ SceneRenderer::renderQuad() const
glBindVertexArray(0);
}
-SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : Program {lighting_vs, directionalLight_fs} { }
+SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : Program {lighting_vert, directionalLight_frag} { }
const auto toTextureSpaceMat = glm::translate(glm::identity<glm::mat4>(), glm::vec3 {0.5F})
* glm::scale(glm::identity<glm::mat4>(), glm::vec3 {0.5F});
@@ -142,8 +188,7 @@ SceneRenderer::DirectionalLightProgram::setDirectionalLight(
return toTextureSpaceMat * m;
};
glUniform(colourLoc, c);
- const auto nd = glm::normalize(d);
- glUniform(directionLoc, nd);
+ glUniform(directionLoc, d);
glUniform(lightPointLoc, p);
glUniform(lightViewProjectionCountLoc, static_cast<GLuint>(lvp.size()));
glUniform(lightViewProjectionLoc, std::span<const glm::mat4> {lvp * toTextureSpace});
diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h
index 4195bcf..05921a1 100644
--- a/gfx/gl/sceneRenderer.h
+++ b/gfx/gl/sceneRenderer.h
@@ -1,20 +1,25 @@
#pragma once
-#include "camera.h"
+#include "gfx/lightDirection.h"
#include "glArrays.h"
+#include "gldebug.h"
#include "program.h"
#include "sceneProvider.h"
#include "sceneShader.h"
#include "shadowMapper.h"
+#include <gfx/camera.h>
#include <glm/fwd.hpp>
class SceneRenderer {
public:
- explicit SceneRenderer(ScreenAbsCoord size, GLuint output);
+ SceneRenderer(ScreenAbsCoord size, GLuint output);
+ SceneRenderer(ScreenAbsCoord size, GLuint output, glDebugScope);
+
+ void resize(ScreenAbsCoord size);
void render(const SceneProvider &) const;
void setAmbientLight(const RGB & colour) const;
- void setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider &) const;
+ void setDirectionalLight(const RGB & colour, const LightDirection & direction, const SceneProvider &) const;
Camera camera;
@@ -24,6 +29,7 @@ protected:
ScreenAbsCoord size;
GLuint output;
glFrameBuffer gBuffer, gBufferIll;
+ GLint normaliFormat;
glTexture gPosition, gNormal, gAlbedoSpec, gIllumination;
glRenderBuffer depth;
diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp
index 4cbccb3..72cde91 100644
--- a/gfx/gl/sceneShader.cpp
+++ b/gfx/gl/sceneShader.cpp
@@ -1,23 +1,25 @@
#include "sceneShader.h"
-#include <gfx/gl/shaders/fs-landmass.h>
-#include <gfx/gl/shaders/fs-material.h>
-#include <gfx/gl/shaders/fs-network.h>
-#include <gfx/gl/shaders/fs-pointLight.h>
-#include <gfx/gl/shaders/fs-spotLight.h>
-#include <gfx/gl/shaders/fs-water.h>
-#include <gfx/gl/shaders/gs-networkCurve.h>
-#include <gfx/gl/shaders/gs-networkStraight.h>
-#include <gfx/gl/shaders/gs-pointLight.h>
-#include <gfx/gl/shaders/gs-spotLight.h>
-#include <gfx/gl/shaders/vs-dynamicPoint.h>
-#include <gfx/gl/shaders/vs-dynamicPointInst.h>
-#include <gfx/gl/shaders/vs-fixedPoint.h>
-#include <gfx/gl/shaders/vs-landmass.h>
-#include <gfx/gl/shaders/vs-networkCurve.h>
-#include <gfx/gl/shaders/vs-networkStraight.h>
-#include <gfx/gl/shaders/vs-pointLight.h>
-#include <gfx/gl/shaders/vs-spotLight.h>
-#include <gfx/gl/shaders/vs-water.h>
+#include <gfx/gl/shaders/dynamicPoint-vert.h>
+#include <gfx/gl/shaders/dynamicPointInst-vert.h>
+#include <gfx/gl/shaders/fixedPoint-vert.h>
+#include <gfx/gl/shaders/landmass-frag.h>
+#include <gfx/gl/shaders/landmass-vert.h>
+#include <gfx/gl/shaders/material-frag.h>
+#include <gfx/gl/shaders/network-frag.h>
+#include <gfx/gl/shaders/networkCurve-geom.h>
+#include <gfx/gl/shaders/networkCurve-tesc.h>
+#include <gfx/gl/shaders/networkCurve-tese.h>
+#include <gfx/gl/shaders/networkCurve-vert.h>
+#include <gfx/gl/shaders/networkStraight-geom.h>
+#include <gfx/gl/shaders/networkStraight-vert.h>
+#include <gfx/gl/shaders/pointLight-frag.h>
+#include <gfx/gl/shaders/pointLight-geom.h>
+#include <gfx/gl/shaders/pointLight-vert.h>
+#include <gfx/gl/shaders/spotLight-frag.h>
+#include <gfx/gl/shaders/spotLight-geom.h>
+#include <gfx/gl/shaders/spotLight-vert.h>
+#include <gfx/gl/shaders/water-frag.h>
+#include <gfx/gl/shaders/water-vert.h>
#include <gfx/gl/vertexArrayObject.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
@@ -34,11 +36,11 @@ SceneShader::allPrograms(auto member, auto &&... ps) const
}
SceneShader::SceneShader() :
- basicInst {dynamicPointInst_vs, material_fs}, landmass {landmass_vs, landmass_fs},
- absolute {fixedPoint_vs, material_fs}, spotLightInst {spotLight_vs, spotLight_gs, spotLight_fs},
- pointLightInst {pointLight_vs, pointLight_gs, pointLight_fs},
- networkStraight {networkStraight_vs, networkStraight_gs, network_fs},
- networkCurve {networkCurve_vs, networkCurve_gs, network_fs}
+ basicInst {dynamicPointInst_vert, material_frag}, absolute {fixedPoint_vert, material_frag},
+ spotLightInst {spotLight_vert, spotLight_geom, spotLight_frag},
+ pointLightInst {pointLight_vert, pointLight_geom, pointLight_frag}, landmass {landmass_vert, landmass_frag},
+ networkStraight {networkStraight_vert, networkStraight_geom, network_frag},
+ networkCurve {networkCurve_vert, networkCurve_tesc, networkCurve_tese, networkCurve_geom, network_frag}
{
}
@@ -65,13 +67,13 @@ SceneShader::SceneProgram::setViewProjection(const GlobalPosition3D & viewPoint,
void
SceneShader::SceneProgram::setViewPort(const ViewPort & viewPort) const
{
- if (viewPortLoc >= 0) {
+ if (viewPortLoc) {
glUseProgram(*this);
glUniform(viewPortLoc, viewPort);
}
}
-SceneShader::BasicProgram::BasicProgram() : SceneProgram {dynamicPoint_vs, material_fs} { }
+SceneShader::BasicProgram::BasicProgram() : SceneProgram {dynamicPoint_vert, material_frag} { }
void
SceneShader::BasicProgram::setModel(Location const & location) const
@@ -88,6 +90,13 @@ SceneShader::BasicProgram::use(Location const & location) const
}
void
+SceneShader::LandmassProgram::use(const glm::vec3 colourBias) const
+{
+ Program::use();
+ glUniform(colourBiasLos, colourBias);
+}
+
+void
SceneShader::NetworkProgram::use(
const std::span<const glm::vec3> profile, const std::span<const float> texturePos) const
{
@@ -97,7 +106,7 @@ SceneShader::NetworkProgram::use(
glUniform(profileLengthLoc, static_cast<GLuint>(profile.size()));
}
-SceneShader::WaterProgram::WaterProgram() : SceneProgram {water_vs, water_fs} { }
+SceneShader::WaterProgram::WaterProgram() : SceneProgram {water_vert, water_frag} { }
void
SceneShader::WaterProgram::use(float waveCycle) const
diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h
index 51f0e21..47d4397 100644
--- a/gfx/gl/sceneShader.h
+++ b/gfx/gl/sceneShader.h
@@ -50,6 +50,15 @@ class SceneShader {
RequiredUniformLocation profileLengthLoc {*this, "profileLength"};
};
+ class LandmassProgram : public AbsolutePosProgram {
+ public:
+ using AbsolutePosProgram::AbsolutePosProgram;
+ void use(const glm::vec3) const;
+
+ private:
+ RequiredUniformLocation colourBiasLos {*this, "colourBias"};
+ };
+
class WaterProgram : public SceneProgram {
public:
WaterProgram();
@@ -64,7 +73,8 @@ public:
BasicProgram basic;
WaterProgram water;
- AbsolutePosProgram basicInst, landmass, absolute, spotLightInst, pointLightInst;
+ AbsolutePosProgram basicInst, absolute, spotLightInst, pointLightInst;
+ LandmassProgram landmass;
NetworkProgram networkStraight, networkCurve;
void setViewProjection(const GlobalPosition3D & viewPoint, const glm::mat4 & viewProjection) const;
diff --git a/gfx/gl/shader.cpp b/gfx/gl/shader.cpp
index 0bc127a..319726f 100644
--- a/gfx/gl/shader.cpp
+++ b/gfx/gl/shader.cpp
@@ -1,4 +1,5 @@
#include "shader.h"
+#include "msgException.h"
#include <algorithm>
#include <array>
#include <format>
@@ -7,17 +8,51 @@
namespace {
auto
- getInt(GLenum e)
+ getInt(GLenum pname)
{
- GLint i {};
- glGetIntegerv(e, &i);
- return std::to_string(i);
+ GLint data {};
+ glGetIntegerv(pname, &data);
+ return std::to_string(data);
}
using LookUpFunction = std::string (*)(GLenum);
- constexpr std::array<std::tuple<std::string_view, GLenum, LookUpFunction>, 1> LOOKUPS {{
+ constexpr auto LOOKUPS = std::to_array<std::tuple<std::string_view, GLenum, LookUpFunction>>({
{"GL_MAX_GEOMETRY_OUTPUT_VERTICES", GL_MAX_GEOMETRY_OUTPUT_VERTICES, getInt},
- }};
+ {"GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS", GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, getInt},
+ });
+
+ struct ShaderCompileError : public MsgException<std::invalid_argument> {
+ explicit ShaderCompileError(GLuint shader, Shader::Source src) :
+ MsgException<std::invalid_argument> {"Error compiling shader"}, shader {shader}, source {src},
+ msg {getShaderText(GL_INFO_LOG_LENGTH, glGetShaderInfoLog)}
+ {
+ }
+
+ [[nodiscard]] std::string
+ getMsg() const noexcept override
+ {
+ return std::format("Error compiling shader: '{}'\nSource:\n{}",
+ getShaderText(GL_INFO_LOG_LENGTH, glGetShaderInfoLog), source);
+ }
+
+ private:
+ std::string
+ getShaderText(GLenum param, auto getTextFunc) const
+ {
+ std::string text;
+ text.resize_and_overwrite(static_cast<size_t>(Shader::getShaderParam(shader, param)),
+ [this, getTextFunc](auto buf, auto len) {
+ GLsizei outLen {};
+ getTextFunc(shader, static_cast<GLsizei>(len), &outLen, buf);
+ return outLen;
+ });
+ return text;
+ }
+
+ const GLuint shader;
+ const Shader::Source source;
+ const std::string msg;
+ };
}
Shader::ShaderRef
@@ -29,8 +64,8 @@ Shader::compile() const
};
if (lookups) {
std::basic_string<GLchar> textMod {text};
- for (const auto & match : ctre::range<R"(\bGL_[A-Z_]+\b)">(textMod)) {
- if (const auto lookup = std::find_if(LOOKUPS.begin(), LOOKUPS.end(),
+ while (const auto match = ctre::search<R"(\bGL_[A-Z_]+\b)">(textMod)) {
+ if (const auto * const lookup = std::find_if(LOOKUPS.begin(), LOOKUPS.end(),
[&match](const auto & lookup) {
return std::get<std::string_view>(lookup) == match;
});
@@ -38,6 +73,9 @@ Shader::compile() const
const auto & [name, pname, getFunction] = *lookup;
textMod.replace(match.begin(), match.end(), getFunction(pname));
}
+ else {
+ throw std::domain_error(std::format("Unknown shader constant: {}", match.view()));
+ }
}
source(textMod.c_str(), static_cast<GLint>(textMod.length()));
}
@@ -46,31 +84,22 @@ Shader::compile() const
}
glCompileShader(shader);
- CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!");
+ checkShaderError(shader);
return shader;
}
void
-Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage)
+Shader::checkShaderError(GLuint shader) const
{
- GLint success = 0;
-
- if (isProgram) {
- glGetProgramiv(shader, flag, &success);
- }
- else {
- glGetShaderiv(shader, flag, &success);
+ if (getShaderParam(shader, GL_COMPILE_STATUS) == GL_FALSE) {
+ throw ShaderCompileError {shader, text};
}
+}
- if (success == GL_FALSE) {
- std::array<GLchar, 1024> error {};
- if (isProgram) {
- glGetProgramInfoLog(shader, error.size(), nullptr, error.data());
- }
- else {
- glGetShaderInfoLog(shader, error.size(), nullptr, error.data());
- }
-
- throw std::runtime_error {std::format("{}: '{}'", errorMessage, error.data())};
- }
+GLint
+Shader::getShaderParam(GLuint shader, GLenum pname)
+{
+ GLint pvalue {};
+ glGetShaderiv(shader, pname, &pvalue);
+ return pvalue;
}
diff --git a/gfx/gl/shader.h b/gfx/gl/shader.h
index c6b45af..ce97734 100644
--- a/gfx/gl/shader.h
+++ b/gfx/gl/shader.h
@@ -7,6 +7,7 @@
class Shader {
public:
+ using Source = std::basic_string_view<GLchar>;
using ShaderRef = glRef<GLuint, &glCreateShader, &glDeleteShader>;
constexpr Shader(const GLchar * text, GLuint type) :
@@ -15,10 +16,13 @@ public:
}
[[nodiscard]] ShaderRef compile() const;
- static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage);
+
+ [[nodiscard]] static GLint getShaderParam(GLuint shader, GLenum pname);
private:
- const std::basic_string_view<GLchar> text;
+ void checkShaderError(GLuint shader) const;
+
+ const Source text;
GLuint type;
bool lookups;
};
diff --git a/gfx/gl/shaders/commonPoint.glsl b/gfx/gl/shaders/commonPoint.glsl
index 2d9e388..dc534d5 100644
--- a/gfx/gl/shaders/commonPoint.glsl
+++ b/gfx/gl/shaders/commonPoint.glsl
@@ -1,17 +1,4 @@
-layout(binding = 1) uniform usampler2DRect materialData;
-
-MaterialDetail
-getMaterialDetail(uint midx)
-{
- if (midx > 0u) {
- const vec4 sPosSize = texture(materialData, uvec2(0, midx - 1u));
- const uvec4 sMode = texture(materialData, uvec2(1, midx - 1u));
- const uint mapmodeU = sMode.x & 0xFu;
- const uint mapmodeV = (sMode.x & 0xF0u) >> 1;
- return MaterialDetail(sPosSize.xy, sPosSize.zw, uvec2(mapmodeU, mapmodeV));
- }
- return MaterialDetail(vec2(0, 0), vec2(0, 0), uvec2(0, 0));
-}
+include(`getMaterialDetail.glsl')
void
main()
diff --git a/gfx/gl/shaders/commonShadowPoint.gs b/gfx/gl/shaders/commonShadowPoint.geom
index b99bd20..a515d97 100644
--- a/gfx/gl/shaders/commonShadowPoint.gs
+++ b/gfx/gl/shaders/commonShadowPoint.geom
@@ -1,5 +1,6 @@
-#version 330 core
-#extension GL_ARB_viewport_array : enable
+#version 460 core
+
+ifdef(`TEXTURES', include(`materialDetail.glsl'))
uniform mat4 viewProjection[4];
uniform int viewProjections;
@@ -7,7 +8,8 @@ in vec4 vworldPos[];
layout(triangles) in;
layout(triangle_strip, max_vertices = 12) out;
-ifdef(`TEXTURES', in vec2 vtexCoord[]; out vec2 texCoord;);
+ifdef(`TEXTURES', in vec2 TexCoords[]; out vec2 texCoord;)
+ifdef(`TEXTURES', flat in MaterialDetail Material[]; flat out MaterialDetail material;)
void
main()
@@ -17,7 +19,8 @@ main()
gl_Position = viewProjection[vp] * vworldPos[v];
gl_Position.z = max(gl_Position.z, -1);
gl_Layer = vp;
- ifdef(`TEXTURES', texCoord = vtexCoord[v];);
+ ifdef(`TEXTURES', texCoord = TexCoords[v];)
+ ifdef(`TEXTURES', material = Material[v];)
EmitVertex();
}
EndPrimitive();
diff --git a/gfx/gl/shaders/commonShadowPoint.glsl b/gfx/gl/shaders/commonShadowPoint.glsl
index c4ea827..9910d46 100644
--- a/gfx/gl/shaders/commonShadowPoint.glsl
+++ b/gfx/gl/shaders/commonShadowPoint.glsl
@@ -1,11 +1,10 @@
out vec4 vworldPos;
-ifdef(`TEXTURES', out vec2 vtexCoord;);
-
void
main()
{
vec3 worldPos = model * position;
vworldPos = vec4(worldPos - viewPoint + modelPos, 1);
- ifdef(`TEXTURES', vtexCoord = texCoord;);
+ ifdef(`TEXTURES', TexCoords = texCoord;);
+ ifdef(`TEXTURES', Material = getMaterialDetail(material););
}
diff --git a/gfx/gl/shaders/directionalLight.frag b/gfx/gl/shaders/directionalLight.frag
new file mode 100644
index 0000000..e5ebfb0
--- /dev/null
+++ b/gfx/gl/shaders/directionalLight.frag
@@ -0,0 +1,60 @@
+#version 460 core
+
+const int MAX_MAPS = 4;
+
+out vec3 FragColor;
+
+in vec2 TexCoords;
+
+layout(binding = 0) uniform isampler2D gPosition;
+layout(binding = 1) uniform sampler2D gNormal;
+layout(binding = 2) uniform sampler2DArray shadowMap;
+
+uniform vec3 lightDirection;
+uniform vec3 lightColour;
+uniform ivec3 lightPoint;
+uniform mat4 lightViewProjection[MAX_MAPS];
+uniform uint lightViewProjectionCount;
+
+float
+getShadow(vec3 positionInLightSpace, float m, vec2 texelSize)
+{
+ float shadow = 0.0;
+ for (float x = -texelSize.x; x <= texelSize.x; x += texelSize.x) {
+ for (float y = -texelSize.y; y <= texelSize.y; y += texelSize.y) {
+ const float lightSpaceDepth = texture(shadowMap, vec3(positionInLightSpace.xy + vec2(x, y), m)).r;
+ shadow += step(positionInLightSpace.z, lightSpaceDepth + 0.001);
+ }
+ }
+ return shadow / 9.0;
+}
+
+float
+insideShadowCube(vec3 v, vec2 texelSize)
+{
+ const vec3 s = step(vec3(texelSize, 0), v) - step(vec3(1 - texelSize, 1), v);
+ return s.x * s.y * s.z;
+}
+
+float
+isShaded(vec4 Position)
+{
+ const vec2 texelSize = 1.0 / textureSize(shadowMap, 0).xy;
+ for (uint m = 0u; m < lightViewProjectionCount; m++) {
+ const vec3 positionInLightSpace = (lightViewProjection[m] * Position).xyz;
+ const float inside = insideShadowCube(positionInLightSpace, texelSize);
+ if (inside > 0) {
+ return getShadow(positionInLightSpace, m, texelSize);
+ }
+ }
+ return 1.0;
+}
+
+void
+main()
+{
+ const vec4 Position = vec4(texture(gPosition, TexCoords).xyz - lightPoint, 1);
+ const vec3 Normal = texture(gNormal, TexCoords).rgb;
+ const float shaded = isShaded(Position);
+ FragColor = shaded * max(dot(-lightDirection, Normal) * lightColour, 0);
+}
diff --git a/gfx/gl/shaders/directionalLight.fs b/gfx/gl/shaders/directionalLight.fs
deleted file mode 100644
index 24457b8..0000000
--- a/gfx/gl/shaders/directionalLight.fs
+++ /dev/null
@@ -1,50 +0,0 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
-
-const int MAX_MAPS = 4;
-
-out vec3 FragColor;
-
-in vec2 TexCoords;
-
-layout(binding = 0) uniform isampler2D gPosition;
-layout(binding = 1) uniform sampler2D gNormal;
-layout(binding = 2) uniform sampler2DArray shadowMap;
-
-uniform vec3 lightDirection;
-uniform vec3 lightColour;
-uniform ivec3 lightPoint;
-uniform mat4 lightViewProjection[MAX_MAPS];
-uniform uint lightViewProjectionCount;
-
-const vec3 e1 = vec3(0, 0, 0), e2 = vec3(1, 1, 1);
-
-float
-insideShadowCube(vec3 v)
-{
- const vec3 s = step(e1, v) - step(e2, v);
- return s.x * s.y * s.z;
-}
-
-float
-isShaded(vec4 Position)
-{
- for (uint m = 0u; m < lightViewProjectionCount; m++) {
- const vec3 PositionInLightSpace = (lightViewProjection[m] * Position).xyz;
- const float inside = insideShadowCube(PositionInLightSpace);
- if (inside > 0) {
- const float lightSpaceDepth = texture(shadowMap, vec3(PositionInLightSpace.xy, m)).r;
- return step(lightSpaceDepth, PositionInLightSpace.z);
- }
- }
- return 0;
-}
-
-void
-main()
-{
- const vec4 Position = vec4(texture(gPosition, TexCoords).xyz - lightPoint, 1);
- const vec3 Normal = texture(gNormal, TexCoords).rgb;
- const float shaded = isShaded(Position);
- FragColor = (1 - shaded) * max(dot(-lightDirection, Normal) * lightColour, 0);
-}
diff --git a/gfx/gl/shaders/dynamicPoint.vs b/gfx/gl/shaders/dynamicPoint.vert
index 7551688..cd5fc26 100644
--- a/gfx/gl/shaders/dynamicPoint.vs
+++ b/gfx/gl/shaders/dynamicPoint.vert
@@ -1,5 +1,6 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
+
+layout(binding = 1) uniform usampler2DRect materialData;
include(`meshIn.glsl')
include(`materialInterface.glsl')
diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vert
index 69eab0c..46fead9 100644
--- a/gfx/gl/shaders/dynamicPointInst.vs
+++ b/gfx/gl/shaders/dynamicPointInst.vert
@@ -1,5 +1,6 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
+
+layout(binding = 1) uniform usampler2DRect materialData;
include(`meshIn.glsl')
include(`materialInterface.glsl')
diff --git a/gfx/gl/shaders/fixedPoint.vs b/gfx/gl/shaders/fixedPoint.vert
index 5cfe9b3..9201251 100644
--- a/gfx/gl/shaders/fixedPoint.vs
+++ b/gfx/gl/shaders/fixedPoint.vert
@@ -1,5 +1,6 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
+
+layout(binding = 1) uniform usampler2DRect materialData;
include(`meshIn.glsl')
include(`materialInterface.glsl')
diff --git a/gfx/gl/shaders/getMaterialDetail.glsl b/gfx/gl/shaders/getMaterialDetail.glsl
new file mode 100644
index 0000000..f819fb2
--- /dev/null
+++ b/gfx/gl/shaders/getMaterialDetail.glsl
@@ -0,0 +1,12 @@
+MaterialDetail
+getMaterialDetail(uint midx)
+{
+ if (midx > 0u) {
+ const vec4 sPosSize = texture(materialData, uvec2(0, midx - 1u));
+ const uvec4 sMode = texture(materialData, uvec2(1, midx - 1u));
+ const uint mapmodeU = sMode.x & 0xFu;
+ const uint mapmodeV = (sMode.x & 0xF0u) >> 1;
+ return MaterialDetail(sPosSize.xy, sPosSize.zw, uvec2(mapmodeU, mapmodeV));
+ }
+ return MaterialDetail(vec2(0, 0), vec2(0, 0), uvec2(0, 0));
+}
diff --git a/gfx/gl/shaders/landmass.fs b/gfx/gl/shaders/landmass.frag
index 55e3c24..b5c7fa1 100644
--- a/gfx/gl/shaders/landmass.fs
+++ b/gfx/gl/shaders/landmass.frag
@@ -1,12 +1,12 @@
-#version 330 core
+#version 460 core
include(`materialOut.glsl')
in vec3 FragPos;
in vec3 Normal;
-flat in vec3 ColourBias;
uniform sampler2D texture0;
uniform ivec3 viewPoint;
+uniform vec3 colourBias;
const vec3 grass = vec3(.1, .4, .05);
const vec3 slope = vec3(.6, .6, .4);
@@ -35,8 +35,8 @@ main()
vec3 color = texture(texture0, vec2(position.xy % 10000) / 10000.0).rgb;
int height = position.z;
- if (ColourBias.r >= 0) {
- color *= ColourBias;
+ if (colourBias.r >= 0) {
+ color *= colourBias;
}
else if (height < beachline) { // Sandy beach
color *= sand;
diff --git a/gfx/gl/shaders/landmass.vs b/gfx/gl/shaders/landmass.vert
index 9617cb9..91fc7f8 100644
--- a/gfx/gl/shaders/landmass.vs
+++ b/gfx/gl/shaders/landmass.vert
@@ -1,13 +1,10 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
layout(location = 0) in ivec3 position;
layout(location = 1) in vec3 normal;
-layout(location = 2) in vec3 colourBias;
out vec3 FragPos;
out vec3 Normal;
-flat out vec3 ColourBias;
uniform mat4 viewProjection;
uniform ivec3 viewPoint;
@@ -17,7 +14,6 @@ main()
{
FragPos = position - viewPoint;
Normal = normal;
- ColourBias = colourBias;
gl_Position = viewProjection * vec4(FragPos, 1);
}
diff --git a/gfx/gl/shaders/lighting.fs b/gfx/gl/shaders/lighting.frag
index 4646b75..b5c6c8b 100644
--- a/gfx/gl/shaders/lighting.fs
+++ b/gfx/gl/shaders/lighting.frag
@@ -1,5 +1,4 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
out vec3 FragColor;
diff --git a/gfx/gl/shaders/lighting.vs b/gfx/gl/shaders/lighting.vert
index e07cd0a..1046379 100644
--- a/gfx/gl/shaders/lighting.vs
+++ b/gfx/gl/shaders/lighting.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
in ivec4 position;
diff --git a/gfx/gl/shaders/material.frag b/gfx/gl/shaders/material.frag
new file mode 100644
index 0000000..18a3169
--- /dev/null
+++ b/gfx/gl/shaders/material.frag
@@ -0,0 +1,18 @@
+#version 460 core
+
+layout(binding = 0) uniform sampler2D textureAlbedo;
+
+include(`materialInterface.glsl')
+include(`materialOut.glsl')
+include(`materialCommon.glsl')
+
+void
+main()
+{
+ vec4 textureColour = getTextureColour(Material, TexCoords);
+ float opaque = step(0.5, mix(textureColour.a, 1, Colour.a));
+ gPosition = ivec4(FragPos, opaque);
+ gNormal = vec4(Normal, opaque);
+ gl_FragDepth = mix(1.0, gl_FragCoord.z, opaque);
+ gAlbedoSpec = mix(textureColour, vec4(Colour.rgb, 1), Colour.a);
+}
diff --git a/gfx/gl/shaders/material.fs b/gfx/gl/shaders/material.fs
deleted file mode 100644
index 5b93707..0000000
--- a/gfx/gl/shaders/material.fs
+++ /dev/null
@@ -1,49 +0,0 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
-
-include(`materialInterface.glsl')
-include(`materialOut.glsl')
-
-layout(binding = 0) uniform sampler2D texture0;
-
-float map(uint mapmode, float value)
-{
- switch (mapmode) {
- case 0u: // Repeat
- return fract(value);
- case 1u: // Clamp to edge
- return clamp(0.0, 1.0, value);
- case 2u: // Mirror
- discard;
- case 3u: // Decal
- if (value != clamp(0.0, 1.0, value)) {
- discard;
- }
- }
- return 0;
-}
-
-vec2 map(uvec2 mapmode, vec2 value)
-{
- return vec2(map(mapmode.x, value.x), map(mapmode.y, value.y));
-}
-
-vec4 getTextureColour(MaterialDetail mat, vec2 uv)
-{
- if (mat.textureSize.x > 0) {
- const vec2 tSize = textureSize(texture0, 0);
- uv = (mat.textureOrigin + mat.textureSize * map(mat.mapmode, uv)) / tSize;
- }
- return texture(texture0, uv);
-}
-
-void
-main()
-{
- vec4 textureColour = getTextureColour(Material, TexCoords);
- float opaque = step(0.5, mix(textureColour.a, 1, Colour.a));
- gPosition = ivec4(FragPos, opaque);
- gNormal = vec4(Normal, opaque);
- gl_FragDepth = mix(1.0, gl_FragCoord.z, opaque);
- gAlbedoSpec = mix(textureColour, vec4(Colour.rgb, 1), Colour.a);
-}
diff --git a/gfx/gl/shaders/materialCommon.glsl b/gfx/gl/shaders/materialCommon.glsl
new file mode 100644
index 0000000..4c2fbf8
--- /dev/null
+++ b/gfx/gl/shaders/materialCommon.glsl
@@ -0,0 +1,33 @@
+float
+map(uint mapmode, float value)
+{
+ switch (mapmode) {
+ case 0u: // Repeat
+ return fract(value);
+ case 1u: // Clamp to edge
+ return clamp(0.0, 1.0, value);
+ case 2u: // Mirror
+ discard;
+ case 3u: // Decal
+ if (value != clamp(0.0, 1.0, value)) {
+ discard;
+ }
+ }
+ return 0.0;
+}
+
+vec2
+map(uvec2 mapmode, vec2 value)
+{
+ return vec2(map(mapmode.x, value.x), map(mapmode.y, value.y));
+}
+
+vec4
+getTextureColour(MaterialDetail mat, vec2 uv)
+{
+ if (mat.textureSize.x > 0) {
+ const vec2 tSize = textureSize(textureAlbedo, 0);
+ uv = (mat.textureOrigin + mat.textureSize * map(mat.mapmode, uv)) / tSize;
+ }
+ return texture(textureAlbedo, uv);
+}
diff --git a/gfx/gl/shaders/materialDetail.glsl b/gfx/gl/shaders/materialDetail.glsl
new file mode 100644
index 0000000..a208d50
--- /dev/null
+++ b/gfx/gl/shaders/materialDetail.glsl
@@ -0,0 +1,5 @@
+struct MaterialDetail {
+ vec2 textureOrigin;
+ vec2 textureSize;
+ uvec2 mapmode;
+};
diff --git a/gfx/gl/shaders/materialInterface.glsl b/gfx/gl/shaders/materialInterface.glsl
index 3a4796b..bf78290 100644
--- a/gfx/gl/shaders/materialInterface.glsl
+++ b/gfx/gl/shaders/materialInterface.glsl
@@ -1,13 +1,9 @@
-struct MaterialDetail {
- vec2 textureOrigin;
- vec2 textureSize;
- uvec2 mapmode;
-};
+include(`materialDetail.glsl')
-ifelse(TYPE, .fs, in, out) vec3 FragPos;
-ifelse(TYPE, .fs, in, out) vec2 TexCoords;
-ifelse(TYPE, .fs, in, out) vec3 Normal;
-ifelse(TYPE, .fs, in, out) vec4 Colour;
-flat
-ifelse(TYPE, .fs, in, out)
-MaterialDetail Material;
+define(INOUT, ifelse(TYPE, .frag, in, out))
+
+INOUT vec3 FragPos;
+INOUT vec2 TexCoords;
+INOUT vec3 Normal;
+INOUT vec4 Colour;
+flat INOUT MaterialDetail Material;
diff --git a/gfx/gl/shaders/network.fs b/gfx/gl/shaders/network.frag
index 4e347b4..2f291ea 100644
--- a/gfx/gl/shaders/network.fs
+++ b/gfx/gl/shaders/network.frag
@@ -1,5 +1,4 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
include(`materialOut.glsl')
in vec3 rposition;
diff --git a/gfx/gl/shaders/networkCommon.glsl b/gfx/gl/shaders/networkCommon.glsl
index 0bc3c1c..7aa911d 100644
--- a/gfx/gl/shaders/networkCommon.glsl
+++ b/gfx/gl/shaders/networkCommon.glsl
@@ -12,13 +12,19 @@ out vec2 texCoord;
out vec3 rposition;
float
+viewPointDist(const ivec3 position)
+{
+ return length(vec3(viewPoint - position));
+}
+
+float
segDist(const ivec3 a, const ivec3 b)
{
- return min(distance(viewPoint, a), distance(viewPoint, b));
+ return min(viewPointDist(a), viewPointDist(b));
}
ifelse(
- TYPE, .gs,
+ TYPE, .geom,
// Begin: Geometry shader only function
void doVertex(const ivec3 end, const uint v, const float texY, const mat2 rot) {
ivec3 vpos = end + ivec3(rot * profile[v].xy, profile[v].z);
diff --git a/gfx/gl/shaders/networkCurve.geom b/gfx/gl/shaders/networkCurve.geom
new file mode 100644
index 0000000..4a5b3db
--- /dev/null
+++ b/gfx/gl/shaders/networkCurve.geom
@@ -0,0 +1,17 @@
+#version 460 core
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 10) out;
+
+flat in ivec3 pos[];
+flat in mat2 rot[];
+flat in float tpos[];
+flat in float dist[];
+
+include(`networkCommon.glsl')
+
+void
+main()
+{
+ doSeg(min(dist[0], dist[1]), pos[0], pos[1], tpos[0], tpos[1], rot[0], rot[1]);
+}
diff --git a/gfx/gl/shaders/networkCurve.gs b/gfx/gl/shaders/networkCurve.gs
deleted file mode 100644
index 7cb6c42..0000000
--- a/gfx/gl/shaders/networkCurve.gs
+++ /dev/null
@@ -1,47 +0,0 @@
-#version 330 core
-
-flat in ivec3 apos[];
-flat in ivec3 bpos[];
-flat in ivec3 cpos[];
-flat in float reps[];
-flat in float aangle[];
-flat in float bangle[];
-flat in float radius[];
-
-layout(points) in;
-layout(triangle_strip, max_vertices = GL_MAX_GEOMETRY_OUTPUT_VERTICES) out;
-
-const mat2 rot = mat2(1);
-
-include(`networkCommon.glsl')
-
-mat2
-getRot(float angle)
-{
- return mat2(cos(angle), sin(angle), -sin(angle), cos(angle));
-}
-
-void
-main()
-{
- float segs = clamp(
- round(reps[0] * radius[0] / 1000), 4, floor(uint(GL_MAX_GEOMETRY_OUTPUT_VERTICES) / (profileLength * 2u)));
- vec3 arcstep = vec3((bangle[0] - aangle[0]), // angle
- reps[0], // texture
- (bpos[0].z - apos[0].z)) // height
- / segs;
-
- ivec3 prevPos = apos[0];
- mat2 prevRot = getRot(aangle[0]);
- float prevTex = 0;
- for (vec3 arc = arcstep; arc.y < reps[0] - 0.01; arc += arcstep) {
- mat2 rot = getRot(arc.x + aangle[0]);
- ivec3 pos = cpos[0] + ivec3(rot * vec2(radius[0], 0), arc.z);
- float tex = arc.y;
- doSeg(segDist(prevPos, pos), pos, prevPos, tex, prevTex, rot, prevRot);
- prevPos = pos;
- prevRot = rot;
- prevTex = tex;
- }
- doSeg(segDist(prevPos, bpos[0]), bpos[0], prevPos, reps[0], prevTex, getRot(bangle[0]), prevRot);
-}
diff --git a/gfx/gl/shaders/networkCurve.tesc b/gfx/gl/shaders/networkCurve.tesc
new file mode 100644
index 0000000..5a6e449
--- /dev/null
+++ b/gfx/gl/shaders/networkCurve.tesc
@@ -0,0 +1,37 @@
+#version 460 core
+
+layout(vertices = 1) out;
+
+flat in ivec3 pos[][2];
+flat in ivec2 cpos[];
+flat in float reps[];
+flat in float angles[][2];
+flat in float radius[];
+
+flat out ivec3 c_pos[][2];
+flat out ivec2 c_cpos[];
+flat out float c_reps[];
+flat out float c_angles[][2];
+flat out float c_radius[];
+
+float
+segments()
+{
+ const float arc = angles[gl_InvocationID][0] - angles[gl_InvocationID][1];
+ const float error = 100.;
+ const float diff = acos(1.f - (error / radius[gl_InvocationID]));
+ return clamp(arc / diff, arc, 180);
+}
+
+void
+main()
+{
+ c_pos[gl_InvocationID] = pos[gl_InvocationID];
+ c_cpos[gl_InvocationID] = cpos[gl_InvocationID];
+ c_reps[gl_InvocationID] = reps[gl_InvocationID];
+ c_angles[gl_InvocationID] = angles[gl_InvocationID];
+ c_radius[gl_InvocationID] = radius[gl_InvocationID];
+
+ gl_TessLevelOuter[0] = 1;
+ gl_TessLevelOuter[1] = segments();
+}
diff --git a/gfx/gl/shaders/networkCurve.tese b/gfx/gl/shaders/networkCurve.tese
new file mode 100644
index 0000000..9cc31e2
--- /dev/null
+++ b/gfx/gl/shaders/networkCurve.tese
@@ -0,0 +1,45 @@
+#version 460 core
+
+layout(isolines, equal_spacing, cw) in;
+
+flat in ivec3 c_pos[][2];
+flat in ivec2 c_cpos[];
+flat in float c_reps[];
+flat in float c_angles[][2];
+flat in float c_radius[];
+
+flat out ivec3 pos;
+flat out mat2 rot;
+flat out float tpos;
+flat out float dist;
+
+const float startTolerance = 1. / 200.;
+const float endTolerance = 1. - startTolerance;
+
+include(`networkCommon.glsl')
+
+mat2
+getRot(float angle)
+{
+ return mat2(cos(angle), sin(angle), -sin(angle), cos(angle));
+}
+
+void
+main()
+{
+ const float angle = mix(c_angles[0][1], c_angles[0][0], gl_TessCoord.x);
+ rot = getRot(angle);
+ if (gl_TessCoord.x < startTolerance) {
+ pos = c_pos[0][1];
+ }
+ else if (gl_TessCoord.x > endTolerance) {
+ pos = c_pos[0][0];
+ }
+ else {
+ const int height = int(mix(c_pos[0][1].z, c_pos[0][0].z, gl_TessCoord.x));
+ pos = ivec3(c_cpos[0] + ivec2(rot * vec2(c_radius[0], 0)), height);
+ }
+
+ tpos = c_reps[0] * gl_TessCoord.x;
+ dist = viewPointDist(pos);
+}
diff --git a/gfx/gl/shaders/networkCurve.vert b/gfx/gl/shaders/networkCurve.vert
new file mode 100644
index 0000000..7e363d3
--- /dev/null
+++ b/gfx/gl/shaders/networkCurve.vert
@@ -0,0 +1,23 @@
+#version 460 core
+
+layout(location = 0) in ivec3 v_pos[2];
+layout(location = 2) in ivec3 v_centre;
+layout(location = 3) in float v_reps;
+layout(location = 4) in float v_angles[2];
+layout(location = 6) in float v_radius;
+
+flat out ivec3 pos[2];
+flat out ivec2 cpos;
+flat out float reps;
+flat out float angles[2];
+flat out float radius;
+
+void
+main()
+{
+ pos = v_pos;
+ cpos = v_centre.xy;
+ reps = v_reps;
+ angles = v_angles;
+ radius = v_radius;
+}
diff --git a/gfx/gl/shaders/networkCurve.vs b/gfx/gl/shaders/networkCurve.vs
deleted file mode 100644
index f51bb87..0000000
--- a/gfx/gl/shaders/networkCurve.vs
+++ /dev/null
@@ -1,29 +0,0 @@
-#version 330 core
-
-layout(location = 0) in ivec3 v_apos;
-layout(location = 1) in ivec3 v_bpos;
-layout(location = 2) in ivec3 v_centre;
-layout(location = 3) in float v_reps;
-layout(location = 4) in float v_aangle;
-layout(location = 5) in float v_bangle;
-layout(location = 6) in float v_radius;
-
-flat out ivec3 apos;
-flat out ivec3 bpos;
-flat out ivec3 cpos;
-flat out float reps;
-flat out float aangle;
-flat out float bangle;
-flat out float radius;
-
-void
-main()
-{
- apos = v_apos;
- bpos = v_bpos;
- cpos = v_centre;
- reps = v_reps;
- aangle = v_aangle;
- bangle = v_bangle;
- radius = v_radius;
-}
diff --git a/gfx/gl/shaders/networkStraight.gs b/gfx/gl/shaders/networkStraight.geom
index 51df5fb..a0e57c8 100644
--- a/gfx/gl/shaders/networkStraight.gs
+++ b/gfx/gl/shaders/networkStraight.geom
@@ -1,17 +1,17 @@
-#version 330 core
+#version 460 core
-flat in ivec3 apos[];
-flat in ivec3 bpos[];
+layout(points) in;
+layout(triangle_strip, max_vertices = 10) out;
+
+flat in ivec3 pos[][2];
flat in mat2 rot[];
flat in float reps[];
flat in float dist[];
-layout(points) in;
-layout(triangle_strip, max_vertices = 10) out;
include(`networkCommon.glsl')
void
main()
{
- doSeg(dist[0], apos[0], bpos[0], 0.f, reps[0], rot[0], rot[0]);
+ doSeg(dist[0], pos[0][0], pos[0][1], 0.f, reps[0], rot[0], rot[0]);
}
diff --git a/gfx/gl/shaders/networkStraight.vs b/gfx/gl/shaders/networkStraight.vert
index 55f9c4f..91ba955 100644
--- a/gfx/gl/shaders/networkStraight.vs
+++ b/gfx/gl/shaders/networkStraight.vert
@@ -1,12 +1,10 @@
-#version 330 core
+#version 460 core
-layout(location = 0) in ivec3 v_apos;
-layout(location = 1) in ivec3 v_bpos;
+layout(location = 0) in ivec3 v_pos[2];
layout(location = 2) in mat2 v_rot;
layout(location = 4) in float v_reps;
-flat out ivec3 apos;
-flat out ivec3 bpos;
+flat out ivec3 pos[2];
flat out mat2 rot;
flat out float reps;
flat out float dist;
@@ -16,9 +14,8 @@ include(`networkCommon.glsl')
void
main()
{
- apos = v_apos;
- bpos = v_bpos;
+ pos = v_pos;
rot = v_rot;
reps = v_reps;
- dist = segDist(v_apos, v_bpos);
+ dist = segDist(v_pos[0], v_pos[1]);
}
diff --git a/gfx/gl/shaders/pointLight.fs b/gfx/gl/shaders/pointLight.frag
index 7531d3e..bb2c453 100644
--- a/gfx/gl/shaders/pointLight.fs
+++ b/gfx/gl/shaders/pointLight.frag
@@ -1,5 +1,4 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
out vec3 FragColor;
diff --git a/gfx/gl/shaders/pointLight.gs b/gfx/gl/shaders/pointLight.geom
index fc1d7c3..1ee7e06 100644
--- a/gfx/gl/shaders/pointLight.gs
+++ b/gfx/gl/shaders/pointLight.geom
@@ -1,6 +1,4 @@
-#version 330 core
-#extension GL_ARB_enhanced_layouts : enable
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
const vec3[] cube = vec3[]( // http://www.cs.umd.edu/gvil/papers/av_ts.pdf
vec3(-1, 1, 1), // Front-top-left
diff --git a/gfx/gl/shaders/pointLight.vs b/gfx/gl/shaders/pointLight.vert
index fbd031c..2fd5418 100644
--- a/gfx/gl/shaders/pointLight.vs
+++ b/gfx/gl/shaders/pointLight.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_colour;
diff --git a/gfx/gl/shaders/shadowDynamicPoint.vs b/gfx/gl/shaders/shadowDynamicPoint.vert
index 7335b9a..907378e 100644
--- a/gfx/gl/shaders/shadowDynamicPoint.vs
+++ b/gfx/gl/shaders/shadowDynamicPoint.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
include(`meshIn.glsl')
diff --git a/gfx/gl/shaders/shadowDynamicPointInst.vs b/gfx/gl/shaders/shadowDynamicPointInst.vert
index d0eb649..da4a76f 100644
--- a/gfx/gl/shaders/shadowDynamicPointInst.vs
+++ b/gfx/gl/shaders/shadowDynamicPointInst.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
include(`meshIn.glsl')
diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.frag b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.frag
new file mode 100644
index 0000000..cad9d9d
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.frag
@@ -0,0 +1,18 @@
+#version 460 core
+
+layout(binding = 3) uniform sampler2D textureAlbedo;
+
+include(`materialInterface.glsl')
+include(`materialCommon.glsl')
+
+in vec2 texCoord;
+flat in MaterialDetail material;
+
+void
+main()
+{
+ if (getTextureColour(material, texCoord).a < 0.5) {
+ discard;
+ }
+ gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs
deleted file mode 100644
index 90519e3..0000000
--- a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs
+++ /dev/null
@@ -1,15 +0,0 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
-
-layout(binding = 3) uniform sampler2D texture0;
-
-in vec2 texCoord;
-
-void
-main()
-{
- if (texture(texture0, texCoord).a < 0.5) {
- discard;
- }
- gl_FragDepth = gl_FragCoord.z;
-}
diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.geom b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.geom
new file mode 100644
index 0000000..3aaf9a8
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.geom
@@ -0,0 +1,3 @@
+define(`TEXTURES', 1)
+
+include(`commonShadowPoint.geom')
diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.gs b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.gs
deleted file mode 100644
index e6e213e..0000000
--- a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.gs
+++ /dev/null
@@ -1,3 +0,0 @@
-define(`TEXTURES', 1)
-
-include(`commonShadowPoint.gs')
diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert
new file mode 100644
index 0000000..41a47b0
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert
@@ -0,0 +1,14 @@
+#version 460 core
+
+layout(binding = 4) uniform usampler2DRect materialData;
+
+define(`TEXTURES', 1)
+include(`materialInterface.glsl')
+include(`getMaterialDetail.glsl')
+include(`meshIn.glsl')
+
+uniform ivec3 viewPoint;
+layout(location = 5) in mat3 model;
+layout(location = 8) in ivec3 modelPos;
+
+include(`commonShadowPoint.glsl')
diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs
deleted file mode 100644
index 27ad9d7..0000000
--- a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs
+++ /dev/null
@@ -1,3 +0,0 @@
-define(`TEXTURES', 1)
-
-include(`shadowDynamicPointInst.vs')
diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.frag b/gfx/gl/shaders/shadowDynamicPointStencil.frag
new file mode 100644
index 0000000..d6b8a0e
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointStencil.frag
@@ -0,0 +1,15 @@
+#version 460 core
+
+layout(binding = 0) uniform sampler2DArray stencilDepth;
+flat in vec3 scale;
+in vec3 texCoord;
+
+void
+main()
+{
+ float stDepth = texture(stencilDepth, texCoord).r;
+ if (stDepth >= 1) {
+ discard;
+ }
+ gl_FragDepth = gl_FragCoord.z + ((stDepth - 0.5) * scale.z);
+}
diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.geom b/gfx/gl/shaders/shadowDynamicPointStencil.geom
new file mode 100644
index 0000000..df8be8d
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointStencil.geom
@@ -0,0 +1,35 @@
+#version 460 core
+
+const vec2[] corners = vec2[4](vec2(-1, -1), vec2(-1, 1), vec2(1, -1), vec2(1, 1));
+const float tau = 6.28318531;
+
+uniform mat4 viewProjection[4];
+uniform int viewProjections;
+uniform vec3 sizes[4];
+uniform float size;
+
+in float vmodelYaw[];
+in ivec3 vworldPos[];
+
+flat out vec3 scale;
+out vec3 texCoord;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 16) out;
+
+void
+main()
+{
+ int viewAngle = int(round(4.0 + (vmodelYaw[0] / tau))) % 8;
+ for (gl_Layer = 0; gl_Layer < viewProjections; ++gl_Layer) {
+ scale = 2.0 * size / sizes[gl_Layer];
+ vec4 pos = viewProjection[gl_Layer] * vec4(vworldPos[0], 1);
+ for (int c = 0; c < corners.length(); ++c) {
+ gl_Position = pos + vec4(scale.xy * corners[c], 0, 0);
+ gl_Position.z = max(gl_Position.z, -1);
+ texCoord = vec3((corners[c] * 0.5) + 0.5, viewAngle);
+ EmitVertex();
+ }
+ EndPrimitive();
+ }
+}
diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.vert b/gfx/gl/shaders/shadowDynamicPointStencil.vert
new file mode 100644
index 0000000..b750b3e
--- /dev/null
+++ b/gfx/gl/shaders/shadowDynamicPointStencil.vert
@@ -0,0 +1,16 @@
+#version 460 core
+
+layout(location = 0) in ivec3 worldPos;
+layout(location = 1) in float modelYaw;
+uniform ivec3 viewPoint;
+uniform vec3 centre;
+
+out float vmodelYaw;
+out ivec3 vworldPos;
+
+void
+main()
+{
+ vmodelYaw = modelYaw;
+ vworldPos = worldPos - viewPoint + ivec3(centre);
+}
diff --git a/gfx/gl/shaders/shadowLandmass.vs b/gfx/gl/shaders/shadowLandmass.vert
index becf142..cf68fe5 100644
--- a/gfx/gl/shaders/shadowLandmass.vs
+++ b/gfx/gl/shaders/shadowLandmass.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
layout(location = 0) in ivec3 position;
diff --git a/gfx/gl/shaders/shadowStencil.frag b/gfx/gl/shaders/shadowStencil.frag
new file mode 100644
index 0000000..3269f69
--- /dev/null
+++ b/gfx/gl/shaders/shadowStencil.frag
@@ -0,0 +1,17 @@
+#version 460 core
+
+layout(binding = 0) uniform sampler2D textureAlbedo;
+
+include(`materialDetail.glsl')
+include(`materialCommon.glsl')
+in vec2 gTexCoords;
+flat in MaterialDetail gMaterial;
+
+void
+main()
+{
+ if (getTextureColour(gMaterial, gTexCoords).a < 0.5) {
+ discard;
+ }
+ gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/gfx/gl/shaders/shadowStencil.geom b/gfx/gl/shaders/shadowStencil.geom
new file mode 100644
index 0000000..53a4c19
--- /dev/null
+++ b/gfx/gl/shaders/shadowStencil.geom
@@ -0,0 +1,27 @@
+#version 460 core
+
+include(`materialDetail.glsl')
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices = 24) out;
+
+uniform mat4 viewProjection[8];
+in vec3 FragPos[];
+in vec2 TexCoords[];
+flat in MaterialDetail Material[];
+out vec2 gTexCoords;
+flat out MaterialDetail gMaterial;
+
+void
+main()
+{
+ for (gl_Layer = 0; gl_Layer < viewProjection.length(); ++gl_Layer) {
+ for (int v = 0; v < FragPos.length(); ++v) {
+ gl_Position = viewProjection[gl_Layer] * vec4(FragPos[v], 1);
+ gTexCoords = TexCoords[v];
+ gMaterial = Material[v];
+ EmitVertex();
+ }
+ EndPrimitive();
+ }
+}
diff --git a/gfx/gl/shaders/shadowStencil.vert b/gfx/gl/shaders/shadowStencil.vert
new file mode 100644
index 0000000..e6286e6
--- /dev/null
+++ b/gfx/gl/shaders/shadowStencil.vert
@@ -0,0 +1,19 @@
+#version 460 core
+
+layout(binding = 1) uniform usampler2DRect materialData;
+
+include(`meshIn.glsl')
+include(`materialDetail.glsl')
+include(`getMaterialDetail.glsl')
+
+out vec3 FragPos;
+out vec2 TexCoords;
+flat out MaterialDetail Material;
+
+void
+main()
+{
+ TexCoords = texCoord;
+ Material = getMaterialDetail(material);
+ FragPos = position;
+}
diff --git a/gfx/gl/shaders/spotLight.fs b/gfx/gl/shaders/spotLight.frag
index ad33458..1305dbd 100644
--- a/gfx/gl/shaders/spotLight.fs
+++ b/gfx/gl/shaders/spotLight.frag
@@ -1,5 +1,4 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
out vec3 FragColor;
diff --git a/gfx/gl/shaders/spotLight.gs b/gfx/gl/shaders/spotLight.geom
index 194812a..fec191e 100644
--- a/gfx/gl/shaders/spotLight.gs
+++ b/gfx/gl/shaders/spotLight.geom
@@ -1,6 +1,4 @@
-#version 330 core
-#extension GL_ARB_enhanced_layouts : enable
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
const vec3[] pyramid = vec3[]( // four-sided
vec3(0, 0, 0), // Apex
diff --git a/gfx/gl/shaders/spotLight.vs b/gfx/gl/shaders/spotLight.vert
index e0196c3..36d2ee5 100644
--- a/gfx/gl/shaders/spotLight.vs
+++ b/gfx/gl/shaders/spotLight.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_direction;
diff --git a/gfx/gl/shaders/uiShader.fs b/gfx/gl/shaders/uiShader.fs
deleted file mode 100644
index c5f4e92..0000000
--- a/gfx/gl/shaders/uiShader.fs
+++ /dev/null
@@ -1,11 +0,0 @@
-#version 330 core
-
-in vec2 texCoord0;
-
-uniform sampler2D sampler;
-
-void
-main()
-{
- gl_FragColor = texture(sampler, texCoord0);
-}
diff --git a/gfx/gl/shaders/uiShader.vs b/gfx/gl/shaders/uiShader.vs
deleted file mode 100644
index e9e4373..0000000
--- a/gfx/gl/shaders/uiShader.vs
+++ /dev/null
@@ -1,13 +0,0 @@
-#version 330 core
-
-in vec4 position;
-
-out vec2 texCoord0;
-uniform mat4 uiProjection;
-
-void
-main()
-{
- gl_Position = uiProjection * vec4(position.xy, 0.0, 1.0);
- texCoord0 = position.zw;
-}
diff --git a/gfx/gl/shaders/uiShaderFont.fs b/gfx/gl/shaders/uiShaderFont.fs
deleted file mode 100644
index a1ef6ef..0000000
--- a/gfx/gl/shaders/uiShaderFont.fs
+++ /dev/null
@@ -1,12 +0,0 @@
-#version 330 core
-
-in vec2 texCoord0;
-
-uniform sampler2D sampler;
-uniform vec3 colour;
-
-void
-main()
-{
- gl_FragColor = vec4(colour, texture(sampler, texCoord0).r);
-}
diff --git a/gfx/gl/shaders/water.fs b/gfx/gl/shaders/water.frag
index 0918d9f..a09e754 100644
--- a/gfx/gl/shaders/water.fs
+++ b/gfx/gl/shaders/water.frag
@@ -1,5 +1,4 @@
-#version 330 core
-#extension GL_ARB_shading_language_420pack : enable
+#version 460 core
in vec3 FragPos;
in vec2 TexCoords;
diff --git a/gfx/gl/shaders/water.vs b/gfx/gl/shaders/water.vert
index 58bf7b6..60e4fb8 100644
--- a/gfx/gl/shaders/water.vs
+++ b/gfx/gl/shaders/water.vert
@@ -1,4 +1,4 @@
-#version 330 core
+#version 460 core
layout(location = 0) in ivec3 position;
out vec3 FragPos;
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index a846a3d..7035162 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -1,30 +1,39 @@
#include "shadowMapper.h"
-#include "camera.h"
#include "collections.h"
-#include "gfx/gl/shaders/fs-shadowDynamicPointInstWithTextures.h"
-#include "gfx/gl/shaders/gs-commonShadowPoint.h"
-#include "gfx/gl/shaders/gs-shadowDynamicPointInstWithTextures.h"
-#include "gfx/gl/shaders/vs-shadowDynamicPoint.h"
-#include "gfx/gl/shaders/vs-shadowDynamicPointInst.h"
-#include "gfx/gl/shaders/vs-shadowDynamicPointInstWithTextures.h"
-#include "gfx/gl/shaders/vs-shadowLandmass.h"
+#include "game/gamestate.h"
+#include "gfx/aabb.h"
+#include "gfx/gl/shadowStenciller.h"
+#include "gfx/lightDirection.h"
+#include "gfx/renderable.h"
#include "gl_traits.h"
+#include "gldebug.h"
#include "location.h"
#include "maths.h"
#include "sceneProvider.h"
#include "sceneShader.h"
-#include "sorting.h"
+#include <gfx/camera.h>
+#include <gfx/gl/shaders/commonShadowPoint-geom.h>
+#include <gfx/gl/shaders/shadowDynamicPoint-vert.h>
+#include <gfx/gl/shaders/shadowDynamicPointInst-vert.h>
+#include <gfx/gl/shaders/shadowDynamicPointInstWithTextures-frag.h>
+#include <gfx/gl/shaders/shadowDynamicPointInstWithTextures-geom.h>
+#include <gfx/gl/shaders/shadowDynamicPointInstWithTextures-vert.h>
+#include <gfx/gl/shaders/shadowDynamicPointStencil-frag.h>
+#include <gfx/gl/shaders/shadowDynamicPointStencil-geom.h>
+#include <gfx/gl/shaders/shadowDynamicPointStencil-vert.h>
+#include <gfx/gl/shaders/shadowLandmass-vert.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/matrix.hpp>
#include <vector>
ShadowMapper::ShadowMapper(const TextureAbsCoord & s) :
- landmess {shadowLandmass_vs}, dynamicPointInst {shadowDynamicPointInst_vs},
- dynamicPointInstWithTextures {shadowDynamicPointInstWithTextures_vs, shadowDynamicPointInstWithTextures_gs,
- shadowDynamicPointInstWithTextures_fs},
+ landmess {shadowLandmass_vert}, dynamicPointInst {shadowDynamicPointInst_vert},
+ dynamicPointInstWithTextures {shadowDynamicPointInstWithTextures_vert, shadowDynamicPointInstWithTextures_geom,
+ shadowDynamicPointInstWithTextures_frag},
size {s}
{
+ glDebugScope _ {depthMap};
glBindTexture(GL_TEXTURE_2D_ARRAY, depthMap);
glTexImage3D(
GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, size.x, size.y, 4, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
@@ -45,13 +54,15 @@ ShadowMapper::ShadowMapper(const TextureAbsCoord & s) :
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
-constexpr std::array<GlobalDistance, ShadowMapper::SHADOW_BANDS + 1> shadowBands {
- 1000,
- 250000,
- 750000,
- 2500000,
- 10000000,
-};
+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)))...};
+ }(4.6F, std::make_integer_sequence<GlobalDistance, ShadowMapper::SHADOW_BANDS>());
+
+static_assert(shadowBands.front() == 1);
+static_assert(shadowBands.back() == 10'000'000);
+static_assert(shadowBands.size() == ShadowMapper::SHADOW_BANDS + 1);
std::vector<std::array<RelativePosition3D, 4>>
ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightViewDir)
@@ -72,43 +83,59 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV
}
ShadowMapper::Definitions
-ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const Camera & camera) const
+ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, const Camera & camera) const
{
+ glDebugScope _ {depthMap};
+ glCullFace(GL_FRONT);
+ glEnable(GL_DEPTH_TEST);
+
+ shadowStenciller.setLightDirection(dir);
+ for (const auto & [id, asset] : gameState->assets) {
+ if (const auto r = asset.getAs<const Renderable>()) {
+ r->updateStencil(shadowStenciller);
+ }
+ }
+
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
- glCullFace(GL_FRONT);
glViewport(0, 0, size.x, size.y);
- const auto lightViewDir = glm::lookAt({}, dir, up);
+ const auto lightViewDir = glm::lookAt({}, dir.vector(), up);
const auto lightViewPoint = camera.getPosition();
const auto bandViewExtents = getBandViewExtents(camera, lightViewDir);
Definitions out;
- std::transform(bandViewExtents.begin(), std::prev(bandViewExtents.end()), std::next(bandViewExtents.begin()),
- std::back_inserter(out),
- [bands = bandViewExtents.size() - 2, &lightViewDir](const auto & near, const auto & far) mutable {
- const auto extents_minmax = [extents = std::span {near.begin(), far.end()}](auto && comp) {
- const auto mm = std::minmax_element(extents.begin(), extents.end(), comp);
- return std::make_pair(comp.get(*mm.first), comp.get(*mm.second));
- };
-
- 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_minmax(CompareBy {0}), extents_minmax(CompareBy {1}), extents_minmax(CompareBy {2}));
-
+ Sizes sizes;
+ 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}) {
- p->setView(out, lightViewPoint);
+ &landmess, &dynamicPoint, &dynamicPointInst, &dynamicPointInstWithTextures, &stencilShadowProgram}) {
+ p->setView(out, sizes, lightViewPoint);
+ }
+ ExtentsBoundingBox extents {lightViewPoint, lightViewPoint};
+ for (const auto & point : bandViewExtents.back()) {
+ extents += point;
}
- scene.shadows(*this);
+ 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);
return out;
}
-ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs) : Program {vs, commonShadowPoint_gs} { }
+ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs) : Program {vs, commonShadowPoint_geom} { }
ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs, const Shader & gs, const Shader & fs) :
Program {vs, gs, fs}
@@ -116,12 +143,15 @@ ShadowMapper::ShadowProgram::ShadowProgram(const Shader & vs, const Shader & gs,
}
void
-ShadowMapper::ShadowProgram::setView(
- const std::span<const glm::mat4> viewProjection, const GlobalPosition3D viewPoint) const
+ShadowMapper::ShadowProgram::setView(const std::span<const glm::mat4x4> viewProjection,
+ const std::span<const RelativePosition3D> sizes, const GlobalPosition3D viewPoint) const
{
use();
glUniform(viewPointLoc, viewPoint);
glUniform(viewProjectionLoc, viewProjection);
+ if (sizesLoc) {
+ glUniform(sizesLoc, sizes);
+ }
glUniform(viewProjectionsLoc, static_cast<GLint>(viewProjection.size()));
}
@@ -131,7 +161,7 @@ ShadowMapper::ShadowProgram::use() const
glUseProgram(*this);
}
-ShadowMapper::DynamicPoint::DynamicPoint() : ShadowProgram {shadowDynamicPoint_vs} { }
+ShadowMapper::DynamicPoint::DynamicPoint() : ShadowProgram {shadowDynamicPoint_vert} { }
void
ShadowMapper::DynamicPoint::use(const Location & location) const
@@ -146,3 +176,16 @@ ShadowMapper::DynamicPoint::setModel(const Location & location) const
glUniform(modelLoc, location.getRotationTransform());
glUniform(modelPosLoc, location.pos);
}
+
+ShadowMapper::StencilShadowProgram::StencilShadowProgram() :
+ ShadowProgram {shadowDynamicPointStencil_vert, shadowDynamicPointStencil_geom, shadowDynamicPointStencil_frag}
+{
+}
+
+void
+ShadowMapper::StencilShadowProgram::use(const RelativePosition3D & centre, const float size) const
+{
+ Program::use();
+ glUniform(centreLoc, centre);
+ glUniform(sizeLoc, size);
+}
diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h
index 73dadd0..951e29c 100644
--- a/gfx/gl/shadowMapper.h
+++ b/gfx/gl/shadowMapper.h
@@ -1,6 +1,7 @@
#pragma once
#include "config/types.h"
+#include "gfx/gl/shadowStenciller.h"
#include "lib/glArrays.h"
#include "program.h"
#include <gfx/models/texture.h>
@@ -10,6 +11,7 @@
class SceneProvider;
class Camera;
+class LightDirection;
class ShadowMapper {
public:
@@ -18,20 +20,23 @@ public:
static constexpr std::size_t SHADOW_BANDS {4};
using Definitions = std::vector<glm::mat4x4>;
+ using Sizes = std::vector<RelativePosition3D>;
- [[nodiscard]] Definitions update(const SceneProvider &, const Direction3D & direction, const Camera &) const;
+ [[nodiscard]] Definitions update(const SceneProvider &, const LightDirection & direction, const Camera &) const;
class ShadowProgram : public Program {
public:
explicit ShadowProgram(const Shader & vs);
explicit ShadowProgram(const Shader & vs, const Shader & gs, const Shader & fs);
- void setView(const std::span<const glm::mat4>, const GlobalPosition3D) const;
+ void setView(const std::span<const glm::mat4x4>, const std::span<const RelativePosition3D>,
+ const GlobalPosition3D) const;
void use() const;
private:
RequiredUniformLocation viewProjectionLoc {*this, "viewProjection"};
RequiredUniformLocation viewProjectionsLoc {*this, "viewProjections"};
+ UniformLocation sizesLoc {*this, "sizes"};
RequiredUniformLocation viewPointLoc {*this, "viewPoint"};
};
@@ -46,8 +51,19 @@ public:
RequiredUniformLocation modelPosLoc {*this, "modelPos"};
};
+ class StencilShadowProgram : public ShadowProgram {
+ public:
+ StencilShadowProgram();
+ void use(const RelativePosition3D & centre, const float size) const;
+
+ private:
+ RequiredUniformLocation centreLoc {*this, "centre"};
+ RequiredUniformLocation sizeLoc {*this, "size"};
+ };
+
ShadowProgram landmess, dynamicPointInst, dynamicPointInstWithTextures;
DynamicPoint dynamicPoint;
+ StencilShadowProgram stencilShadowProgram;
// NOLINTNEXTLINE(hicpp-explicit-conversions)
operator GLuint() const
@@ -61,4 +77,5 @@ private:
glFrameBuffer depthMapFBO;
glTexture depthMap;
TextureAbsCoord size;
+ mutable ShadowStenciller shadowStenciller;
};
diff --git a/gfx/gl/shadowStenciller.cpp b/gfx/gl/shadowStenciller.cpp
new file mode 100644
index 0000000..aee7161
--- /dev/null
+++ b/gfx/gl/shadowStenciller.cpp
@@ -0,0 +1,76 @@
+#include "shadowStenciller.h"
+#include "gfx/lightDirection.h"
+#include "gfx/models/mesh.h"
+#include "glArrays.h"
+#include "gl_traits.h"
+#include "gldebug.h"
+#include "maths.h"
+#include <gfx/gl/shaders/shadowStencil-frag.h>
+#include <gfx/gl/shaders/shadowStencil-geom.h>
+#include <gfx/gl/shaders/shadowStencil-vert.h>
+#include <stdexcept>
+
+ShadowStenciller::ShadowStenciller() :
+ shadowCaster {shadowStencil_vert, shadowStencil_geom, shadowStencil_frag}, viewProjections {}
+{
+ glDebugScope _ {fbo};
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void
+ShadowStenciller::setLightDirection(const LightDirection & lightDir)
+{
+ viewProjections = [&lightDir]<GLint... Ep>(std::integer_sequence<GLint, Ep...>) {
+ constexpr float STEP = two_pi / STENCIL_ANGLES<decltype(two_pi)>;
+ return std::array {rotate_pitch<4>(half_pi - lightDir.position().y)
+ * rotate_yaw<4>((Ep * STEP) - lightDir.position().x)...};
+ }(std::make_integer_sequence<GLint, STENCIL_ANGLES<GLint>>());
+}
+
+glTexture
+ShadowStenciller::createStencilTexture(GLsizei width, GLsizei height)
+{
+ glTexture stencil;
+ glBindTexture(GL_TEXTURE_2D_ARRAY, stencil);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, width, height, STENCIL_ANGLES<GLint>, 0,
+ GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
+
+ return stencil;
+}
+
+void
+ShadowStenciller::renderStencil(const glTexture & stencil, const MeshBase & mesh, const Texture::AnyPtr texture) const
+{
+ glDebugScope _ {fbo};
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, stencil, 0);
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ throw std::runtime_error("Stencil framebuffer not complete!");
+ }
+ if (texture) {
+ texture->bind();
+ }
+ glUseProgram(shadowCaster);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ const auto stencilSize = Texture::getSize(stencil);
+ glViewport(0, 0, stencilSize.x, stencilSize.y);
+ const auto & centre = mesh.getDimensions().centre;
+ const auto & size = mesh.getDimensions().size;
+ glUniform(viewProjectionLoc,
+ std::span<const glm::mat4> {viewProjections *
+ [extentsMat = glm::translate(glm::ortho(-size, size, -size, size, -size, size), -centre)](
+ const auto & viewProjection) {
+ return viewProjection * extentsMat;
+ }});
+ mesh.Draw();
+}
diff --git a/gfx/gl/shadowStenciller.h b/gfx/gl/shadowStenciller.h
new file mode 100644
index 0000000..f774ac7
--- /dev/null
+++ b/gfx/gl/shadowStenciller.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "gfx/gl/program.h"
+#include "gfx/models/mesh.h"
+#include "gfx/models/texture.h"
+#include "glArrays.h"
+
+class LightDirection;
+
+class ShadowStenciller {
+public:
+ template<typename T> static constexpr T STENCIL_ANGLES = 8;
+
+ ShadowStenciller();
+
+ [[nodiscard]]
+ static glTexture createStencilTexture(GLsizei width, GLsizei height);
+ void setLightDirection(const LightDirection & lightDir);
+ void renderStencil(const glTexture &, const MeshBase &, Texture::AnyPtr texture) const;
+
+private:
+ glFrameBuffer fbo;
+ Program shadowCaster;
+ Program::RequiredUniformLocation viewProjectionLoc {shadowCaster, "viewProjection"};
+
+ std::array<glm::mat4, STENCIL_ANGLES<size_t>> viewProjections;
+};
diff --git a/gfx/gl/uiShader.cpp b/gfx/gl/uiShader.cpp
deleted file mode 100644
index 23da9dc..0000000
--- a/gfx/gl/uiShader.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "uiShader.h"
-#include "gl_traits.h"
-#include <gfx/gl/program.h>
-#include <gfx/gl/shader.h>
-#include <gfx/gl/shaders/fs-uiShader.h>
-#include <gfx/gl/shaders/fs-uiShaderFont.h>
-#include <gfx/gl/shaders/vs-uiShader.h>
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-UIShader::IconProgram::IconProgram(const glm::mat4 & vp) : UIProgram {vp, uiShader_vs, uiShader_fs} { }
-
-UIShader::TextProgram::TextProgram(const glm::mat4 & vp) : UIProgram {vp, uiShader_vs, uiShaderFont_fs} { }
-
-UIShader::UIShader(size_t width, size_t height) :
- UIShader {glm::ortho<float>(0, static_cast<float>(width), 0, static_cast<float>(height))}
-{
-}
-
-UIShader::UIShader(const glm::mat4 & viewProjection) : icon {viewProjection}, text {viewProjection} { }
-
-void
-UIShader::TextProgram::use(const RGB & colour) const
-{
- Program::use();
- glUniform(colorLoc, colour);
-}
diff --git a/gfx/gl/uiShader.h b/gfx/gl/uiShader.h
deleted file mode 100644
index 6d00166..0000000
--- a/gfx/gl/uiShader.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include "config/types.h"
-#include "gl_traits.h"
-#include "program.h"
-#include <cstddef>
-#include <glad/gl.h>
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-class UIShader {
-public:
- UIShader(std::size_t width, std::size_t height);
-
-private:
- explicit UIShader(const glm::mat4 & viewProjection);
-
- class UIProgram : public Program {
- public:
- template<typename... S>
- explicit UIProgram(const glm::mat4 & vp, S &&... srcs) : Program {std::forward<S>(srcs)...}
- {
- const RequiredUniformLocation uiProjectionLoc {*this, "uiProjection"};
- glUseProgram(*this);
- glUniform(uiProjectionLoc, vp);
- }
- };
-
- class IconProgram : public UIProgram {
- public:
- explicit IconProgram(const glm::mat4 & vp);
- using Program::use;
- };
-
- class TextProgram : public UIProgram {
- public:
- explicit TextProgram(const glm::mat4 & vp);
- void use(const RGB & colour) const;
-
- private:
- RequiredUniformLocation colorLoc {*this, "colour"};
- };
-
-public:
- IconProgram icon;
- TextProgram text;
-};
diff --git a/gfx/gl/vertexArrayObject.h b/gfx/gl/vertexArrayObject.h
index 57daaf3..d008897 100644
--- a/gfx/gl/vertexArrayObject.h
+++ b/gfx/gl/vertexArrayObject.h
@@ -21,14 +21,15 @@ public:
NO_COPY(VertexArrayObject);
template<typename m, typename T> struct MP {
- constexpr MP(m T::*p) : P {p} { }
+ constexpr MP(m T::* p) : P {p} { }
+ constexpr
operator void *() const
{
return &(static_cast<T *>(nullptr)->*P);
}
- m T::*P;
+ m T::* P;
using value_type = m;
};
@@ -69,6 +70,13 @@ public:
return *this;
}
+ VertexArrayObject &
+ data(const GLuint arrayBuffer, GLenum target)
+ {
+ glBindBuffer(target, arrayBuffer);
+ return *this;
+ }
+
template<typename Data>
static void
data(const Data & data, const GLuint arrayBuffer, GLenum target)
diff --git a/gfx/lightDirection.cpp b/gfx/lightDirection.cpp
new file mode 100644
index 0000000..3932872
--- /dev/null
+++ b/gfx/lightDirection.cpp
@@ -0,0 +1,12 @@
+#include "lightDirection.h"
+#include "maths.h"
+
+constexpr auto ASTRONOMICAL_TWILIGHT = 18.0_degrees;
+constexpr auto SUN_ANGLUAR_SIZE = 0.5_degrees;
+
+LightDirection::LightDirection(const Direction2D sunPos) :
+ pos {sunPos}, vec {glm::mat3 {rotate_yp(pi + sunPos.x, -sunPos.y)} * north},
+ amb {glm::clamp(sunPos.y + ASTRONOMICAL_TWILIGHT, 0.F, 1.F)},
+ dir {glm::clamp(sunPos.y + SUN_ANGLUAR_SIZE, 0.F, 1.F)}
+{
+}
diff --git a/gfx/lightDirection.h b/gfx/lightDirection.h
new file mode 100644
index 0000000..789830b
--- /dev/null
+++ b/gfx/lightDirection.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "config/types.h"
+
+class LightDirection {
+public:
+ // NOLINTNEXTLINE(hicpp-explicit-conversions) deliberately a helper
+ LightDirection(Direction2D sunPos);
+
+ [[nodiscard]] Direction2D
+ position() const noexcept
+ {
+ return pos;
+ }
+
+ [[nodiscard]] Direction3D
+ vector() const noexcept
+ {
+ return vec;
+ }
+
+ [[nodiscard]] float
+ ambient() const noexcept
+ {
+ return amb;
+ }
+
+ [[nodiscard]] float
+ directional() const noexcept
+ {
+ return dir;
+ }
+
+private:
+ Direction2D pos;
+ Direction3D vec;
+ float amb;
+ float dir;
+};
diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp
index e7474ca..2eae160 100644
--- a/gfx/models/mesh.cpp
+++ b/gfx/models/mesh.cpp
@@ -1,6 +1,32 @@
#include "mesh.h"
-MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode) : m_numIndices {m_numIndices}, mode {mode} { }
+MeshBase::MeshBase(GLsizei m_numIndices, GLenum mode, const std::vector<RelativePosition3D> & positions) :
+ m_numIndices {m_numIndices}, mode {mode}, dimensions {positions}
+{
+}
+
+MeshBase::Dimensions::Dimensions(const std::span<const RelativePosition3D> positions) :
+ Dimensions {positions, {extents(positions, 0), extents(positions, 1), extents(positions, 2)}}
+{
+}
+
+MeshBase::Dimensions::Dimensions(
+ const std::span<const RelativePosition3D> positions, const std::array<Extents1D, 3> & extents1ds) :
+ minExtent(extents1ds[0].min, extents1ds[1].min, extents1ds[2].min),
+ maxExtent(extents1ds[0].max, extents1ds[1].max, extents1ds[2].max), centre {(minExtent + maxExtent) / 2.0F},
+ size {std::ranges::max(positions | std::views::transform([this](const auto & v) {
+ return glm::distance(v, centre);
+ }))}
+{
+}
+
+MeshBase::Dimensions::Extents1D
+MeshBase::Dimensions::extents(const std::span<const RelativePosition3D> positions, glm::length_t D)
+{
+ return std::ranges::minmax(positions | std::views::transform([D](const auto & v) {
+ return v[D];
+ }));
+}
void
MeshBase::Draw() const
diff --git a/gfx/models/mesh.h b/gfx/models/mesh.h
index 248cb8f..8791aed 100644
--- a/gfx/models/mesh.h
+++ b/gfx/models/mesh.h
@@ -1,8 +1,10 @@
#pragma once
+#include "config/types.h"
#include "gfx/gl/vertexArrayObject.h"
#include <glArrays.h>
#include <glad/gl.h>
+#include <ranges>
#include <span>
#include <stdTypeDefs.h>
@@ -10,22 +12,46 @@ class Vertex;
class MeshBase {
public:
+ class Dimensions {
+ public:
+ using Extents1D = std::ranges::minmax_result<RelativeDistance>;
+ explicit Dimensions(const std::span<const RelativePosition3D>);
+
+ RelativePosition3D minExtent, maxExtent;
+ RelativePosition3D centre;
+ RelativeDistance size;
+
+ private:
+ Dimensions(const std::span<const RelativePosition3D>, const std::array<Extents1D, 3> &);
+ static Extents1D extents(const std::span<const RelativePosition3D>, glm::length_t D);
+ };
+
void Draw() const;
void DrawInstanced(GLuint vao, GLsizei count, GLuint base = 0) const;
+ [[nodiscard]] const Dimensions &
+ getDimensions() const
+ {
+ return dimensions;
+ }
+
protected:
- MeshBase(GLsizei m_numIndices, GLenum mode);
+ MeshBase(GLsizei m_numIndices, GLenum mode, const std::vector<RelativePosition3D> &);
glVertexArray m_vertexArrayObject;
glBuffers<2> m_vertexArrayBuffers;
GLsizei m_numIndices;
GLenum mode;
+ Dimensions dimensions;
};
template<typename V> class MeshT : public MeshBase, public ConstTypeDefs<MeshT<V>> {
public:
MeshT(const std::span<const V> vertices, const std::span<const unsigned int> indices, GLenum mode = GL_TRIANGLES) :
- MeshBase {static_cast<GLsizei>(indices.size()), mode}
+ MeshBase {static_cast<GLsizei>(indices.size()), mode,
+ materializeRange(vertices | std::views::transform([](const auto & v) {
+ return static_cast<RelativePosition3D>(v.pos);
+ }))}
{
VertexArrayObject::data(vertices, m_vertexArrayBuffers[0], GL_ARRAY_BUFFER);
VertexArrayObject::data(indices, m_vertexArrayBuffers[1], GL_ARRAY_BUFFER);
diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp
index 51223aa..3457fb5 100644
--- a/gfx/models/texture.cpp
+++ b/gfx/models/texture.cpp
@@ -50,6 +50,16 @@ Texture::Texture(GLsizei width, GLsizei height, const void * data, TextureOption
glTexParameter(type, GL_TEXTURE_MIN_FILTER, to.minFilter);
glTexParameter(type, GL_TEXTURE_MAG_FILTER, to.magFilter);
glTexImage2D(type, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ auto isMimmap = [](auto value) {
+ auto eqAnyOf = [value](auto... test) {
+ return (... || (value == test));
+ };
+ return eqAnyOf(
+ GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR);
+ };
+ if (isMimmap(to.minFilter) || isMimmap(to.magFilter)) {
+ glGenerateMipmap(type);
+ }
}
void
@@ -59,12 +69,13 @@ Texture::bind(GLenum unit) const
glBindTexture(type, m_texture);
}
-TextureAbsCoord
+TextureDimensions
Texture::getSize(const glTexture & texture)
{
- TextureAbsCoord size;
+ TextureDimensions size {};
glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_WIDTH, &size.x);
glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_HEIGHT, &size.y);
+ glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_DEPTH, &size.z);
return size;
}
@@ -73,7 +84,7 @@ Texture::save(
const glTexture & texture, GLenum format, GLenum type, uint8_t channels, const char * path, uint8_t tgaFormat)
{
const auto size = getSize(texture);
- const size_t dataSize = (static_cast<size_t>(size.x * size.y * channels));
+ const size_t dataSize = (static_cast<size_t>(size.x * size.y * size.z * channels));
const size_t fileSize = dataSize + sizeof(TGAHead);
filesystem::fh out {path, O_RDWR | O_CREAT, 0660};
@@ -81,7 +92,7 @@ Texture::save(
auto tga = out.mmap(fileSize, 0, PROT_WRITE, MAP_SHARED);
*tga.get<TGAHead>() = {
.format = tgaFormat,
- .size = size,
+ .size = {size.x, size.y * size.z},
.pixelDepth = static_cast<uint8_t>(8 * channels),
};
glPixelStorei(GL_PACK_ALIGNMENT, 1);
diff --git a/gfx/models/texture.h b/gfx/models/texture.h
index 689d378..d8c3b29 100644
--- a/gfx/models/texture.h
+++ b/gfx/models/texture.h
@@ -1,8 +1,9 @@
#pragma once
#include "config/types.h"
+#include "glArrays.h"
+#include "stdTypeDefs.h"
#include <filesystem>
-#include <glArrays.h>
#include <glm/fwd.hpp>
class Image;
@@ -20,7 +21,7 @@ struct TextureOptions {
static GLint glMapMode(MapMode);
};
-class Texture {
+class Texture : public StdTypeDefs<Texture> {
public:
virtual ~Texture() = default;
DEFAULT_MOVE_NO_COPY(Texture);
@@ -37,10 +38,10 @@ public:
static void saveDepth(const glTexture &, const char * path);
static void saveNormal(const glTexture &, const char * path);
static void savePosition(const glTexture &, const char * path);
+ static TextureDimensions getSize(const glTexture &);
protected:
static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat);
- static TextureAbsCoord getSize(const glTexture &);
glTexture m_texture;
GLenum type;
diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp
index 0340189..27f2459 100644
--- a/gfx/renderable.cpp
+++ b/gfx/renderable.cpp
@@ -6,6 +6,11 @@ Renderable::lights(const SceneShader &) const
}
void
-Renderable::shadows(const ShadowMapper &) const
+Renderable::shadows(const ShadowMapper &, const Frustum &) const
+{
+}
+
+void
+Renderable::updateStencil(const ShadowStenciller &) const
{
}
diff --git a/gfx/renderable.h b/gfx/renderable.h
index e126fff..140c570 100644
--- a/gfx/renderable.h
+++ b/gfx/renderable.h
@@ -3,7 +3,9 @@
#include <special_members.h>
class SceneShader;
+class Frustum;
class ShadowMapper;
+class ShadowStenciller;
class Renderable {
public:
@@ -11,7 +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;
};