diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp index f05cda5f..6dabd8c6 100644 --- a/src/assets/Assets.cpp +++ b/src/assets/Assets.cpp @@ -34,7 +34,6 @@ void Assets::store(Shader* shader, std::string name){ shaders.emplace(name, shader); } - Font* Assets::getFont(std::string name) const { auto found = fonts.find(name); if (found == fonts.end()) diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index cd8f6d3e..16bf1afc 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -18,6 +18,7 @@ AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths) addLoader(ASSET_FONT, assetload::font); addLoader(ASSET_ATLAS, assetload::atlas); addLoader(ASSET_LAYOUT, assetload::layout); + addLoader(ASSET_SOUND, assetload::sound); } void AssetsLoader::addLoader(int tag, aloader_func func) { diff --git a/src/assets/AssetsLoader.h b/src/assets/AssetsLoader.h index 17826fa8..736216ff 100644 --- a/src/assets/AssetsLoader.h +++ b/src/assets/AssetsLoader.h @@ -52,6 +52,12 @@ class AssetsLoader { public: AssetsLoader(Assets* assets, const ResPaths* paths); void addLoader(int tag, aloader_func func); + + /// @brief Enqueue asset load + /// @param tag asset type + /// @param filename asset file path + /// @param alias internal asset name + /// @param settings asset loading settings (based on asset type) void add( int tag, const std::string filename, @@ -59,10 +65,12 @@ public: std::shared_ptr settings=nullptr ); - bool hasNext() const; bool loadNext(); + /// @brief Enqueue core and content assets + /// @param loader target loader + /// @param content engine content static void addDefaults(AssetsLoader& loader, const Content* content); const ResPaths* getPaths() const; diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 698a94f5..2b9b752d 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -20,6 +20,14 @@ namespace fs = std::filesystem; +static bool animation( + Assets* assets, + const ResPaths* paths, + const std::string directory, + const std::string name, + Atlas* dstAtlas +); + bool assetload::texture( AssetsLoader&, Assets* assets, @@ -102,7 +110,7 @@ bool assetload::atlas( Atlas* atlas = builder.build(2); assets->store(atlas, name); for (const auto& file : builder.getNames()) { - assetload::animation(assets, paths, "textures", file, atlas); + animation(assets, paths, "textures", file, atlas); } return true; } @@ -152,7 +160,6 @@ bool assetload::layout( return false; } } - bool assetload::sound( AssetsLoader& loader, Assets* assets, @@ -162,17 +169,43 @@ bool assetload::sound( std::shared_ptr config ) { auto cfg = dynamic_cast(config.get()); - auto sound = audio::load_sound(paths->find(file), cfg->keepPCM); - if (sound == nullptr) { - std::cerr << "failed to load sound '" << name << "' from '"; - std::cerr << file << "'" << std::endl; + bool keepPCM = cfg ? cfg->keepPCM : false; + + size_t lastindex = file.find_last_of("."); + std::string extension = file.substr(lastindex); + std::string extensionless = file.substr(0, lastindex); + try { + std::unique_ptr baseSound = nullptr; + + // looking for 'sound_name' as base sound + auto soundFile = paths->find(file); + if (fs::exists(soundFile)) { + baseSound.reset(audio::load_sound(soundFile, keepPCM)); + } + // looking for 'sound_name_0' as base sound + auto variantFile = paths->find(extensionless+"_0"+extension); + if (fs::exists(variantFile)) { + baseSound.reset(audio::load_sound(variantFile, keepPCM)); + } + + // loading sound variants + for (uint i = 1; ; i++) { + auto variantFile = paths->find(extensionless+"_"+std::to_string(i)+extension); + if (!fs::exists(variantFile)) { + break; + } + baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM)); + } + assets->store(baseSound.release(), name); + } + catch (std::runtime_error& err) { + std::cerr << err.what() << std::endl; return false; } - assets->store(sound, name); return true; } -bool assetload::animation( +static bool animation( Assets* assets, const ResPaths* paths, const std::string directory, diff --git a/src/assets/assetload_funcs.h b/src/assets/assetload_funcs.h index 893ba2a5..aebdb0a6 100644 --- a/src/assets/assetload_funcs.h +++ b/src/assets/assetload_funcs.h @@ -10,6 +10,7 @@ class AssetsLoader; class Atlas; struct AssetCfg; +/// @brief see AssetsLoader.h: aloader_func namespace assetload { bool texture( AssetsLoader&, @@ -60,14 +61,6 @@ namespace assetload { const std::string name, std::shared_ptr settings ); - - bool animation( - Assets*, - const ResPaths* paths, - const std::string directory, - const std::string name, - Atlas* dstAtlas - ); } -#endif // ASSETS_ASSET_LOADERS_H_ \ No newline at end of file +#endif // ASSETS_ASSET_LOADERS_H_ diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 4467490a..2c9d5c6e 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -157,10 +157,6 @@ void audio::initialize(bool enabled) { backend = NoAudio::create(); } create_channel("master"); - create_channel("regular"); - create_channel("music"); - create_channel("ambient"); - create_channel("ui"); } PCM* audio::load_PCM(const fs::path& file, bool headerOnly) { @@ -379,20 +375,32 @@ void audio::update(double delta) { } } -void audio::reset() { +void audio::reset_channel(int index) { + auto channel = get_channel(index); + if (channel == nullptr) { + return; + } for (auto& entry : speakers) { - entry.second->stop(); + if (entry.second->getChannel() == index) { + entry.second->stop(); + } } for (auto& entry : streams) { entry.second->update(0.0f); } - for (auto& channel : channels) { - if (channel->isPaused()) { - channel->resume(); + for (auto it = speakers.begin(); it != speakers.end();) { + auto speaker = it->second.get(); + int speakerChannel = speaker->getChannel(); + if (speakerChannel == index) { + streams.erase(it->first); + it = speakers.erase(it); + } else { + it++; } } - streams.clear(); - speakers.clear(); + if (channel->isPaused()) { + channel->resume(); + } } void audio::close() { diff --git a/src/audio/audio.h b/src/audio/audio.h index 772dde46..b5e7f07d 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -192,6 +192,9 @@ namespace audio { /// So it's audio data is stored in memory. class Sound { public: + /// @brief Sound variants will be chosen randomly to play + std::vector> variants; + virtual ~Sound() {} /// @brief Get sound duration @@ -474,8 +477,8 @@ namespace audio { /// @param delta time elapsed since the last update (seconds) extern void update(double delta); - /// @brief Stop all playing audio, destroy all non-builtin channels - extern void reset(); + /// @brief Stop all playing audio in channel, reset channel state + extern void reset_channel(int channel); /// @brief Finalize audio system extern void close(); diff --git a/src/constants.h b/src/constants.h index bf7771f0..123f115e 100644 --- a/src/constants.h +++ b/src/constants.h @@ -40,5 +40,6 @@ inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=C #define TEXTURES_FOLDER "textures" #define FONTS_FOLDER "fonts" #define LAYOUTS_FOLDER "layouts" +#define SOUNDS_FOLDER "sounds" #endif // SRC_CONSTANTS_H_ diff --git a/src/content/Content.h b/src/content/Content.h index 32cba96f..01921b9b 100644 --- a/src/content/Content.h +++ b/src/content/Content.h @@ -9,7 +9,7 @@ #include #include "../typedefs.h" -using DrawGroups = std::set; +using DrawGroups = std::set; class Block; class ItemDef; @@ -134,4 +134,4 @@ public: const std::unordered_map>& getPacks() const; }; -#endif // CONTENT_CONTENT_H_ \ No newline at end of file +#endif // CONTENT_CONTENT_H_ diff --git a/src/engine.cpp b/src/engine.cpp index ec3a0632..d7dad0c9 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -57,6 +57,10 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths) throw initialize_error("could not initialize window"); } audio::initialize(true); + audio::create_channel("regular"); + audio::create_channel("music"); + audio::create_channel("ambient"); + audio::create_channel("ui"); auto resdir = paths->getResources(); scripting::initialize(this); @@ -147,9 +151,8 @@ Engine::~Engine() { std::cout << "-- shutting down" << std::endl; screen.reset(); content.reset(); - - audio::close(); assets.reset(); + audio::close(); scripting::close(); Window::terminate(); std::cout << "-- engine finished" << std::endl; @@ -238,7 +241,8 @@ double Engine::getDelta() const { } void Engine::setScreen(std::shared_ptr screen) { - audio::reset(); + audio::reset_channel(audio::get_channel_index("regular")); + audio::reset_channel(audio::get_channel_index("ambient")); this->screen = screen; } diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index c519c8bc..d9c3f4e5 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -17,18 +17,18 @@ #include "../voxels/Chunk.h" -const uint REGION_HEADER_SIZE = 10; +inline constexpr uint REGION_HEADER_SIZE = 10; -const uint REGION_LAYER_VOXELS = 0; -const uint REGION_LAYER_LIGHTS = 1; -const uint REGION_LAYER_INVENTORIES = 2; +inline constexpr uint REGION_LAYER_VOXELS = 0; +inline constexpr uint REGION_LAYER_LIGHTS = 1; +inline constexpr uint REGION_LAYER_INVENTORIES = 2; -const uint REGION_SIZE_BIT = 5; -const uint REGION_SIZE = (1 << (REGION_SIZE_BIT)); -const uint REGION_CHUNKS_COUNT = ((REGION_SIZE) * (REGION_SIZE)); -const uint REGION_FORMAT_VERSION = 2; -const uint WORLD_FORMAT_VERSION = 1; -const uint MAX_OPEN_REGION_FILES = 16; +inline constexpr uint REGION_SIZE_BIT = 5; +inline constexpr uint REGION_SIZE = (1 << (REGION_SIZE_BIT)); +inline constexpr uint REGION_CHUNKS_COUNT = ((REGION_SIZE) * (REGION_SIZE)); +inline constexpr uint REGION_FORMAT_VERSION = 2; +inline constexpr uint WORLD_FORMAT_VERSION = 1; +inline constexpr uint MAX_OPEN_REGION_FILES = 16; #define REGION_FORMAT_MAGIC ".VOXREG" #define WORLD_FORMAT_MAGIC ".VOXWLD" diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index 1d566fa8..d0a39af3 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -445,12 +445,12 @@ void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) { if (isFocused() && multiline) { batch->setColor(glm::vec4(1, 1, 1, 0.1f)); glm::vec2 lcoord = label->calcCoord(); - lcoord.y -= 4; + lcoord.y -= 2; uint line = label->getLineByTextIndex(caret); int lineY = label->getLineYOffset(line); int lineHeight = font->getLineHeight() * label->getLineInterval(); batch->rect(lcoord.x, lcoord.y+lineY, label->getSize().x, 1); - batch->rect(lcoord.x, lcoord.y+lineY+lineHeight, label->getSize().x, 1); + batch->rect(lcoord.x, lcoord.y+lineY+lineHeight-2, label->getSize().x, 1); } label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f));