From 07adbd04ea26fb38504420d2b73879c9624e97a0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 9 Feb 2024 09:59:36 +0300 Subject: [PATCH] UiDocument is an asset now --- src/assets/Assets.cpp | 12 ++ src/assets/Assets.h | 5 + src/assets/AssetsLoader.cpp | 11 +- src/assets/AssetsLoader.h | 1 + src/assets/assetload_funcs.cpp | 283 +++++++++++++++++-------------- src/assets/assetload_funcs.h | 58 ++++--- src/constants.h | 1 + src/content/ContentPack.h | 4 + src/engine.cpp | 1 - src/frontend/ContentGfxCache.cpp | 13 ++ src/frontend/ContentGfxCache.h | 2 + src/frontend/InventoryView.cpp | 207 +++++++++++----------- src/frontend/InventoryView.h | 38 +++-- src/frontend/LevelFrontend.h | 1 - src/frontend/UiDocument.cpp | 15 +- src/frontend/UiDocument.h | 11 +- src/frontend/gui/gui_xml.cpp | 15 +- src/frontend/gui/gui_xml.h | 4 +- src/frontend/hud.cpp | 20 ++- src/voxels/Block.h | 2 +- src/window/Window.cpp | 2 +- 21 files changed, 402 insertions(+), 304 deletions(-) diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp index c13f3da0..3d10e1e1 100644 --- a/src/assets/Assets.cpp +++ b/src/assets/Assets.cpp @@ -4,6 +4,7 @@ #include "../graphics/Shader.h" #include "../graphics/Atlas.h" #include "../graphics/Font.h" +#include "../frontend/UiDocument.h" Assets::~Assets() { } @@ -62,6 +63,17 @@ void Assets::store(const TextureAnimation& animation) { animations.emplace_back(animation); } +UiDocument* Assets::getLayout(std::string name) const { + auto found = layouts.find(name); + if (found == layouts.end()) + return nullptr; + return found->second.get(); +} + +void Assets::store(UiDocument* layout, std::string name) { + layouts[name].reset(layout); +} + void Assets::extend(const Assets& assets) { for (auto entry : assets.textures) { textures[entry.first] = entry.second; diff --git a/src/assets/Assets.h b/src/assets/Assets.h index 6df72ac4..fbe976de 100644 --- a/src/assets/Assets.h +++ b/src/assets/Assets.h @@ -12,12 +12,14 @@ class Texture; class Shader; class Font; class Atlas; +class UiDocument; class Assets { std::unordered_map> textures; std::unordered_map> shaders; std::unordered_map> fonts; std::unordered_map> atlases; + std::unordered_map> layouts; std::vector animations; public: ~Assets(); @@ -36,6 +38,9 @@ public: const std::vector& getAnimations(); void store(const TextureAnimation& animation); + UiDocument* getLayout(std::string name) const; + void store(UiDocument* layout, std::string name); + void extend(const Assets& assets); }; diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index c2ca666d..91b9861a 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -48,6 +48,7 @@ void AssetsLoader::createDefaults(AssetsLoader& loader) { loader.addLoader(ASSET_TEXTURE, assetload::texture); loader.addLoader(ASSET_FONT, assetload::font); loader.addLoader(ASSET_ATLAS, assetload::atlas); + loader.addLoader(ASSET_LAYOUT, assetload::layout); } void AssetsLoader::addDefaults(AssetsLoader& loader, bool world) { @@ -66,6 +67,14 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, bool world) { loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun"); + + for (fs::path& file : loader.getPaths()->listdir(LAYOUTS_FOLDER)) { + std::string packName = file.parent_path().parent_path().filename(); + if (packName == "res") { + packName = "core"; + } + loader.add(ASSET_LAYOUT, file.u8string(), packName+":"+file.stem().u8string()); + } } loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/blocks", "blocks"); loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/items", "items"); @@ -73,4 +82,4 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, bool world) { const ResPaths* AssetsLoader::getPaths() const { return paths; -} \ No newline at end of file +} diff --git a/src/assets/AssetsLoader.h b/src/assets/AssetsLoader.h index 61a88b30..c4a1874d 100644 --- a/src/assets/AssetsLoader.h +++ b/src/assets/AssetsLoader.h @@ -10,6 +10,7 @@ const short ASSET_TEXTURE = 1; const short ASSET_SHADER = 2; const short ASSET_FONT = 3; const short ASSET_ATLAS = 4; +const short ASSET_LAYOUT = 5; class ResPaths; class Assets; diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 8336f5a8..9820d585 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -13,6 +13,7 @@ #include "../graphics/Atlas.h" #include "../graphics/Font.h" #include "../graphics/TextureAnimation.h" +#include "../frontend/UiDocument.h" namespace fs = std::filesystem; @@ -20,187 +21,205 @@ bool assetload::texture(Assets* assets, const ResPaths* paths, const std::string filename, const std::string name) { - std::unique_ptr texture( - png::load_texture(paths->find(filename).string()) + std::unique_ptr texture( + png::load_texture(paths->find(filename).u8string()) ); - if (texture == nullptr) { - std::cerr << "failed to load texture '" << name << "'" << std::endl; - return false; - } - assets->store(texture.release(), name); - return true; + if (texture == nullptr) { + std::cerr << "failed to load texture '" << name << "'" << std::endl; + return false; + } + assets->store(texture.release(), name); + return true; } bool assetload::shader(Assets* assets, const ResPaths* paths, const std::string filename, const std::string name) { - fs::path vertexFile = paths->find(filename+".glslv"); - fs::path fragmentFile = paths->find(filename+".glslf"); + fs::path vertexFile = paths->find(filename+".glslv"); + fs::path fragmentFile = paths->find(filename+".glslf"); - std::string vertexSource = files::read_string(vertexFile); - std::string fragmentSource = files::read_string(fragmentFile); + std::string vertexSource = files::read_string(vertexFile); + std::string fragmentSource = files::read_string(fragmentFile); - Shader* shader = Shader::loadShader( - vertexFile.string(), - fragmentFile.string(), - vertexSource, fragmentSource); + Shader* shader = Shader::loadShader( + vertexFile.string(), + fragmentFile.string(), + vertexSource, fragmentSource); - if (shader == nullptr) { - std::cerr << "failed to load shader '" << name << "'" << std::endl; - return false; - } - assets->store(shader, name); - return true; + if (shader == nullptr) { + std::cerr << "failed to load shader '" << name << "'" << std::endl; + return false; + } + assets->store(shader, name); + return true; } static bool appendAtlas(AtlasBuilder& atlas, const fs::path& file) { - // png is only supported format - if (file.extension() != ".png") - return false; - std::string name = file.stem().string(); - // skip duplicates - if (atlas.has(name)) { - return false; - } - std::unique_ptr image(png::load_image(file.string())); - if (image == nullptr) { - std::cerr << "could not to load " << file.string() << std::endl; - return false; - } - image->fixAlphaColor(); - atlas.add(name, image.release()); + // png is only supported format + if (file.extension() != ".png") + return false; + std::string name = file.stem().string(); + // skip duplicates + if (atlas.has(name)) { + return false; + } + std::unique_ptr image(png::load_image(file.string())); + if (image == nullptr) { + std::cerr << "could not to load " << file.string() << std::endl; + return false; + } + image->fixAlphaColor(); + atlas.add(name, image.release()); - return true; + return true; } bool assetload::atlas(Assets* assets, const ResPaths* paths, const std::string directory, const std::string name) { - AtlasBuilder builder; - for (const auto& file : paths->listdir(directory)) { - if (!appendAtlas(builder, file)) continue; - } - Atlas* atlas = builder.build(2); - assets->store(atlas, name); - for (const auto& file : builder.getNames()) { - assetload::animation(assets, paths, "textures", file, atlas); - } - return true; + AtlasBuilder builder; + for (const auto& file : paths->listdir(directory)) { + if (!appendAtlas(builder, file)) continue; + } + Atlas* atlas = builder.build(2); + assets->store(atlas, name); + for (const auto& file : builder.getNames()) { + assetload::animation(assets, paths, "textures", file, atlas); + } + return true; } bool assetload::font(Assets* assets, const ResPaths* paths, const std::string filename, const std::string name) { - std::vector> pages; - for (size_t i = 0; i <= 4; i++) { + std::vector> pages; + for (size_t i = 0; i <= 4; i++) { std::string name = filename + "_" + std::to_string(i) + ".png"; name = paths->find(name).string(); - std::unique_ptr texture (png::load_texture(name)); - if (texture == nullptr) { - std::cerr << "failed to load bitmap font '" << name; + std::unique_ptr texture (png::load_texture(name)); + if (texture == nullptr) { + std::cerr << "failed to load bitmap font '" << name; std::cerr << "' (missing page " << std::to_string(i) << ")"; std::cerr << std::endl; - return false; - } - pages.push_back(std::move(texture)); - } + return false; + } + pages.push_back(std::move(texture)); + } int res = pages[0]->height / 16; - assets->store(new Font(std::move(pages), res, 4), name); - return true; + assets->store(new Font(std::move(pages), res, 4), name); + return true; } bool assetload::animation(Assets* assets, - const ResPaths* paths, - const std::string directory, - const std::string name, - Atlas* dstAtlas) { - std::string animsDir = directory + "/animations"; - std::string blocksDir = directory + "/blocks"; + const ResPaths* paths, + const std::string directory, + const std::string name, + Atlas* dstAtlas) { + std::string animsDir = directory + "/animations"; + std::string blocksDir = directory + "/blocks"; - for (const auto& folder : paths->listdir(animsDir)) { - if (!fs::is_directory(folder)) continue; - if (folder.filename().string() != name) continue; - if (fs::is_empty(folder)) continue; - - AtlasBuilder builder; + for (const auto& folder : paths->listdir(animsDir)) { + if (!fs::is_directory(folder)) continue; + if (folder.filename().string() != name) continue; + if (fs::is_empty(folder)) continue; + + AtlasBuilder builder; appendAtlas(builder, paths->find(blocksDir + "/" + name + ".png")); - std::string animFile = folder.string() + "/animation.json"; + std::string animFile = folder.string() + "/animation.json"; - std::vector> frameList; + std::vector> frameList; - if (fs::exists(animFile)) { - auto root = files::read_json(animFile); + if (fs::exists(animFile)) { + auto root = files::read_json(animFile); - auto frameArr = root->list("frames"); + auto frameArr = root->list("frames"); - float frameDuration = DEFAULT_FRAME_DURATION; - std::string frameName; + float frameDuration = DEFAULT_FRAME_DURATION; + std::string frameName; - if (frameArr) { - for (size_t i = 0; i < frameArr->size(); i++) { - auto currentFrame = frameArr->list(i); + if (frameArr) { + for (size_t i = 0; i < frameArr->size(); i++) { + auto currentFrame = frameArr->list(i); - frameName = currentFrame->str(0); - if (currentFrame->size() > 1) frameDuration = static_cast(currentFrame->integer(1)) / 1000; + frameName = currentFrame->str(0); + if (currentFrame->size() > 1) + frameDuration = static_cast(currentFrame->integer(1)) / 1000; - frameList.emplace_back(frameName, frameDuration); - } - } - } - for (const auto& file : paths->listdir(animsDir + "/" + name)) { - if (!frameList.empty()) { - bool contains = false; - for (const auto& elem : frameList) { - if (file.stem() == elem.first) { - contains = true; - break; - } - } - if (!contains) continue; - } - if (!appendAtlas(builder, file)) continue; - } + frameList.emplace_back(frameName, frameDuration); + } + } + } + for (const auto& file : paths->listdir(animsDir + "/" + name)) { + if (!frameList.empty()) { + bool contains = false; + for (const auto& elem : frameList) { + if (file.stem() == elem.first) { + contains = true; + break; + } + } + if (!contains) continue; + } + if (!appendAtlas(builder, file)) continue; + } - std::unique_ptr srcAtlas (builder.build(2)); + std::unique_ptr srcAtlas (builder.build(2)); - Texture* srcTex = srcAtlas->getTexture(); - Texture* dstTex = dstAtlas->getTexture(); + Texture* srcTex = srcAtlas->getTexture(); + Texture* dstTex = dstAtlas->getTexture(); - TextureAnimation animation(srcTex, dstTex); - Frame frame; - UVRegion region = dstAtlas->get(name); + TextureAnimation animation(srcTex, dstTex); + Frame frame; + UVRegion region = dstAtlas->get(name); - frame.dstPos = glm::ivec2(region.u1 * dstTex->width, region.v1 * dstTex->height); - frame.size = glm::ivec2(region.u2 * dstTex->width, region.v2 * dstTex->height) - frame.dstPos; + frame.dstPos = glm::ivec2(region.u1 * dstTex->width, region.v1 * dstTex->height); + frame.size = glm::ivec2(region.u2 * dstTex->width, region.v2 * dstTex->height) - frame.dstPos; - if (frameList.empty()) { - for (const auto& elem : builder.getNames()) { - region = srcAtlas->get(elem); - frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); - animation.addFrame(frame); - } - } - else { - for (const auto& elem : frameList) { - if (!srcAtlas->has(elem.first)) { - std::cerr << "Unknown frame name: " << elem.first << std::endl; - continue; - } - region = srcAtlas->get(elem.first); - frame.duration = elem.second; - frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); - animation.addFrame(frame); - } - } + if (frameList.empty()) { + for (const auto& elem : builder.getNames()) { + region = srcAtlas->get(elem); + frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); + animation.addFrame(frame); + } + } + else { + for (const auto& elem : frameList) { + if (!srcAtlas->has(elem.first)) { + std::cerr << "Unknown frame name: " << elem.first << std::endl; + continue; + } + region = srcAtlas->get(elem.first); + frame.duration = elem.second; + frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); + animation.addFrame(frame); + } + } - assets->store(srcAtlas.release(), name + "_animation"); - assets->store(animation); + assets->store(srcAtlas.release(), name + "_animation"); + assets->store(animation); - return true; - } - return true; + return true; + } + return true; +} + +bool assetload::layout( + Assets* assets, + const ResPaths* paths, + const std::string file, + const std::string name +) { + try { + auto document = UiDocument::read(name, file); + assets->store(document.release(), name); + return true; + } catch (const parsing_error& err) { + std::cerr << "failed to parse layout XML '" << file << "'" << std::endl; + std::cerr << err.errorLog() << std::endl; + return false; + } } diff --git a/src/assets/assetload_funcs.h b/src/assets/assetload_funcs.h index 67da528c..830d1d5a 100644 --- a/src/assets/assetload_funcs.h +++ b/src/assets/assetload_funcs.h @@ -8,27 +8,43 @@ class Assets; class Atlas; namespace assetload { - bool texture(Assets* assets, - const ResPaths* paths, - const std::string filename, - const std::string name); - bool shader(Assets* assets, - const ResPaths* paths, - const std::string filename, - const std::string name); - bool atlas(Assets* assets, - const ResPaths* paths, - const std::string directory, - const std::string name); - bool font(Assets* assets, - const ResPaths* paths, - const std::string filename, - const std::string name); - bool animation(Assets* assets, - const ResPaths* paths, - const std::string directory, - const std::string name, - Atlas* dstAtlas); + bool texture( + Assets* assets, + const ResPaths* paths, + const std::string filename, + const std::string name + ); + bool shader( + Assets* assets, + const ResPaths* paths, + const std::string filename, + const std::string name + ); + bool atlas( + Assets* assets, + const ResPaths* paths, + const std::string directory, + const std::string name + ); + bool font( + Assets* assets, + const ResPaths* paths, + const std::string filename, + const std::string name + ); + bool animation( + Assets* assets, + const ResPaths* paths, + const std::string directory, + const std::string name, + Atlas* dstAtlas + ); + bool layout( + Assets* assets, + const ResPaths* paths, + const std::string file, + const std::string name + ); } #endif // ASSETS_ASSET_LOADERS_H_ \ No newline at end of file diff --git a/src/constants.h b/src/constants.h index 05cc1a21..56f54c7f 100644 --- a/src/constants.h +++ b/src/constants.h @@ -36,5 +36,6 @@ constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=CHUNK_D) #define SHADERS_FOLDER "shaders" #define TEXTURES_FOLDER "textures" #define FONTS_FOLDER "fonts" +#define LAYOUTS_FOLDER "layouts" #endif // SRC_CONSTANTS_H_ diff --git a/src/content/ContentPack.h b/src/content/ContentPack.h index 3055990b..bf4bd7e8 100644 --- a/src/content/ContentPack.h +++ b/src/content/ContentPack.h @@ -67,6 +67,10 @@ public: inline const std::string& getId() { return info.id; } + + inline const ContentPack& getInfo() const { + return info; + } }; #endif // CONTENT_CONTENT_PACK_H_ diff --git a/src/engine.cpp b/src/engine.cpp index 48f88265..41e5227c 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -196,7 +196,6 @@ void Engine::loadContent() { void Engine::loadWorldContent(const fs::path& folder) { contentPacks.clear(); auto packNames = ContentPack::worldPacksList(folder); - std::cout << folder << " " << packNames.size() << std::endl; ContentPack::readPacks(paths, contentPacks, packNames, folder); loadContent(); } diff --git a/src/frontend/ContentGfxCache.cpp b/src/frontend/ContentGfxCache.cpp index 20e0e81a..f8e7bd40 100644 --- a/src/frontend/ContentGfxCache.cpp +++ b/src/frontend/ContentGfxCache.cpp @@ -4,6 +4,7 @@ #include "../assets/Assets.h" #include "../content/Content.h" +#include "../content/ContentPack.h" #include "../graphics/Atlas.h" #include "../voxels/Block.h" #include "../core_defs.h" @@ -37,3 +38,15 @@ ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) : conte ContentGfxCache::~ContentGfxCache() { } + +std::shared_ptr ContentGfxCache::getLayout(const std::string& id) { + auto found = layouts.find(id); + if (found == layouts.end()) { + return nullptr; + } + return found->second; +} + +const Content* ContentGfxCache::getContent() const { + return content; +} diff --git a/src/frontend/ContentGfxCache.h b/src/frontend/ContentGfxCache.h index 5e4feed3..b561742b 100644 --- a/src/frontend/ContentGfxCache.h +++ b/src/frontend/ContentGfxCache.h @@ -28,6 +28,8 @@ public: } std::shared_ptr getLayout(const std::string& id); + + const Content* getContent() const; }; #endif // FRONTEND_BLOCKS_GFX_CACHE_H_ diff --git a/src/frontend/InventoryView.cpp b/src/frontend/InventoryView.cpp index ce05b6d2..fffa0a7a 100644 --- a/src/frontend/InventoryView.cpp +++ b/src/frontend/InventoryView.cpp @@ -39,11 +39,8 @@ SlotLayout::SlotLayout( shareFunc(shareFunc), rightClick(rightClick) {} -InventoryBuilder::InventoryBuilder( - LevelFrontend* frontend, - InventoryInteraction& interaction -) { - view = std::make_shared(frontend, interaction); +InventoryBuilder::InventoryBuilder() { + view = std::make_shared(); } void InventoryBuilder::addGrid( @@ -101,13 +98,8 @@ std::shared_ptr InventoryBuilder::build() { } SlotView::SlotView( - LevelFrontend* frontend, - InventoryInteraction& interaction, SlotLayout layout -) : UINode(glm::vec2(), glm::vec2(InventoryView::SLOT_SIZE)), - frontend(frontend), - interaction(interaction), - content(frontend->getLevel()->content), +) : UINode(glm::vec2(), glm::vec2(InventoryView::SLOT_SIZE)), layout(layout) { setColor(glm::vec4(0, 0, 0, 0.2f)); @@ -206,7 +198,7 @@ void SlotView::clicked(gui::GUI* gui, int button) { if (bound == nullptr) throw std::runtime_error("unbound slot"); - ItemStack& grabbed = interaction.getGrabbedItem(); + ItemStack& grabbed = interaction->getGrabbedItem(); ItemStack& stack = *bound; if (button == mousecode::BUTTON_1) { @@ -260,23 +252,21 @@ void SlotView::focus(gui::GUI* gui) { clicked(gui, 0); } -void SlotView::bind(ItemStack& stack) { +void SlotView::bind( + ItemStack& stack, + LevelFrontend* frontend, + InventoryInteraction* interaction +) { bound = &stack; + content = frontend->getLevel()->content; + this->frontend = frontend; } const SlotLayout& SlotView::getLayout() const { return layout; } -InventoryView::InventoryView( - LevelFrontend* frontend, - InventoryInteraction& interaction -) : Container(glm::vec2(), glm::vec2()), - frontend(frontend), - interaction(interaction) -{ - content = frontend->getLevel()->content; - indices = content->getIndices(); +InventoryView::InventoryView() : Container(glm::vec2(), glm::vec2()) { setColor(glm::vec4(0, 0, 0, 0.0f)); } @@ -297,9 +287,7 @@ std::shared_ptr InventoryView::addSlot(SlotLayout layout) { } setSize(vsize); - auto slot = std::make_shared( - frontend, interaction, layout - ); + auto slot = std::make_shared(layout); if (!layout.background) { slot->setColor(glm::vec4()); } @@ -307,10 +295,21 @@ std::shared_ptr InventoryView::addSlot(SlotLayout layout) { return slot; } -void InventoryView::bind(std::shared_ptr inventory) { +void InventoryView::bind( + std::shared_ptr inventory, + LevelFrontend* frontend, + InventoryInteraction* interaction +) { + this->frontend = frontend; + this->interaction = interaction; this->inventory = inventory; + content = frontend->getLevel()->content; + indices = content->getIndices(); for (auto slot : slots) { - slot->bind(inventory->getSlot(slot->getLayout().index)); + slot->bind( + inventory->getSlot(slot->getLayout().index), + frontend, interaction + ); } } @@ -340,90 +339,98 @@ void InventoryView::setInventory(std::shared_ptr inventory) { #include "../coders/xml.h" #include "gui/gui_xml.h" +static void readSlot(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelement element) { + int index = element->attr("index", "0").asInt(); + bool itemSource = element->attr("item-source", "false").asBool(); + SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr); + if (element->has("coord")) { + layout.position = element->attr("coord").asVec2(); + } + auto slot = view->addSlot(layout); + reader.readUINode(reader, element, *slot); + view->add(slot); +} + +static void readSlotsGrid(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelement element) { + int startIndex = element->attr("start-index", "0").asInt(); + int rows = element->attr("rows", "0").asInt(); + int cols = element->attr("cols", "0").asInt(); + int count = element->attr("count", "0").asInt(); + const int slotSize = InventoryView::SLOT_SIZE; + int interval = element->attr("interval", "-1").asInt(); + if (interval < 0) { + interval = InventoryView::SLOT_INTERVAL; + } + int padding = element->attr("padding", "-1").asInt(); + if (padding < 0) { + padding = interval; + } + if (rows == 0) { + rows = ceildiv(count, cols); + } else if (cols == 0) { + cols = ceildiv(count, rows); + } else if (count == 0) { + count = rows * cols; + } + bool itemSource = element->attr("item-source", "false").asBool(); + SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr); + if (element->has("coord")) { + layout.position = element->attr("coord").asVec2(); + } + layout.padding = padding; + + glm::vec2 size ( + cols * slotSize + (cols - 1) * interval + padding * 2, + rows * slotSize + (rows - 1) * interval + padding * 2 + ); + int idx = 0; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++, idx++) { + if (idx >= count) { + return; + } + SlotLayout slotLayout = layout; + slotLayout.index = startIndex + idx; + slotLayout.position = glm::vec2( + padding + col * (slotSize + interval), + padding + row * (slotSize + interval) + ); + auto slot = view->addSlot(slotLayout); + view->add(slot, slotLayout.position); + } + } +} + std::shared_ptr InventoryView::readXML( - LevelFrontend* frontend, - InventoryInteraction& interaction, const std::string& src, const std::string& file, const scripting::Environment& env ) { - auto view = std::make_shared(frontend, interaction); + auto view = std::make_shared(); gui::UiXmlReader reader(env); - reader.add("inventory", [=](gui::UiXmlReader& reader, xml::xmlelement element) { - reader.readUINode(reader, element, *view); - return view; - }); - - reader.add("slot", [=](gui::UiXmlReader& reader, xml::xmlelement element) { - int index = element->attr("index", "0").asInt(); - bool itemSource = element->attr("item-source", "false").asBool(); - SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr); - if (element->has("coord")) { - layout.position = element->attr("coord").asVec2(); - } - auto slot = view->addSlot(layout); - reader.readUINode(reader, element, *slot); - return slot; - }); - - reader.add("slots-grid", [=](gui::UiXmlReader& reader, xml::xmlelement element) { - int startIndex = element->attr("start-index", "0").asInt(); - int rows = element->attr("rows", "0").asInt(); - int cols = element->attr("cols", "0").asInt(); - int count = element->attr("count", "0").asInt(); - const int slotSize = InventoryView::SLOT_SIZE; - int interval = element->attr("interval", "-1").asInt(); - if (interval < 0) { - interval = InventoryView::SLOT_INTERVAL; - } - int padding = element->attr("padding", "-1").asInt(); - if (padding < 0) { - padding = interval; - } - if (rows == 0) { - rows = ceildiv(count, cols); - } else if (cols == 0) { - cols = ceildiv(count, rows); - } else if (count == 0) { - count = rows * cols; - } - bool itemSource = element->attr("item-source", "false").asBool(); - SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr); - if (element->has("coord")) { - layout.position = element->attr("coord").asVec2(); - } - layout.padding = padding; - - glm::vec2 size ( - cols * slotSize + (cols - 1) * interval + padding * 2, - rows * slotSize + (rows - 1) * interval + padding * 2 - ); - auto container = std::make_shared(layout.position, size); - int idx = 0; - for (int row = 0; row < rows; row++) { - for (int col = 0; col < cols; col++, idx++) { - if (idx >= count) { - return container; - } - SlotLayout slotLayout = layout; - slotLayout.index = startIndex + idx; - slotLayout.position = glm::vec2( - padding + col * (slotSize + interval), - padding + row * (slotSize + interval) - ); - auto slot = view->addSlot(slotLayout); - container->add(slot, slotLayout.position); - } - } - return container; - }); + createReaders(reader); auto document = xml::parse(file, src); auto root = document->getRoot(); if (root->getTag() != "inventory") { throw std::runtime_error("'inventory' element expected"); } - reader.readXML(file, root); - return view; + return std::dynamic_pointer_cast(reader.readXML(file, root)); +} + +void InventoryView::createReaders(gui::UiXmlReader& reader) { + reader.add("inventory", [=](gui::UiXmlReader& reader, xml::xmlelement element) { + auto view = std::make_shared(); + reader.readUINode(reader, element, *view, true); + + for (auto& sub : element->getElements()) { + if (sub->getTag() == "slot") { + readSlot(view.get(), reader, sub); + } else if (sub->getTag() == "slots-grid") { + readSlotsGrid(view.get(), reader, sub); + } + } + return view; + }); } diff --git a/src/frontend/InventoryView.h b/src/frontend/InventoryView.h index 84cbf234..22ba1823 100644 --- a/src/frontend/InventoryView.h +++ b/src/frontend/InventoryView.h @@ -18,6 +18,10 @@ class ContentIndices; class LevelFrontend; class Inventory; +namespace gui { + class UiXmlReader; +} + namespace scripting { class Environment; } @@ -53,17 +57,15 @@ struct SlotLayout { }; class SlotView : public gui::UINode { - LevelFrontend* frontend; - InventoryInteraction& interaction; - const Content* const content; + LevelFrontend* frontend = nullptr; + InventoryInteraction* interaction = nullptr; + const Content* content; SlotLayout layout; bool highlighted = false; ItemStack* bound = nullptr; public: - SlotView(LevelFrontend* frontend, - InventoryInteraction& interaction, - SlotLayout layout); + SlotView(SlotLayout layout); virtual void draw(const GfxContext* pctx, Assets* assets) override; @@ -73,7 +75,11 @@ public: virtual void clicked(gui::GUI*, int) override; virtual void focus(gui::GUI*) override; - void bind(ItemStack& stack); + void bind( + ItemStack& stack, + LevelFrontend* frontend, + InventoryInteraction* interaction + ); const SlotLayout& getLayout() const; }; @@ -83,13 +89,13 @@ class InventoryView : public gui::Container { const ContentIndices* indices; std::shared_ptr inventory; - LevelFrontend* frontend; - InventoryInteraction& interaction; + LevelFrontend* frontend = nullptr; + InventoryInteraction* interaction = nullptr; std::vector slots; glm::vec2 origin {}; public: - InventoryView(LevelFrontend* frontend, InventoryInteraction& interaction); + InventoryView(); virtual ~InventoryView(); void setInventory(std::shared_ptr inventory); @@ -101,18 +107,22 @@ public: void setSelected(int index); - void bind(std::shared_ptr inventory); + void bind( + std::shared_ptr inventory, + LevelFrontend* frontend, + InventoryInteraction* interaction + ); std::shared_ptr addSlot(SlotLayout layout); static std::shared_ptr readXML( - LevelFrontend* frontend, - InventoryInteraction& interaction, const std::string& src, const std::string& file, const scripting::Environment& env ); + static void createReaders(gui::UiXmlReader& reader); + static const int SLOT_INTERVAL = 4; static const int SLOT_SIZE = ITEM_ICON_SIZE; }; @@ -120,7 +130,7 @@ public: class InventoryBuilder { std::shared_ptr view; public: - InventoryBuilder(LevelFrontend* frontend, InventoryInteraction& interaction); + InventoryBuilder(); void addGrid( int cols, int count, diff --git a/src/frontend/LevelFrontend.h b/src/frontend/LevelFrontend.h index 98a8a111..772c5309 100644 --- a/src/frontend/LevelFrontend.h +++ b/src/frontend/LevelFrontend.h @@ -24,5 +24,4 @@ public: Atlas* getBlocksAtlas() const; }; - #endif // FRONTEND_LEVEL_FRONTEND_H_ diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index d7a036e4..7cb5b343 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -5,6 +5,7 @@ #include "InventoryView.h" #include "../logic/scripting/scripting.h" #include "../files/files.h" +#include "../frontend/gui/gui_xml.h" UiDocument::UiDocument( std::string namesp, @@ -27,16 +28,14 @@ void UiDocument::collect(uinodes_map& map, std::shared_ptr node) { } } -std::unique_ptr UiDocument::readInventory( - std::string namesp, - fs::path file, - LevelFrontend* frontend, - InventoryInteraction& interaction -) { +std::unique_ptr UiDocument::read(std::string namesp, fs::path file) { const std::string text = files::read_string(file); + auto xmldoc = xml::parse(file.u8string(), text); auto env = scripting::create_environment(); - auto view = InventoryView::readXML( - frontend, interaction, text, file.u8string(), *env + gui::UiXmlReader reader(*env); + InventoryView::createReaders(reader); + auto view = reader.readXML( + file.u8string(), xmldoc->getRoot() ); uidocscript script {}; auto scriptFile = fs::path(file.u8string()+".lua"); diff --git a/src/frontend/UiDocument.h b/src/frontend/UiDocument.h index 83317a3c..e724faff 100644 --- a/src/frontend/UiDocument.h +++ b/src/frontend/UiDocument.h @@ -12,9 +12,6 @@ namespace gui { class UINode; } -class InventoryInteraction; -class LevelFrontend; - struct uidocscript { int environment; bool onopen : 1; @@ -37,13 +34,7 @@ public: /* Collect map of all uinodes having identifiers */ static void collect(uinodes_map& map, std::shared_ptr node); - /* @return root node is always an InventoryView */ - static std::unique_ptr readInventory ( - std::string namesp, - fs::path file, - LevelFrontend* frontend, - InventoryInteraction& interaction - ); + static std::unique_ptr read (std::string namesp, fs::path file); }; #endif // FRONTEND_UI_DOCUMENT_H_ diff --git a/src/frontend/gui/gui_xml.cpp b/src/frontend/gui/gui_xml.cpp index 179da876..67e65e5f 100644 --- a/src/frontend/gui/gui_xml.cpp +++ b/src/frontend/gui/gui_xml.cpp @@ -41,7 +41,7 @@ static void _readUINode(xml::xmlelement element, UINode& node) { } -static void _readContainer(UiXmlReader& reader, xml::xmlelement element, Container& container) { +static void _readContainer(UiXmlReader& reader, xml::xmlelement element, Container& container, bool ignoreUnknown) { _readUINode(element, container); if (element->has("scrollable")) { @@ -50,12 +50,15 @@ static void _readContainer(UiXmlReader& reader, xml::xmlelement element, Contain for (auto& sub : element->getElements()) { if (sub->isText()) continue; + if (ignoreUnknown && !reader.hasReader(sub->getTag())) { + continue; + } container.add(reader.readUINode(sub)); } } -void UiXmlReader::readUINode(UiXmlReader& reader, xml::xmlelement element, Container& container) { - _readContainer(reader, element, container); +void UiXmlReader::readUINode(UiXmlReader& reader, xml::xmlelement element, Container& container, bool ignoreUnknown) { + _readContainer(reader, element, container, ignoreUnknown); } void UiXmlReader::readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) { @@ -104,7 +107,7 @@ static std::shared_ptr readLabel(UiXmlReader& reader, xml::xmlelement el static std::shared_ptr readContainer(UiXmlReader& reader, xml::xmlelement element) { auto container = std::make_shared(glm::vec2(), glm::vec2()); - _readContainer(reader, element, *container); + _readContainer(reader, element, *container, false); return container; } @@ -153,6 +156,10 @@ void UiXmlReader::add(const std::string& tag, uinode_reader reader) { readers[tag] = reader; } +bool UiXmlReader::hasReader(const std::string& tag) const { + return readers.find(tag) != readers.end(); +} + std::shared_ptr UiXmlReader::readUINode(xml::xmlelement element) { const std::string& tag = element->getTag(); diff --git a/src/frontend/gui/gui_xml.h b/src/frontend/gui/gui_xml.h index 0637be00..47a0ca3d 100644 --- a/src/frontend/gui/gui_xml.h +++ b/src/frontend/gui/gui_xml.h @@ -24,6 +24,7 @@ namespace gui { UiXmlReader(const scripting::Environment& env); void add(const std::string& tag, uinode_reader reader); + bool hasReader(const std::string& tag) const; std::shared_ptr readUINode(xml::xmlelement element); @@ -36,7 +37,8 @@ namespace gui { void readUINode( UiXmlReader& reader, xml::xmlelement element, - Container& container + Container& container, + bool ignoreUnknown=false ); std::shared_ptr readXML( diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index a1e8c6af..0857c277 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -189,10 +189,10 @@ std::shared_ptr HudRenderer::createContentAccess() { inventory->getSlot(player->getChosenSlot()).set(item); }); - InventoryBuilder builder(frontend, *interaction); + InventoryBuilder builder; builder.addGrid(8, itemsCount-1, glm::vec2(), 8, true, slotLayout); auto view = builder.build(); - view->bind(accessInventory); + view->bind(accessInventory, frontend, interaction.get()); return view; } @@ -202,12 +202,12 @@ std::shared_ptr HudRenderer::createHotbar() { auto inventory = player->getInventory(); SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr); - InventoryBuilder builder(frontend, *interaction); + InventoryBuilder builder; builder.addGrid(10, 10, glm::vec2(), 4, true, slotLayout); auto view = builder.build(); view->setOrigin(glm::vec2(view->getSize().x/2, 0)); - view->bind(inventory); + view->bind(inventory, frontend, interaction.get()); view->setInteractive(false); return view; } @@ -221,10 +221,10 @@ std::shared_ptr HudRenderer::createInventory() { stack.clear(); }, nullptr); - InventoryBuilder builder(frontend, *interaction); + InventoryBuilder builder; builder.addGrid(10, inventory->size(), glm::vec2(), 4, true, slotLayout); auto view = builder.build(); - view->bind(inventory); + view->bind(inventory, frontend, interaction.get()); return view; } @@ -237,11 +237,13 @@ HudRenderer::HudRenderer(Engine* engine, LevelFrontend* frontend) interaction = std::make_unique(); grabbedItemView = std::make_shared( - frontend, - *interaction, SlotLayout(-1, glm::vec2(), false, false, nullptr, nullptr) ); - grabbedItemView->bind(interaction->getGrabbedItem()); + grabbedItemView->bind( + interaction->getGrabbedItem(), + frontend, + interaction.get() + ); grabbedItemView->setColor(glm::vec4()); grabbedItemView->setInteractive(false); diff --git a/src/voxels/Block.h b/src/voxels/Block.h index 2f74d19b..4a56a20a 100644 --- a/src/voxels/Block.h +++ b/src/voxels/Block.h @@ -82,7 +82,7 @@ public: std::vector modelExtraPoints = {}; //initially made for tetragons std::vector modelUVs = {}; // boxes' tex-UVs also there uint8_t emission[4] {0, 0, 0, 0}; - ubyte drawGroup = 0; + uint8_t drawGroup = 0; BlockModel model = BlockModel::block; bool lightPassing = false; bool skyLightPassing = false; diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 4470d117..b140dbaa 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -335,4 +335,4 @@ bool Window::tryToMaximize(GLFWwindow* window, GLFWmonitor* monitor) { glfwSetWindowPos(window, workArea.x + (workArea.z - Window::width) / 2, workArea.y + (workArea.w - Window::height) / 2 + windowFrame.y / 2); return false; -} \ No newline at end of file +}