diff --git a/res/content/base/preload.json b/res/content/base/preload.json index 56b9896e..80105543 100644 --- a/res/content/base/preload.json +++ b/res/content/base/preload.json @@ -5,7 +5,8 @@ "sounds": [ "blocks/door_open", "blocks/door_close", - "events/pickup" + "events/pickup", + "ambient/rain" ], "models": [ "drop-item" diff --git a/res/content/base/sounds/ambient/rain_0.ogg b/res/content/base/sounds/ambient/rain_0.ogg new file mode 100644 index 00000000..5a870d16 Binary files /dev/null and b/res/content/base/sounds/ambient/rain_0.ogg differ diff --git a/res/content/base/sounds/ambient/rain_1.ogg b/res/content/base/sounds/ambient/rain_1.ogg new file mode 100644 index 00000000..56ee339c Binary files /dev/null and b/res/content/base/sounds/ambient/rain_1.ogg differ diff --git a/res/content/base/sounds/ambient/rain_2.ogg b/res/content/base/sounds/ambient/rain_2.ogg new file mode 100644 index 00000000..deb63a93 Binary files /dev/null and b/res/content/base/sounds/ambient/rain_2.ogg differ diff --git a/res/content/base/sounds/ambient/rain_3.ogg b/res/content/base/sounds/ambient/rain_3.ogg new file mode 100644 index 00000000..9e354751 Binary files /dev/null and b/res/content/base/sounds/ambient/rain_3.ogg differ diff --git a/res/content/base/sounds/ambient/rain_4.ogg b/res/content/base/sounds/ambient/rain_4.ogg new file mode 100644 index 00000000..8c28dafb Binary files /dev/null and b/res/content/base/sounds/ambient/rain_4.ogg differ diff --git a/res/content/base/textures/particles/rain_splash_0.png b/res/content/base/textures/particles/rain_splash_0.png new file mode 100644 index 00000000..9aacb072 Binary files /dev/null and b/res/content/base/textures/particles/rain_splash_0.png differ diff --git a/res/content/base/textures/particles/rain_splash_1.png b/res/content/base/textures/particles/rain_splash_1.png new file mode 100644 index 00000000..a15f7abb Binary files /dev/null and b/res/content/base/textures/particles/rain_splash_1.png differ diff --git a/res/content/base/textures/particles/rain_splash_2.png b/res/content/base/textures/particles/rain_splash_2.png new file mode 100644 index 00000000..86c2b4a0 Binary files /dev/null and b/res/content/base/textures/particles/rain_splash_2.png differ diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 08e1b41e..62fc747d 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -209,7 +209,9 @@ void LevelScreen::update(float delta) { playerController->postUpdate(delta, !inputLocked, hud->isPause()); hud->update(hudVisible); - decorator->update(delta, *camera); + decorator->update( + hud->isPause() ? 0.0f : delta, *camera, worldRenderer->weather + ); } void LevelScreen::draw(float delta) { diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index 605e9ec6..4dde75d2 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -17,6 +17,8 @@ #include "util/stringutil.hpp" #include "engine/Engine.hpp" #include "io/io.hpp" +#include "audio/audio.hpp" +#include "maths/util.hpp" namespace fs = std::filesystem; @@ -80,8 +82,79 @@ void Decorator::addParticles(const Block& def, const glm::ivec3& pos) { } } +void Decorator::updateRandom( + float delta, + const glm::ivec3& areaCenter, + const WeatherPreset& weather +) { + util::PseudoRandom random(rand()); + + const auto& chunks = *player.chunks; + const auto& indices = *level.content.getIndices(); + + ParticlesPreset rainSplash; + rainSplash.frames = { + "particles:rain_splash_0", + "particles:rain_splash_1", + "particles:rain_splash_2" + }; + rainSplash.lifetime = 0.2f; + rainSplash.spawnInterval = 0.0f; + rainSplash.size = {0.2f, 0.2f, 0.2f}; + + auto pos = areaCenter + glm::ivec3( + random.rand32() % 12, + random.rand32() % 12, + random.rand32() % 12 + ); + if (auto vox = chunks.get(pos)) { + const auto& def = indices.blocks.require(vox->id); + auto dst2 = util::distance2(pos, areaCenter); + if (dst2 < 256 && def.obstacle && + !weather.fall.noise.empty()) { + bool is_covered = false; + for (int y = pos.y + 1; y < CHUNK_H; y++) { + if (indices.blocks.require(chunks.get(pos.x, y, pos.z)->id).obstacle) { + is_covered = true; + break; + } + } + if (!is_covered) { + if (dst2 < 128) { + auto treg = util::get_texture_region( + assets, "particles:rain_splash_0", "" + ); + renderer.particles->add(std::make_unique( + level, + glm::vec3{pos.x + random.randFloat(), pos.y + 1.1, pos.z + random.randFloat()}, + rainSplash, + treg.texture, + treg.region, + 2 + )); + } + if (random.rand() % 200 < 2 && pos.y < areaCenter.y + 1) { + auto sound = assets.get(weather.fall.noise); + audio::play( + sound, + pos, + false, + 1.0f, + 1.0f, + false, + audio::PRIORITY_LOW, + audio::get_channel_index("ambient") + ); + } + } + } + } +} + void Decorator::update( - float delta, const glm::ivec3& areaStart, const glm::ivec3& areaCenter + float delta, + const glm::ivec3& areaStart, + const glm::ivec3& areaCenter ) { int index = currentIndex; currentIndex = (currentIndex + BIG_PRIME) % UPDATE_BLOCKS; @@ -93,7 +166,8 @@ void Decorator::update( int lz = (index / UPDATE_AREA_DIAMETER) % UPDATE_AREA_DIAMETER; int ly = (index / UPDATE_AREA_DIAMETER / UPDATE_AREA_DIAMETER); - auto pos = areaStart + glm::ivec3(lx, ly, lz); + glm::ivec3 offset {lx, ly, lz}; + auto pos = areaStart + offset; if (auto vox = chunks.get(pos)) { const auto& def = indices.blocks.require(vox->id); @@ -103,11 +177,17 @@ void Decorator::update( } } -void Decorator::update(float delta, const Camera& camera) { +void Decorator::update( + float delta, const Camera& camera, const WeatherPreset& weather +) { glm::ivec3 pos = camera.position; for (int i = 0; i < ITERATIONS; i++) { update(delta, pos - glm::ivec3(UPDATE_AREA_DIAMETER / 2), pos); } + int randIters = std::min(50'000, static_cast(delta * 24'000)); + for (int i = 0; i < randIters; i++) { + updateRandom(delta, pos, weather); + } const auto& chunks = *player.chunks; const auto& indices = *level.content.getIndices(); auto iter = blockEmitters.begin(); diff --git a/src/graphics/render/Decorator.hpp b/src/graphics/render/Decorator.hpp index e1b7eb17..fb74d11a 100644 --- a/src/graphics/render/Decorator.hpp +++ b/src/graphics/render/Decorator.hpp @@ -18,6 +18,7 @@ class Block; class Engine; class LevelController; class WorldRenderer; +struct WeatherPreset; class Decorator { Engine& engine; @@ -31,7 +32,14 @@ class Decorator { NotePreset playerNamePreset {}; void update( - float delta, const glm::ivec3& areaStart, const glm::ivec3& areaCenter + float delta, + const glm::ivec3& areaStart, + const glm::ivec3& areaCenter + ); + void updateRandom( + float delta, + const glm::ivec3& areaCenter, + const WeatherPreset& weather ); void addParticles(const Block& def, const glm::ivec3& pos); public: @@ -43,5 +51,5 @@ public: Player& player ); - void update(float delta, const Camera& camera); + void update(float delta, const Camera& camera, const WeatherPreset& weather); }; diff --git a/src/graphics/render/PrecipitationRenderer.cpp b/src/graphics/render/PrecipitationRenderer.cpp index 21dcfba4..beef0ed1 100644 --- a/src/graphics/render/PrecipitationRenderer.cpp +++ b/src/graphics/render/PrecipitationRenderer.cpp @@ -92,14 +92,11 @@ static UVRegion calc_uv( return {u1, v1, u1 + m * scale, v1 + FACE_SIZE.y * scale}; } -void PrecipitationRenderer::render(const Camera& camera, float delta) { +void PrecipitationRenderer::render( + const Camera& camera, float delta, const WeatherPreset& weather +) { timer += delta; - WeatherPreset weather {}; - auto& fall = weather.fall; - fall.vspeed = 2.0f; - fall.texture = "misc/rain"; - const int radius = 6; const int depth = 12; @@ -116,7 +113,7 @@ void PrecipitationRenderer::render(const Camera& camera, float delta) { } batch->begin(); - auto& texture = assets.require(fall.texture); + auto& texture = assets.require(weather.fall.texture); texture.setMipMapping(false); batch->setTexture(&texture, {}); diff --git a/src/graphics/render/PrecipitationRenderer.hpp b/src/graphics/render/PrecipitationRenderer.hpp index 0a9a59ee..9a691aca 100644 --- a/src/graphics/render/PrecipitationRenderer.hpp +++ b/src/graphics/render/PrecipitationRenderer.hpp @@ -8,6 +8,7 @@ class Chunks; class Camera; class MainBatch; struct GraphicsSettings; +struct WeatherPreset; class PrecipitationRenderer { std::unique_ptr batch; @@ -28,5 +29,5 @@ public: ~PrecipitationRenderer(); - void render(const Camera& camera, float delta); + void render(const Camera& camera, float delta, const WeatherPreset& weather); }; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 0e40cf8a..8deb8527 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -101,6 +101,12 @@ WorldRenderer::WorldRenderer( settings.graphics.skyboxResolution.get(), assets->require("skybox_gen") ); + + weather = {}; + auto& fall = weather.fall; + fall.vspeed = 2.0f; + fall.texture = "misc/rain"; + fall.noise = "ambient/rain"; } WorldRenderer::~WorldRenderer() = default; @@ -196,7 +202,7 @@ void WorldRenderer::renderLevel( setupWorldShader(entityShader, camera, settings, fogFactor); entityShader.uniform1i("u_alphaClip", false); - precipitation->render(camera, pause ? 0.0f : delta); + precipitation->render(camera, pause ? 0.0f : delta, weather); skybox->unbind(); } diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index b1cb1fa9..4ac9299c 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -10,6 +10,8 @@ #include "typedefs.hpp" +#include "presets/WeatherPreset.hpp" + class Level; class Player; class Camera; @@ -73,6 +75,7 @@ public: std::unique_ptr particles; std::unique_ptr blockWraps; std::unique_ptr precipitation; + WeatherPreset weather; static bool showChunkBorders; static bool showEntitiesDebug; diff --git a/src/presets/WeatherPreset.cpp b/src/presets/WeatherPreset.cpp index ea0daaa5..7326eb7d 100644 --- a/src/presets/WeatherPreset.cpp +++ b/src/presets/WeatherPreset.cpp @@ -10,6 +10,7 @@ dv::value WeatherPreset::serialize() const { froot["vspeed"] = fall.vspeed; froot["hspeed"] = fall.hspeed; froot["scale"] = fall.scale; + froot["noise"] = fall.noise; root["fall"] = froot; return root; @@ -22,5 +23,6 @@ void WeatherPreset::deserialize(const dv::value& src) { froot.at("vspeed").get(fall.vspeed); froot.at("hspeed").get(fall.hspeed); froot.at("scale").get(fall.scale); + froot.at("noise").get(fall.noise); } } diff --git a/src/presets/WeatherPreset.hpp b/src/presets/WeatherPreset.hpp index b0f93210..404980b6 100644 --- a/src/presets/WeatherPreset.hpp +++ b/src/presets/WeatherPreset.hpp @@ -6,6 +6,8 @@ struct WeatherPreset : Serializable { struct { /// @brief Precipitation texture std::string texture; + /// @brief Fall sound + std::string noise; /// @brief Vertical speed float vspeed = 1.0f; /// @brief Max horizontal speed