diff options
Diffstat (limited to 'gfx')
41 files changed, 658 insertions, 147 deletions
diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp index 52dfb35..cf6da34 100644 --- a/gfx/followCameraController.cpp +++ b/gfx/followCameraController.cpp @@ -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/gl/program.cpp b/gfx/gl/program.cpp index 7287fde..fdd4c6f 100644 --- a/gfx/gl/program.cpp +++ b/gfx/gl/program.cpp @@ -10,10 +10,10 @@ void Program::linkAndValidate() const { 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 +22,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..20be1aa 100644 --- a/gfx/gl/program.h +++ b/gfx/gl/program.h @@ -1,6 +1,6 @@ #pragma once -#include "shader.h" +#include "shader.h" // IWYU pragma: export #include <glRef.h> #include <glad/gl.h> #include <glm/mat4x4.hpp> @@ -12,6 +12,8 @@ using ProgramRef = glRef<GLuint, &glCreateProgram, &glDeleteProgram>; class Program { public: + Program() = delete; + template<typename... S> explicit Program(const S &... srcs) { (glAttachShader(m_program, srcs.compile()), ...); @@ -31,6 +33,12 @@ public: return location; } + explicit + operator bool() const + { + return location >= 0; + } + protected: GLint location; }; @@ -47,6 +55,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..4e271db 100644 --- a/gfx/gl/sceneProvider.cpp +++ b/gfx/gl/sceneProvider.cpp @@ -5,7 +5,7 @@ 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 diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index e0938f2..b2a7d78 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -62,7 +62,7 @@ SceneRenderer::render(const SceneProvider & scene) const shader.setViewProjection(camera.getPosition(), camera.getViewProjection()); glViewport(0, 0, size.x, size.y); - // Geometry pass + // Geometry/colour pass - writes albedo, normal and position textures glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); @@ -73,7 +73,13 @@ SceneRenderer::render(const SceneProvider & scene) const glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); scene.content(shader); - // Illumination pass + // Environment pass - + // * ambient - clears illumination texture - see setAmbientLight + // * directional - updates shadowMapper, reads normal and position, writes illumination - see setDirectionalLight + scene.environment(shader, *this); + + // Scene lights pass - + // * per light - reads normal and position, writes illumination glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); glBlendFunc(GL_ONE, GL_ONE); glActiveTexture(GL_TEXTURE0); @@ -82,11 +88,10 @@ SceneRenderer::render(const SceneProvider & scene) const 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 + // Composition pass - reads albedo and illumination, writes output glBindFramebuffer(GL_FRAMEBUFFER, output); glViewport(0, 0, size.x, size.y); glCullFace(GL_BACK); @@ -109,14 +114,22 @@ SceneRenderer::setAmbientLight(const RGB & colour) const } 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) { 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(); } } @@ -142,8 +155,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..93470f5 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -1,6 +1,7 @@ #pragma once #include "camera.h" +#include "gfx/lightDirection.h" #include "glArrays.h" #include "program.h" #include "sceneProvider.h" @@ -14,7 +15,7 @@ public: 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; diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 4cbccb3..571538a 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -65,7 +65,7 @@ SceneShader::SceneProgram::setViewProjection(const GlobalPosition3D & viewPoint, void SceneShader::SceneProgram::setViewPort(const ViewPort & viewPort) const { - if (viewPortLoc >= 0) { + if (viewPortLoc) { glUseProgram(*this); glUniform(viewPortLoc, viewPort); } diff --git a/gfx/gl/shader.cpp b/gfx/gl/shader.cpp index 0bc127a..9a4c270 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> @@ -18,6 +19,39 @@ namespace { constexpr std::array<std::tuple<std::string_view, GLenum, LookUpFunction>, 1> LOOKUPS {{ {"GL_MAX_GEOMETRY_OUTPUT_VERTICES", GL_MAX_GEOMETRY_OUTPUT_VERTICES, 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 +63,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(), + for (const auto & match : ctre::search_all<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; }); @@ -46,31 +80,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); + if (getShaderParam(shader, GL_COMPILE_STATUS) == GL_FALSE) { + throw ShaderCompileError {shader, text}; } - else { - glGetShaderiv(shader, flag, &success); - } - - 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.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/commonShadowPoint.gs b/gfx/gl/shaders/commonShadowPoint.gs index b99bd20..2413cc0 100644 --- a/gfx/gl/shaders/commonShadowPoint.gs +++ b/gfx/gl/shaders/commonShadowPoint.gs @@ -1,13 +1,16 @@ #version 330 core #extension GL_ARB_viewport_array : enable +ifdef(`TEXTURES', include(`materialDetail.glsl')) + uniform mat4 viewProjection[4]; uniform int viewProjections; 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 +20,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/directionalLight.fs b/gfx/gl/shaders/directionalLight.fs index 24457b8..cdf0389 100644 --- a/gfx/gl/shaders/directionalLight.fs +++ b/gfx/gl/shaders/directionalLight.fs @@ -17,27 +17,38 @@ uniform ivec3 lightPoint; uniform mat4 lightViewProjection[MAX_MAPS]; uniform uint lightViewProjectionCount; -const vec3 e1 = vec3(0, 0, 0), e2 = vec3(1, 1, 1); +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) +insideShadowCube(vec3 v, vec2 texelSize) { - const vec3 s = step(e1, v) - step(e2, v); + 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); + const vec3 positionInLightSpace = (lightViewProjection[m] * Position).xyz; + const float inside = insideShadowCube(positionInLightSpace, texelSize); if (inside > 0) { - const float lightSpaceDepth = texture(shadowMap, vec3(PositionInLightSpace.xy, m)).r; - return step(lightSpaceDepth, PositionInLightSpace.z); + return getShadow(positionInLightSpace, m, texelSize); } } - return 0; + return 1; } void @@ -46,5 +57,5 @@ 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); + FragColor = shaded * max(dot(-lightDirection, Normal) * lightColour, 0); } diff --git a/gfx/gl/shaders/dynamicPoint.vs b/gfx/gl/shaders/dynamicPoint.vs index 7551688..97d2983 100644 --- a/gfx/gl/shaders/dynamicPoint.vs +++ b/gfx/gl/shaders/dynamicPoint.vs @@ -1,6 +1,8 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable +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.vs index 69eab0c..a85f9c9 100644 --- a/gfx/gl/shaders/dynamicPointInst.vs +++ b/gfx/gl/shaders/dynamicPointInst.vs @@ -1,6 +1,8 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable +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.vs index 5cfe9b3..435b3d1 100644 --- a/gfx/gl/shaders/fixedPoint.vs +++ b/gfx/gl/shaders/fixedPoint.vs @@ -1,6 +1,8 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable +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/material.fs b/gfx/gl/shaders/material.fs index 5b93707..37f2e27 100644 --- a/gfx/gl/shaders/material.fs +++ b/gfx/gl/shaders/material.fs @@ -1,41 +1,11 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable +layout(binding = 0) uniform sampler2D textureAlbedo; + 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); -} +include(`materialCommon.glsl') void main() diff --git a/gfx/gl/shaders/materialCommon.glsl b/gfx/gl/shaders/materialCommon.glsl new file mode 100644 index 0000000..3fe2237 --- /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; +} + +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..f2ca297 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, .fs, in, out)); + +INOUT vec3 FragPos; +INOUT vec2 TexCoords; +INOUT vec3 Normal; +INOUT vec4 Colour; +flat INOUT MaterialDetail Material; diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs index 90519e3..47ce9c0 100644 --- a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs +++ b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.fs @@ -1,14 +1,18 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable -layout(binding = 3) uniform sampler2D texture0; +layout(binding = 3) uniform sampler2D textureAlbedo; + +include(`materialInterface.glsl') +include(`materialCommon.glsl') in vec2 texCoord; +flat in MaterialDetail material; void main() { - if (texture(texture0, texCoord).a < 0.5) { + if (getTextureColour(material, texCoord).a < 0.5) { discard; } gl_FragDepth = gl_FragCoord.z; diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs index 27ad9d7..a76c87f 100644 --- a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs +++ b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vs @@ -1,3 +1,15 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +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(`shadowDynamicPointInst.vs') +include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.fs b/gfx/gl/shaders/shadowDynamicPointStencil.fs new file mode 100644 index 0000000..fe91b07 --- /dev/null +++ b/gfx/gl/shaders/shadowDynamicPointStencil.fs @@ -0,0 +1,16 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +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.gs b/gfx/gl/shaders/shadowDynamicPointStencil.gs new file mode 100644 index 0000000..7e81d97 --- /dev/null +++ b/gfx/gl/shaders/shadowDynamicPointStencil.gs @@ -0,0 +1,36 @@ +#version 330 core +#extension GL_ARB_viewport_array : enable + +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.vs b/gfx/gl/shaders/shadowDynamicPointStencil.vs new file mode 100644 index 0000000..0dd2d79 --- /dev/null +++ b/gfx/gl/shaders/shadowDynamicPointStencil.vs @@ -0,0 +1,17 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +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/shadowStencil.fs b/gfx/gl/shaders/shadowStencil.fs new file mode 100644 index 0000000..1164cc9 --- /dev/null +++ b/gfx/gl/shaders/shadowStencil.fs @@ -0,0 +1,18 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +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.gs b/gfx/gl/shaders/shadowStencil.gs new file mode 100644 index 0000000..2c3f9bd --- /dev/null +++ b/gfx/gl/shaders/shadowStencil.gs @@ -0,0 +1,28 @@ +#version 330 core +#extension GL_ARB_viewport_array : enable + +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.vs b/gfx/gl/shaders/shadowStencil.vs new file mode 100644 index 0000000..a15c4fb --- /dev/null +++ b/gfx/gl/shaders/shadowStencil.vs @@ -0,0 +1,20 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +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/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index a846a3d..1b95aa3 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -1,13 +1,20 @@ #include "shadowMapper.h" #include "camera.h" #include "collections.h" +#include "game/gamestate.h" #include "gfx/gl/shaders/fs-shadowDynamicPointInstWithTextures.h" +#include "gfx/gl/shaders/fs-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/gs-commonShadowPoint.h" #include "gfx/gl/shaders/gs-shadowDynamicPointInstWithTextures.h" +#include "gfx/gl/shaders/gs-shadowDynamicPointStencil.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-shadowDynamicPointStencil.h" #include "gfx/gl/shaders/vs-shadowLandmass.h" +#include "gfx/gl/shadowStenciller.h" +#include "gfx/lightDirection.h" +#include "gfx/renderable.h" #include "gl_traits.h" #include "location.h" #include "maths.h" @@ -45,13 +52,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)))...}; + }(6.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,34 +81,49 @@ 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 { + glCullFace(GL_FRONT); + glEnable(GL_DEPTH_TEST); + + shadowStenciller.setLightDirection(dir); + for (const auto & [id, asset] : gameState->assets) { + if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) { + 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; + Sizes sizes; 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)); - }; + [bands = bandViewExtents.size() - 2, &lightViewDir, &sizes](const auto & near, const auto & far) mutable { + const auto extents_minmax + = [extents = std::span {near.begin(), far.end()}](auto && comp, RelativeDistance extra) { + const auto mm = std::minmax_element(extents.begin(), extents.end(), comp); + return std::make_pair(comp.get(*mm.first) - extra, comp.get(*mm.second) + extra); + }; + const std::array extents = {extents_minmax(CompareBy {0}, 0), extents_minmax(CompareBy {1}, 0), + extents_minmax(CompareBy {2}, 10'000)}; const auto lightProjection = [](const auto & x, const auto & y, const auto & z) { return glm::ortho(x.first, x.second, y.first, y.second, -z.second, -z.first); - }(extents_minmax(CompareBy {0}), extents_minmax(CompareBy {1}), extents_minmax(CompareBy {2})); + }(extents[0], extents[1], extents[2]); + sizes.emplace_back(extents[0].second - extents[0].first, extents[1].second - extents[1].first, + extents[2].second - extents[2].first); 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); } scene.shadows(*this); @@ -116,12 +140,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())); } @@ -146,3 +173,16 @@ ShadowMapper::DynamicPoint::setModel(const Location & location) const glUniform(modelLoc, location.getRotationTransform()); glUniform(modelPosLoc, location.pos); } + +ShadowMapper::StencilShadowProgram::StencilShadowProgram() : + ShadowProgram {shadowDynamicPointStencil_vs, shadowDynamicPointStencil_gs, shadowDynamicPointStencil_fs} +{ +} + +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..86b77e4 --- /dev/null +++ b/gfx/gl/shadowStenciller.cpp @@ -0,0 +1,74 @@ +#include "shadowStenciller.h" +#include "gfx/gl/program.h" +#include "gfx/gl/shaders/fs-shadowStencil.h" +#include "gfx/gl/shaders/gs-shadowStencil.h" +#include "gfx/gl/shaders/vs-shadowStencil.h" +#include "gfx/lightDirection.h" +#include "gfx/models/mesh.h" +#include "glArrays.h" +#include "gl_traits.h" +#include "maths.h" +#include <stdexcept> + +ShadowStenciller::ShadowStenciller() : + shadowCaster {shadowStencil_vs, shadowStencil_gs, shadowStencil_fs}, viewProjections {} +{ + 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 +{ + 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/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..a508421 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -59,12 +59,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 +74,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 +82,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..3594968 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -9,3 +9,8 @@ void Renderable::shadows(const ShadowMapper &) const { } + +void +Renderable::updateStencil(const ShadowStenciller &) const +{ +} diff --git a/gfx/renderable.h b/gfx/renderable.h index e126fff..83522e3 100644 --- a/gfx/renderable.h +++ b/gfx/renderable.h @@ -4,6 +4,7 @@ class SceneShader; class ShadowMapper; +class ShadowStenciller; class Renderable { public: @@ -14,4 +15,6 @@ public: virtual void render(const SceneShader & shader) const = 0; virtual void lights(const SceneShader & shader) const; virtual void shadows(const ShadowMapper & shadowMapper) const; + + virtual void updateStencil(const ShadowStenciller & lightDir) const; }; |