From a7ad219261fa1f5859c85f07ec74c1341254813a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 May 2026 02:02:06 +0300 Subject: [PATCH] test environment (sky) --- src/data/dv.hpp | 28 ++++ src/graphics/core/Cubemap.cpp | 23 ++- src/graphics/core/Cubemap.hpp | 1 + src/graphics/core/Framebuffer.cpp | 60 ++++--- src/graphics/core/Framebuffer.hpp | 3 +- src/graphics/core/Texture.cpp | 20 ++- src/graphics/core/Texture.hpp | 6 +- src/graphics/render/Skybox.cpp | 219 +++++++++++++++++--------- src/graphics/render/Skybox.hpp | 52 +++--- src/graphics/render/WorldRenderer.cpp | 146 +++++++++-------- src/graphics/render/WorldRenderer.hpp | 2 + src/world/Environment.cpp | 25 +++ src/world/Environment.hpp | 30 ++++ src/world/Level.hpp | 2 + 14 files changed, 421 insertions(+), 196 deletions(-) create mode 100644 src/world/Environment.cpp create mode 100644 src/world/Environment.hpp diff --git a/src/data/dv.hpp b/src/data/dv.hpp index 3c3f4a71e..8acd22136 100644 --- a/src/data/dv.hpp +++ b/src/data/dv.hpp @@ -9,6 +9,10 @@ #include #include +#ifdef VC_ENABLE_REFLECTION +#include "util/EnumMetadata.hpp" +#endif + namespace util { template class Buffer; } @@ -70,6 +74,14 @@ namespace dv { return ptr != nullptr; } + inline value* operator->() noexcept { + return ptr; + } + + inline const value* operator->() const noexcept { + return ptr; + } + inline value& operator*() noexcept { return *ptr; } @@ -78,6 +90,11 @@ namespace dv { return *ptr; } +#ifdef VC_ENABLE_REFLECTION + template + bool get(T& dst, const util::EnumMetadata& mt) const; +#endif + bool get(std::string& dst) const; bool get(bool& dst) const; bool get(char& dst) const; @@ -552,6 +569,17 @@ namespace dv { } return false; } + +#ifdef VC_ENABLE_REFLECTION + template + inline bool optionalvalue::get(T& dst, const util::EnumMetadata& mt) const { + if (ptr) { + return mt.getItem(ptr->asString(), dst); + } + return false; + } +#endif + inline bool optionalvalue::get(std::string& dst) const { if (ptr) { dst = ptr->asString(); diff --git a/src/graphics/core/Cubemap.cpp b/src/graphics/core/Cubemap.cpp index 631a8d7e4..e55fb3127 100644 --- a/src/graphics/core/Cubemap.cpp +++ b/src/graphics/core/Cubemap.cpp @@ -4,7 +4,7 @@ #include Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) - : Texture(0, width, height) + : Texture(0U, width, height, imageFormat) { glGenTextures(1, &id); glBindTexture(GL_TEXTURE_CUBE_MAP, id); @@ -14,7 +14,6 @@ Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - uint format = gl::to_glenum(imageFormat); for (uint face = 0; face < 6; face++) { glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, @@ -37,3 +36,23 @@ void Cubemap::bind() const { void Cubemap::unbind() const { glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } + +void Cubemap::reload(const ubyte* data, uint width, uint height) { + this->width = width; + this->height = height; + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + for (uint face = 0; face < 6; face++) { + glTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, + 0, + format, + width, + height, + 0, + format, + GL_UNSIGNED_BYTE, + data + ); + } + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} diff --git a/src/graphics/core/Cubemap.hpp b/src/graphics/core/Cubemap.hpp index 4ca1b9884..e266c4381 100644 --- a/src/graphics/core/Cubemap.hpp +++ b/src/graphics/core/Cubemap.hpp @@ -9,4 +9,5 @@ public: virtual void bind() const override; virtual void unbind() const override; + virtual void reload(const ubyte* data, uint w, uint h) override; }; diff --git a/src/graphics/core/Framebuffer.cpp b/src/graphics/core/Framebuffer.cpp index 5d6be967d..dde31f6be 100644 --- a/src/graphics/core/Framebuffer.cpp +++ b/src/graphics/core/Framebuffer.cpp @@ -1,14 +1,14 @@ #include "Framebuffer.hpp" #include + #include "Texture.hpp" #include "debug/Logger.hpp" static debug::Logger logger("gl-framebuffer"); Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr texture) - : fbo(fbo), depth(depth), texture(std::move(texture)) -{ + : fbo(fbo), depth(depth), texture(std::move(texture)) { if (this->texture) { width = this->texture->getWidth(); height = this->texture->getHeight(); @@ -18,35 +18,55 @@ Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr texture) } } -static std::unique_ptr create_texture(int width, int height, int format) { - GLuint tex; - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); +static std::unique_ptr create_texture( + int width, int height, bool alpha +) { + GLenum glformat = alpha ? GL_RGBA : GL_RGB; + + GLuint textureid; + glGenTextures(1, &textureid); + glBindTexture(GL_TEXTURE_2D, textureid); + glTexImage2D( + GL_TEXTURE_2D, + 0, + glformat, + width, + height, + 0, + glformat, + GL_UNSIGNED_BYTE, + nullptr + ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); - return std::make_unique(tex, width, height); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid, 0 + ); + return std::make_unique( + textureid, + width, + height, + alpha ? ImageFormat::RGBA8888 : ImageFormat::RGB888 + ); } -Framebuffer::Framebuffer(uint width, uint height, bool alpha) - : width(width), height(height) -{ +Framebuffer::Framebuffer(uint width, uint height, bool alpha) + : width(width), height(height) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); - format = alpha ? GL_RGBA : GL_RGB; - // Setup color attachment (texture) - texture = create_texture(width, height, format); + texture = create_texture(width, height, alpha); // Setup depth attachment glGenRenderbuffers(1, &depth); glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth + ); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { logger.error() << "framebuffer is not complete!"; @@ -60,6 +80,10 @@ Framebuffer::~Framebuffer() { glDeleteRenderbuffers(1, &depth); } +void Framebuffer::setTexture(std::unique_ptr texture) { + this->texture = std::move(texture); +} + void Framebuffer::bind() { glBindFramebuffer(GL_FRAMEBUFFER, fbo); } @@ -81,7 +105,7 @@ void Framebuffer::resize(uint width, uint height) { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); - texture = create_texture(width, height, format); + texture->resize(width, height); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -102,5 +126,5 @@ uint Framebuffer::getHeight() const { } uint Framebuffer::getFBO() const { - return fbo; + return fbo; } diff --git a/src/graphics/core/Framebuffer.hpp b/src/graphics/core/Framebuffer.hpp index 4d21449c5..f64d33f37 100644 --- a/src/graphics/core/Framebuffer.hpp +++ b/src/graphics/core/Framebuffer.hpp @@ -12,13 +12,14 @@ class Framebuffer : public Bindable { uint depth; uint width; uint height; - uint format; std::shared_ptr texture; public: Framebuffer(uint fbo, uint depth, std::unique_ptr texture); Framebuffer(uint width, uint height, bool alpha=false); ~Framebuffer(); + void setTexture(std::unique_ptr texture); + /// @brief Use framebuffer void bind() override; diff --git a/src/graphics/core/Texture.cpp b/src/graphics/core/Texture.cpp index d60bd2779..5f326d20c 100644 --- a/src/graphics/core/Texture.cpp +++ b/src/graphics/core/Texture.cpp @@ -7,8 +7,8 @@ uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it -Texture::Texture(uint id, uint width, uint height) - : id(id), width(width), height(height) { +Texture::Texture(uint id, uint width, uint height, ImageFormat imageFormat) + : id(id), width(width), height(height), format(gl::to_glenum(imageFormat)) { } Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFormat) @@ -17,7 +17,7 @@ Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFo glBindTexture(GL_TEXTURE_2D, id); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - GLenum format = gl::to_glenum(imageFormat); + format = gl::to_glenum(imageFormat); glTexImage2D( GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, static_cast(data) @@ -41,23 +41,27 @@ void Texture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } +void Texture::resize(uint width, uint height) { + reload(nullptr, width, height); +} + void Texture::reload(const ImageData& image) { - width = image.getWidth(); - height = image.getHeight(); reload(image.getData(), width, height); } void Texture::reload(const ubyte* data, uint width, uint height) { + this->width = width; + this->height = height; glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, static_cast(data)); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, + format, GL_UNSIGNED_BYTE, static_cast(data)); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); } void Texture::reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h) { glBindTexture(GL_TEXTURE_2D, id); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.getData()); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, image.getData()); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/src/graphics/core/Texture.hpp b/src/graphics/core/Texture.hpp index 3c8f1b4cb..50734a577 100644 --- a/src/graphics/core/Texture.hpp +++ b/src/graphics/core/Texture.hpp @@ -11,19 +11,21 @@ protected: uint id; uint width; uint height; + uint format; public: - Texture(uint id, uint width, uint height); + Texture(uint id, uint width, uint height, ImageFormat imageFormat); Texture(const ubyte* data, uint width, uint height, ImageFormat format); virtual ~Texture(); virtual void bind() const; virtual void unbind() const; - void reload(const ubyte* data, uint w, uint h); + virtual void reload(const ubyte* data, uint w, uint h); void reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h); void setNearestFilter(); void reload(const ImageData& image); + virtual void resize(uint w, uint h); void setMipMapping(bool flag, bool pixelated); diff --git a/src/graphics/render/Skybox.cpp b/src/graphics/render/Skybox.cpp index c546c62e3..79e5552af 100644 --- a/src/graphics/render/Skybox.cpp +++ b/src/graphics/render/Skybox.cpp @@ -1,47 +1,44 @@ #include "Skybox.hpp" -#include "assets/Assets.hpp" -#include "graphics/core/Shader.hpp" -#include "graphics/core/Mesh.hpp" -#include "graphics/core/Batch3D.hpp" -#include "graphics/core/Texture.hpp" -#include "graphics/core/Cubemap.hpp" -#include "graphics/core/Framebuffer.hpp" -#include "graphics/core/DrawContext.hpp" -#include "window/Window.hpp" -#include "window/Camera.hpp" -#include "maths/UVRegion.hpp" + +#include #include -#include -#include #include -#include #include +#include +#include + +#include "assets/Assets.hpp" +#include "graphics/core/Batch3D.hpp" +#include "graphics/core/Cubemap.hpp" +#include "graphics/core/DrawContext.hpp" +#include "graphics/core/Framebuffer.hpp" +#include "graphics/core/Mesh.hpp" +#include "graphics/core/Shader.hpp" +#include "graphics/core/Texture.hpp" +#include "maths/UVRegion.hpp" +#include "window/Camera.hpp" +#include "window/Window.hpp" using namespace advanced_pipeline; const int STARS_COUNT = 3000; + const int STARS_SEED = 632; -Skybox::Skybox(uint size, Shader& shader) - : size(size), - shader(shader), - batch3d(std::make_unique(4096)) -{ - auto cubemap = std::make_unique(size, size, ImageFormat::RGB888); +Skybox::Skybox(uint size, const Assets& assets) + : size(size), + assets(assets), + shader(assets.require("skybox_gen")), + batch3d(std::make_unique(4096)) { - uint fboid; - glGenFramebuffers(1, &fboid); - fbo = std::make_unique(fboid, 0, std::move(cubemap)); - - SkyboxVertex vertices[]{ + SkyboxVertex vertices[] { {{-1.0f, -1.0f}}, {{-1.0f, 1.0f}}, {{1.0f, 1.0f}}, {{-1.0f, -1.0f}}, {{1.0f, 1.0f}}, - {{1.0f, -1.0f}} - }; + {{1.0f, -1.0f}}}; mesh = std::make_unique>(vertices, 6); @@ -52,7 +49,7 @@ Skybox::Skybox(uint size, Shader& shader) false, glm::pi() * 0.25f, }); - + sprites.push_back(SkySprite { "misc/moon_flare", glm::pi() * 0.5f, @@ -68,20 +65,20 @@ Skybox::Skybox(uint size, Shader& shader) true, glm::pi() * 0.25f, }); + + setMode(mode); } Skybox::~Skybox() = default; -void Skybox::drawBackground( - const Camera& camera, const Assets& assets, int width, int height -) { +void Skybox::drawBackground(const Camera& camera, int width, int height) { auto backShader = assets.get("background"); backShader->use(); backShader->uniformMatrix("u_view", camera.getView(false)); backShader->uniform1f( "u_zoom", camera.zoom * camera.getFov() / glm::half_pi() ); - backShader->uniform1f("u_ar", float(width)/float(height)); + backShader->uniform1f("u_ar", float(width) / float(height)); backShader->uniform1i("u_skybox", 1); bind(); mesh->draw(); @@ -93,9 +90,7 @@ void Skybox::drawStars(float angle, float opacity) { random.setSeed(STARS_SEED); glm::mat4 rotation = glm::rotate( - glm::mat4(1.0f), - -angle + glm::pi() * 0.5f, - glm::vec3(0, 0, -1) + glm::mat4(1.0f), -angle + glm::pi() * 0.5f, glm::vec3(0, 0, -1) ); rotation = glm::rotate(rotation, sunAltitude, glm::vec3(1, 0, 0)); @@ -108,41 +103,20 @@ void Skybox::drawStars(float angle, float opacity) { glm::vec3 pos = glm::vec4(rx, ry, rz, 1) * rotation; float sopacity = random.randFloat(); - if (pos.y < 0.0f) - continue; + if (pos.y < 0.0f) continue; sopacity *= (0.2f + std::sqrt(std::cos(angle)) * 0.5f) - 0.05f; - glm::vec4 tint (1,1,1, sopacity * opacity); + glm::vec4 tint(1, 1, 1, sopacity * opacity); batch3d->point(pos * depth, tint); } batch3d->flushPoints(); } -void Skybox::draw( - const DrawContext& pctx, - const Camera& camera, - const Assets& assets, +void Skybox::drawSkySprites( float daytime, - float fog) -{ - const glm::uvec2& viewport = pctx.getViewport(); - - glActiveTexture(GL_TEXTURE0); - - drawBackground(camera, assets, viewport.x, viewport.y); - - DrawContext ctx = pctx.sub(); - ctx.setBlendMode(BlendMode::addition); - - auto shader = assets.get("ui3d"); - shader->use(); - shader->uniformMatrix("u_projview", camera.getProjView(false)); - shader->uniformMatrix("u_apply", glm::mat4(1.0f)); - batch3d->begin(); - - float angle = daytime * glm::pi() * 2.0f; - float opacity = glm::pow(1.0f - fog, 7.0f); - + float angle, + float opacity +) { float depthScale = 2e3; for (auto& sprite : sprites) { batch3d->texture(assets.get(sprite.texture)); @@ -159,39 +133,132 @@ void Skybox::draw( glm::vec3 pos = glm::vec4(0, distance, 0, 1) * rotation; glm::vec3 up = glm::vec4(depthScale, 0, 0, 1) * rotation; glm::vec3 right = glm::vec4(0, 0, depthScale, 1) * rotation; - glm::vec4 tint (1,1,1, opacity); + glm::vec4 tint(1, 1, 1, opacity); if (!sprite.emissive) { - tint *= 0.6f + std::cos(angle)*0.4; + tint *= 0.6f + std::cos(angle) * 0.4; } - batch3d->sprite(pos, right, - up, 1, 1, UVRegion(), tint); + batch3d->sprite(pos, right, up, 1, 1, UVRegion(), tint); } batch3d->flush(); - drawStars(angle, opacity); } -void Skybox::refresh(const DrawContext& pctx, float t, float mie, const glm::vec3& tint, const glm::vec3& hightlight, uint quality) { +void Skybox::draw( + const Environment& environment, + const DrawContext& pctx, + const Camera& camera, + float daytime, + float fog +) { + const glm::uvec2& viewport = pctx.getViewport(); + + glActiveTexture(GL_TEXTURE0); + + drawBackground(camera, viewport.x, viewport.y); + + float angle = daytime * glm::pi() * 2.0f; + float opacity = glm::pow(1.0f - fog, 7.0f); + + DrawContext ctx = pctx.sub(); + ctx.setBlendMode(BlendMode::addition); + + if (!environment.sky.sprites && !environment.sky.stars) { + return; + } + + auto shader = assets.get("ui3d"); + shader->use(); + shader->uniformMatrix("u_projview", camera.getProjView(false)); + shader->uniformMatrix("u_apply", glm::mat4(1.0f)); + batch3d->begin(); + + if (environment.sky.sprites) { + drawSkySprites(daytime, angle, opacity); + } + if (environment.sky.stars) { + drawStars(angle, opacity); + } +} + +void Skybox::setMode(SkyMode mode) { + if (this->mode == mode && fbo) { + return; + } + this->mode = mode; + + uint size = mode == SkyMode::BOX ? this->size : 1U; + prevT = std::numeric_limits().min(); + + uint fboid; + glGenFramebuffers(1, &fboid); + fbo = std::make_unique( + fboid, + false, + std::make_unique(size, size, ImageFormat::RGB888) + ); +} + +void Skybox::refresh( + const Environment& environment, + const DrawContext& pctx, + float dayTime, + float mie, + const glm::vec3& tint, + const glm::vec3& hightlight, + uint quality +) { + setMode(environment.sky.mode); + + if (mode == SkyMode::NONE) { + return; + } else if (mode == SkyMode::SOLID) { + DrawContext ctx = pctx.sub(); + ctx.setDepthMask(false); + ctx.setDepthTest(false); + ctx.setFramebuffer(fbo.get()); + ctx.setViewport({fbo->getWidth(), fbo->getHeight()}); + + auto cubemap = dynamic_cast(fbo->getTexture()); + assert(cubemap != nullptr); + + glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX); + cubemap->bind(); + + for (int face = 0; face < 6; face++) { + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, + cubemap->getId(), + 0 + ); + glClearColor(tint.r, tint.g, tint.b, 1); + glClear(GL_COLOR_BUFFER_BIT); + } + + cubemap->unbind(); + return; + } + frameid++; - float dayTime = t; DrawContext ctx = pctx.sub(); ctx.setDepthMask(false); ctx.setDepthTest(false); ctx.setFramebuffer(fbo.get()); - ctx.setViewport({size, size}); + ctx.setViewport({fbo->getWidth(), fbo->getHeight()}); auto cubemap = dynamic_cast(fbo->getTexture()); assert(cubemap != nullptr); - ready = true; glActiveTexture(GL_TEXTURE0 + TARGET_SKYBOX); cubemap->bind(); shader.use(); - t *= glm::two_pi(); + float t = dayTime * glm::two_pi(); lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)); - float sunAngle = glm::radians((t / glm::two_pi() - 0.25f) * 360.0f); - float x = -glm::cos(sunAngle + glm::pi() * 0.5f) * glm::radians(sunAltitude); + float sunAngle = glm::radians((dayTime - 0.25f) * 360.0f); + float x = -glm::cos(sunAngle + glm::pi() * 0.5f) * + glm::radians(sunAltitude); float y = sunAngle - glm::pi() * 0.5f; float z = glm::radians(0.0f); rotation = glm::rotate(glm::mat4(1.0f), y, glm::vec3(0, 1, 0)); @@ -207,7 +274,9 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, const glm::vec shader.uniform3f("u_lightDir", lightDir); shader.uniform1f("u_dayTime", dayTime); - if (glm::abs(mie-prevMie) + glm::abs(t-prevT) + glm::abs(prevHighlight.r - hightlight.r) >= 0.01) { + if (glm::abs(mie - prevMie) + glm::abs(t - prevT) + + glm::abs(prevHighlight.r - hightlight.r) >= + 0.01) { for (uint face = 0; face < 6; face++) { refreshFace(face, cubemap); } diff --git a/src/graphics/render/Skybox.hpp b/src/graphics/render/Skybox.hpp index d2dde6f5e..270dc066d 100644 --- a/src/graphics/render/Skybox.hpp +++ b/src/graphics/render/Skybox.hpp @@ -1,14 +1,18 @@ #pragma once +#include #include #include #include -#include -#include "typedefs.hpp" -#include "maths/fastmaths.hpp" -#include "graphics/core/MeshData.hpp" -template class Mesh; +#include "graphics/core/MeshData.hpp" +#include "maths/fastmaths.hpp" +#include "typedefs.hpp" +#include "world/Environment.hpp" + + +template +class Mesh; class Shader; class Assets; class Camera; @@ -21,8 +25,7 @@ struct SkyboxVertex { glm::vec2 position; static constexpr VertexAttribute ATTRIBUTES[] { - {VertexAttribute::Type::FLOAT, false, 2}, - {{}, 0}}; + {VertexAttribute::Type::FLOAT, false, 2}, {{}, 0}}; }; struct SkySprite { @@ -34,10 +37,11 @@ struct SkySprite { }; class Skybox { - std::unique_ptr fbo; + SkyMode mode = SkyMode::SOLID; uint size; + std::unique_ptr fbo; + const Assets& assets; Shader& shader; - bool ready = false; FastRandom random; glm::vec3 lightDir; @@ -53,30 +57,36 @@ class Skybox { glm::mat4 rotation; void drawStars(float angle, float opacity); - void drawBackground( - const Camera& camera, const Assets& assets, int width, int height - ); + void drawBackground(const Camera& camera, int width, int height); + void drawSkySprites(float daytime, float angle, float opacity); void refreshFace(uint face, Cubemap* cubemap); public: - Skybox(uint size, Shader& shader); + Skybox(uint size, const Assets& assets); ~Skybox(); + void setMode(SkyMode mode); + void draw( - const DrawContext& pctx, - const Camera& camera, - const Assets& assets, + const Environment& environment, + const DrawContext& pctx, + const Camera& camera, float daytime, float fog ); - void refresh(const DrawContext& pctx, float t, float mie, const glm::vec3& tint, const glm::vec3& hightlight, uint quality); + void refresh( + const Environment& environment, + const DrawContext& pctx, + float t, + float mie, + const glm::vec3& tint, + const glm::vec3& hightlight, + uint quality + ); void bind() const; void unbind() const; - bool isReady() const { - return ready; - } - const glm::vec3 getLightDir() const { + const glm::vec3& getLightDir() const { return lightDir; } }; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 2e150e1f7..e5d838f7d 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -1,12 +1,45 @@ #include "WorldRenderer.hpp" +#include + +#include +#include +#include +#include + +#include "BlockWrapsRenderer.hpp" +#include "ChunksRenderer.hpp" +#include "CloudsRenderer.hpp" +#include "DebugLinesRenderer.hpp" +#include "Emitter.hpp" +#include "HandsRenderer.hpp" +#include "ModelBatch.hpp" +#include "NamedSkeletons.hpp" +#include "ParticlesRenderer.hpp" +#include "PrecipitationRenderer.hpp" +#include "Skybox.hpp" +#include "TextNote.hpp" +#include "TextsRenderer.hpp" #include "assets/Assets.hpp" #include "assets/assets_util.hpp" +#include "coders/GLSLExtension.hpp" #include "content/Content.hpp" #include "engine/Engine.hpp" -#include "coders/GLSLExtension.hpp" -#include "frontend/LevelFrontend.hpp" #include "frontend/ContentGfxCache.hpp" +#include "frontend/LevelFrontend.hpp" +#include "graphics/commons/Model.hpp" +#include "graphics/core/Atlas.hpp" +#include "graphics/core/Batch3D.hpp" +#include "graphics/core/DrawContext.hpp" +#include "graphics/core/Font.hpp" +#include "graphics/core/Framebuffer.hpp" +#include "graphics/core/GBuffer.hpp" +#include "graphics/core/LineBatch.hpp" +#include "graphics/core/Mesh.hpp" +#include "graphics/core/PostProcessing.hpp" +#include "graphics/core/Shader.hpp" +#include "graphics/core/Shadows.hpp" +#include "graphics/core/Texture.hpp" #include "items/Inventory.hpp" #include "items/ItemDef.hpp" #include "items/ItemStack.hpp" @@ -25,38 +58,6 @@ #include "world/Level.hpp" #include "world/LevelEvents.hpp" #include "world/World.hpp" -#include "graphics/commons/Model.hpp" -#include "graphics/core/Atlas.hpp" -#include "graphics/core/Batch3D.hpp" -#include "graphics/core/DrawContext.hpp" -#include "graphics/core/LineBatch.hpp" -#include "graphics/core/Mesh.hpp" -#include "graphics/core/PostProcessing.hpp" -#include "graphics/core/Framebuffer.hpp" -#include "graphics/core/Shader.hpp" -#include "graphics/core/Texture.hpp" -#include "graphics/core/Font.hpp" -#include "graphics/core/Shadows.hpp" -#include "graphics/core/GBuffer.hpp" -#include "BlockWrapsRenderer.hpp" -#include "ParticlesRenderer.hpp" -#include "PrecipitationRenderer.hpp" -#include "HandsRenderer.hpp" -#include "NamedSkeletons.hpp" -#include "TextsRenderer.hpp" -#include "ChunksRenderer.hpp" -#include "DebugLinesRenderer.hpp" -#include "ModelBatch.hpp" -#include "Skybox.hpp" -#include "Emitter.hpp" -#include "TextNote.hpp" -#include "CloudsRenderer.hpp" - -#include -#include -#include -#include -#include using namespace advanced_pipeline; @@ -105,8 +106,7 @@ WorldRenderer::WorldRenderer( [this](LevelEventType, Chunk* chunk) { chunksRenderer->unload(chunk); } ); skybox = std::make_unique( - settings.graphics.skyboxResolution.get(), - assets.require("skybox_gen") + settings.graphics.skyboxResolution.get(), assets ); const auto& content = level.content; @@ -179,6 +179,11 @@ void WorldRenderer::setupWorldShader( } } +float WorldRenderer::calcFogFactor() const { + const auto& settings = engine.getSettings(); + return 15.0f / static_cast(settings.chunks.loadDistance.get() - 2); +} + void WorldRenderer::renderOpaque( const DrawContext& ctx, const Camera& camera, @@ -187,14 +192,13 @@ void WorldRenderer::renderOpaque( ) { texts->render(ctx, camera, settings, hudVisible, false); - bool culling = engine.getSettings().graphics.frustumCulling.get(); - float fogFactor = - 15.0f / static_cast(settings.chunks.loadDistance.get() - 2); + float fogFactor = calcFogFactor(); auto& entityShader = assets.require("entity"); setupWorldShader(entityShader, camera, settings, fogFactor); skybox->bind(); + bool culling = engine.getSettings().graphics.frustumCulling.get(); if (culling) { frustumCulling->update(camera.getProjView()); } @@ -213,22 +217,24 @@ void WorldRenderer::renderOpaque( auto& shader = assets.require("main"); auto& cloudsShader = assets.require("clouds"); - auto& linesShader = assets.require("lines"); setupWorldShader(shader, camera, settings, fogFactor); chunksRenderer->drawChunks(camera, shader); blockWraps->draw(ctx); - int cloudsQuality = settings.graphics.cloudsQuality.get(); - if (cloudsQuality > 0) { - setupWorldShader(cloudsShader, camera, settings, fogFactor); - cloudsRenderer->draw( - cloudsShader, weather, timer, fogFactor, camera, cloudsQuality - ); + if (level.environment.sky.clouds) { + int cloudsQuality = settings.graphics.cloudsQuality.get(); + if (cloudsQuality > 0) { + setupWorldShader(cloudsShader, camera, settings, fogFactor); + cloudsRenderer->draw( + cloudsShader, weather, timer, fogFactor, camera, cloudsQuality + ); + } } if (hudVisible) { + auto& linesShader = assets.require("lines"); renderLines(camera, linesShader, ctx); } skybox->unbind(); @@ -286,21 +292,19 @@ void WorldRenderer::refreshSettings(Shader** shaders) { int shadowsQuality = graphics.shadowsQuality.get() * gbufferPipeline; shadowMapping->setQuality(shadowsQuality); - + CompileTimeShaderSettings currentSettings { gbufferPipeline, shadowsQuality != 0, - graphics.ssao.get() && gbufferPipeline - }; - if ( - prevCTShaderSettings.advancedRender != currentSettings.advancedRender || + graphics.ssao.get() && gbufferPipeline}; + if (prevCTShaderSettings.advancedRender != currentSettings.advancedRender || prevCTShaderSettings.shadows != currentSettings.shadows || - prevCTShaderSettings.ssao != currentSettings.ssao - ) { + prevCTShaderSettings.ssao != currentSettings.ssao) { std::vector defines; if (currentSettings.shadows) defines.emplace_back("ENABLE_SHADOWS"); if (currentSettings.ssao) defines.emplace_back("ENABLE_SSAO"); - if (currentSettings.advancedRender) defines.emplace_back("ADVANCED_RENDER"); + if (currentSettings.advancedRender) + defines.emplace_back("ADVANCED_RENDER"); for (size_t i = 0; shaders[i]; i++) { shaders[i]->recompile(defines); @@ -332,7 +336,8 @@ void WorldRenderer::renderFrame( auto& entityShader = assets.require("entity"); auto& cloudsShader = assets.require("clouds"); auto& translucentShader = assets.require("translucent"); - auto& deferredShader = assets.require("deferred_lighting").getShader(); + auto& deferredShader = + assets.require("deferred_lighting").getShader(); const auto& settings = engine.getSettings(); @@ -342,19 +347,19 @@ void WorldRenderer::renderFrame( &cloudsShader, &translucentShader, &deferredShader, - nullptr - }; + nullptr}; refreshSettings(affectedShaders); const auto& worldInfo = world->getInfo(); - + float clouds = weather.clouds(); clouds = glm::max(worldInfo.fog, clouds); float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f; float random = rand() / static_cast(RAND_MAX); skybox->refresh( + level.environment, pctx, worldInfo.daytime, mie, @@ -385,8 +390,7 @@ void WorldRenderer::renderFrame( texts->render(pctx, camera, settings, hudVisible, true); } skybox->bind(); - float fogFactor = - 15.0f / static_cast(settings.chunks.loadDistance.get() - 2); + float fogFactor = calcFogFactor(); if (gbufferPipeline) { deferredShader.use(); setupWorldShader(deferredShader, camera, settings, fogFactor); @@ -403,7 +407,9 @@ void WorldRenderer::renderFrame( } // Background sky plane - skybox->draw(ctx, camera, assets, worldInfo.daytime, clouds); + skybox->draw( + level.environment, ctx, camera, worldInfo.daytime, clouds + ); auto& linesShader = assets.require("lines"); linesShader.use(); @@ -429,14 +435,17 @@ void WorldRenderer::renderFrame( entityShader.use(); setupWorldShader(entityShader, camera, settings, fogFactor); - std::array weatherInstances {&weather.a, &weather.b}; + std::array weatherInstances { + &weather.a, &weather.b}; for (const auto& weather : weatherInstances) { float maxIntensity = weather->fall.maxIntensity; float zero = weather->fall.minOpacity; float one = weather->fall.maxOpacity; float t = (weather->intensity * (one - zero)) * maxIntensity + zero; entityShader.uniform1i("u_alphaClip", weather->fall.opaque); - entityShader.uniform1f("u_opacity", weather->fall.opaque ? t * t : t); + entityShader.uniform1f( + "u_opacity", weather->fall.opaque ? t * t : t + ); if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) { precipitation->render(camera, *weather); } @@ -446,7 +455,7 @@ void WorldRenderer::renderFrame( glBindFramebuffer(GL_FRAMEBUFFER, 0); } postProcessing.render(pctx, assets, timer, camera); - + if (player.currentCamera == player.fpCamera) { DrawContext ctx = pctx.sub(); ctx.setDepthTest(true); @@ -457,7 +466,7 @@ void WorldRenderer::renderFrame( hudcam.far = 10.0f; hudcam.setFov(0.9f); hudcam.position = {}; - + hands->render(camera); display::clearDepth(); @@ -486,13 +495,12 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) { if (def.overlayTexture.empty()) { return; } - auto textureRegion = util::get_texture_region( - assets, def.overlayTexture, "blocks:notfound" - ); + auto textureRegion = + util::get_texture_region(assets, def.overlayTexture, "blocks:notfound"); DrawContext ctx = wctx.sub(); ctx.setDepthTest(false); ctx.setCullFace(false); - + auto& shader = assets.require("ui3d"); shader.use(); batch3d->begin(); diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index b9a893d16..c3e6b1669 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -99,6 +99,8 @@ class WorldRenderer { ); void refreshSettings(Shader** shaders); + + float calcFogFactor() const; public: std::unique_ptr particles; std::unique_ptr texts; diff --git a/src/world/Environment.cpp b/src/world/Environment.cpp new file mode 100644 index 000000000..d2ad414bf --- /dev/null +++ b/src/world/Environment.cpp @@ -0,0 +1,25 @@ +#define VC_ENABLE_REFLECTION +#include "Environment.hpp" + +#include "data/dv.hpp" +#include "data/dv_util.hpp" + +dv::value Environment::serialize() const { + return dv::object({ + {"sky", dv::object({ + {"mode", SkyModeMeta.getNameString(sky.mode)}, + {"stars", sky.stars}, + {"clouds", sky.clouds}, + {"sprites", sky.sprites}, + })}, + }); +} + +void Environment::deserialize(const dv::value& src) { + if (auto skyItem = src.at("sky")) { + skyItem->at("mode").get(sky.mode, SkyModeMeta); + skyItem->at("stars").get(sky.stars); + skyItem->at("clouds").get(sky.clouds); + skyItem->at("sprites").get(sky.sprites); + } +} diff --git a/src/world/Environment.hpp b/src/world/Environment.hpp new file mode 100644 index 000000000..5b5f668eb --- /dev/null +++ b/src/world/Environment.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "interfaces/Serializable.hpp" +#include "util/EnumMetadata.hpp" + +enum class SkyMode { + NONE, SOLID, BOX +}; + +VC_ENUM_METADATA(SkyMode) + {"none", SkyMode::NONE}, + {"solid", SkyMode::SOLID}, + {"box", SkyMode::BOX}, +VC_ENUM_END + +class Environment : public Serializable { +public: + struct { + SkyMode mode = SkyMode::BOX; + bool stars = true; + bool clouds = true; + bool sprites = true; + } sky; + + Environment() = default; + + dv::value serialize() const override; + void deserialize(const dv::value& src) override; +private: +}; diff --git a/src/world/Level.hpp b/src/world/Level.hpp index 0dd3251fa..c8945a23c 100644 --- a/src/world/Level.hpp +++ b/src/world/Level.hpp @@ -6,6 +6,7 @@ #include #include "typedefs.hpp" +#include "Environment.hpp" class Content; class World; @@ -36,6 +37,7 @@ public: std::unique_ptr players; std::unique_ptr pathfinding; std::vector> cameras; // move somewhere? + Environment environment {}; Level( std::unique_ptr world,