diff --git a/src/graphics/render/PrecipitationRenderer.cpp b/src/graphics/render/PrecipitationRenderer.cpp index 95297f83..1050afd4 100644 --- a/src/graphics/render/PrecipitationRenderer.cpp +++ b/src/graphics/render/PrecipitationRenderer.cpp @@ -10,6 +10,7 @@ #include "maths/voxmaths.hpp" #include "util/CentredMatrix.hpp" #include "settings.hpp" +#include "presets/WeatherPreset.hpp" #include "voxels/Chunk.hpp" #include "voxels/Chunks.hpp" #include "window/Camera.hpp" @@ -62,33 +63,62 @@ static inline glm::vec4 light_at(const Chunks& chunks, int x, int y, int z) { ); } -void PrecipitationRenderer::render(const Camera& camera, float delta) { - timer += delta * 0.5f; - batch->begin(); +/// @brief 'Random' vertical texture coord offset to randomize rain layers +static constexpr float K = 21.41149; +/// @brief Precipitation face size +static constexpr glm::ivec2 FACE_SIZE {1, 16}; - util::PseudoRandom random(0); +static UVRegion calc_uv( + const glm::vec3& pos, + const glm::vec3& right, + float timer, + const WeatherPreset& weather +) { + static util::PseudoRandom random(0); + + float scale = weather.fall.scale; + + float m = glm::sign(right.x + right.z); + int ux = pos.x; + int uz = pos.z; + if (glm::abs(right.x) < glm::abs(right.z)) { + std::swap(ux, uz); + } + random.setSeed(uz); + float hspeed = (random.randFloat() * 2.0f - 1.0f) * weather.fall.hspeed; + float u1 = ux * scale + timer * hspeed * -m; + float v1 = timer * weather.fall.vspeed + pos.y * scale + uz * K; + + return {u1, v1, u1 + m * scale, v1 + FACE_SIZE.y * scale}; +} + +void PrecipitationRenderer::render(const Camera& camera, float delta) { + timer += delta; + + WeatherPreset weather {}; + auto& fall = weather.fall; + fall.texture = "misc/rain"; + + const int radius = 6; + const int depth = 12; int x = glm::floor(camera.position.x); int y = glm::floor(camera.position.y); int z = glm::floor(camera.position.z); - auto& texture = assets.require("misc/snow"); + util::CentredMatrix heights; + heights.setCenter(x, z); + for (int z = heights.beginY(); z < heights.endY(); z++) { + for (int x = heights.beginX(); x < heights.endX(); x++) { + heights.at(x, z) = getHeightAt(x, z); + } + } + + batch->begin(); + auto& texture = assets.require(fall.texture); texture.setMipMapping(false); batch->setTexture(&texture, {}); - const auto& front = camera.front; - glm::ivec2 size {1, 16}; - - float horizontal = 0.5f * 5; - - glm::vec4 light = light_at(chunks, x, y, z); - - const int radius = 6; - const int depth = 12; - float scale = 0.4f; - int quads = 0; - float k = 21.41149; - const struct { glm::vec3 right; glm::vec3 front; @@ -99,14 +129,6 @@ void PrecipitationRenderer::render(const Camera& camera, float delta) { {{0, 0, 1}, {1, 0, 0}}, }; - util::CentredMatrix heights; - heights.setCenter(x, z); - for (int z = heights.beginY(); z < heights.endY(); z++) { - for (int x = heights.beginX(); x < heights.endX(); x++) { - heights.at(x, z) = getHeightAt(x, z); - } - } - for (const auto& face : faces) { for (int lx = -radius; lx <= radius; lx++) { for (int lz = depth; lz > 0; lz--) { @@ -114,34 +136,20 @@ void PrecipitationRenderer::render(const Camera& camera, float delta) { glm::vec3 pos = face.right * static_cast(lx) + face.front * static_cast(lz); pos += glm::vec3(x, 0, z); - pos.y = glm::max(y - size.y / 2, heights.at(pos.x, pos.z)) + - size.y / 2 + 1; + pos.y = + glm::max(y - FACE_SIZE.y / 2, heights.at(pos.x, pos.z)) + + FACE_SIZE.y / 2 + 1; pos += glm::vec3(0.5f, 0.0f, 0.5f); - - // UV coords calculations - float m = glm::sign(face.right.x + face.right.z); - int ux = pos.x; - int uz = pos.z; - - if (glm::abs(face.right.x) < glm::abs(face.right.z)) { - std::swap(ux, uz); - } - - random.setSeed(uz); - float hspeed = (random.randFloat() * 2.0f - 1.0f) * horizontal; - float u1 = ux * scale + timer * hspeed * -m; - float v1 = timer + pos.y * scale + uz * k; // Draw - glm::vec4 light = light_at(chunks, pos.x, y, pos.z); batch->quad( pos, face.right, {0, 1, 0}, - size, - light, + FACE_SIZE, + light_at(chunks, pos.x, y, pos.z), glm::vec3(1.0f), - UVRegion(u1, v1, u1 + m * scale, v1 + size.y * scale) + calc_uv(pos, face.right, timer, weather) ); } } diff --git a/src/presets/WeatherPreset.cpp b/src/presets/WeatherPreset.cpp new file mode 100644 index 00000000..ea0daaa5 --- /dev/null +++ b/src/presets/WeatherPreset.cpp @@ -0,0 +1,26 @@ +#include "WeatherPreset.hpp" + +#include "data/dv_util.hpp" + +dv::value WeatherPreset::serialize() const { + auto root = dv::object(); + + auto froot = dv::object(); + froot["texture"] = fall.texture; + froot["vspeed"] = fall.vspeed; + froot["hspeed"] = fall.hspeed; + froot["scale"] = fall.scale; + root["fall"] = froot; + + return root; +} + +void WeatherPreset::deserialize(const dv::value& src) { + if (src.has("fall")) { + const auto& froot = src["fall"]; + froot.at("texture").get(fall.texture); + froot.at("vspeed").get(fall.vspeed); + froot.at("hspeed").get(fall.hspeed); + froot.at("scale").get(fall.scale); + } +} diff --git a/src/presets/WeatherPreset.hpp b/src/presets/WeatherPreset.hpp new file mode 100644 index 00000000..b0f93210 --- /dev/null +++ b/src/presets/WeatherPreset.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "interfaces/Serializable.hpp" + +struct WeatherPreset : Serializable { + struct { + /// @brief Precipitation texture + std::string texture; + /// @brief Vertical speed + float vspeed = 1.0f; + /// @brief Max horizontal speed + float hspeed = 0.1f; + /// @brief UV scaling + float scale = 0.1f; + } fall {}; + + dv::value serialize() const override; + void deserialize(const dv::value& src) override; +};