diff --git a/res/content/base/scripts/components/drop.lua b/res/content/base/scripts/components/drop.lua index 90e4810f..80d29db9 100644 --- a/res/content/base/scripts/components/drop.lua +++ b/res/content/base/scripts/components/drop.lua @@ -1,5 +1,3 @@ -local item_models = require "core:item_models" - local tsf = entity.transform local body = entity.rigidbody local rig = entity.skeleton @@ -27,7 +25,7 @@ end do -- setup visuals local matrix = mat4.idt() - scale = item_models.setup(dropitem.id, rig, 0) + rig:set_model(0, item.name(dropitem.id)..".model") local bodysize = math.min(scale[1], scale[2], scale[3]) * DROP_SCALE body:set_size({scale[1] * DROP_SCALE, bodysize, scale[3] * DROP_SCALE}) mat4.mul(matrix, rotation, matrix) diff --git a/res/content/base/scripts/components/player_animator.lua b/res/content/base/scripts/components/player_animator.lua index d1a4c0be..5649032f 100644 --- a/res/content/base/scripts/components/player_animator.lua +++ b/res/content/base/scripts/components/player_animator.lua @@ -1,5 +1,3 @@ -local item_models = require "core:item_models" - local tsf = entity.transform local body = entity.rigidbody local rig = entity.skeleton @@ -9,12 +7,7 @@ local itemIndex = rig:index("item") local function refresh_model(id) itemid = id - if id == 0 then - rig:set_model(itemIndex, "") - else - local scale = item_models.setup(itemid, rig, itemIndex) - rig:set_matrix(itemIndex, mat4.scale(scale)) - end + rig:set_model(itemIndex, item.name(itemid)..".model") end function on_render() diff --git a/res/content/base/models/drop-item.vec3 b/res/models/drop-item.vec3 similarity index 100% rename from res/content/base/models/drop-item.vec3 rename to res/models/drop-item.vec3 diff --git a/res/modules/item_models.lua b/res/modules/item_models.lua deleted file mode 100644 index 6c2c955e..00000000 --- a/res/modules/item_models.lua +++ /dev/null @@ -1,33 +0,0 @@ -local function setup(id, rig, index) - rig:set_model(index, "drop-block") - local icon = item.icon(id) - local size = {1.0, 1.0, 1.0} - if icon:find("^block%-previews%:") then - local bid = block.index(icon:sub(16)) - model = block.get_model(bid) - if model == "X" then - size = {1.0, 0.3, 1.0} - rig:set_model(index, "drop-item") - rig:set_texture("$0", icon) - else - if model == "aabb" then - local rot = block.get_rotation_profile(bid) == "pipe" and 4 or 0 - size = block.get_hitbox(bid, rot)[2] - vec3.mul(size, 2.0, size) - end - local textures = block.get_textures(bid) - for i,t in ipairs(textures) do - rig:set_texture("$"..tostring(i-1), "blocks:"..textures[i]) - end - end - else - size = {1.0, 0.3, 1.0} - rig:set_model(index, "drop-item") - rig:set_texture("$0", icon) - end - return size -end - -return { - setup=setup, -} diff --git a/src/assets/Assets.hpp b/src/assets/Assets.hpp index 86d6fb22..2642e005 100644 --- a/src/assets/Assets.hpp +++ b/src/assets/Assets.hpp @@ -5,11 +5,13 @@ #include #include #include +#include #include #include #include #include +#include "util/stringutil.hpp" #include "graphics/core/TextureAnimation.hpp" class Assets; @@ -84,6 +86,15 @@ public: return static_cast(found->second.get()); } + template + T& require(const std::string& name) const { + T* asset = get(name); + if (asset == nullptr) { + throw std::runtime_error(util::quote(name) + " not found"); + } + return *asset; + } + template std::optional getMap() const { const auto& mapIter = assets.find(typeid(T)); diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index df367b96..df12461a 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -418,11 +418,11 @@ void ContentLoader::loadItem( std::string iconTypeStr = ""; root.at("icon-type").get(iconTypeStr); if (iconTypeStr == "none") { - def.iconType = item_icon_type::none; + def.iconType = ItemIconType::NONE; } else if (iconTypeStr == "block") { - def.iconType = item_icon_type::block; + def.iconType = ItemIconType::BLOCK; } else if (iconTypeStr == "sprite") { - def.iconType = item_icon_type::sprite; + def.iconType = ItemIconType::SPRITE; } else if (iconTypeStr.length()) { logger.error() << name << ": unknown icon type" << iconTypeStr; } @@ -532,7 +532,7 @@ void ContentLoader::loadBlock( auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX); item.generated = true; item.caption = def.caption; - item.iconType = item_icon_type::block; + item.iconType = ItemIconType::BLOCK; item.icon = full; item.placingBlock = full; diff --git a/src/core_defs.cpp b/src/core_defs.cpp index 7d19acd1..c68bb268 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -25,7 +25,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) { } { ItemDef& item = builder->items.create(CORE_EMPTY); - item.iconType = item_icon_type::none; + item.iconType = ItemIconType::NONE; } auto bindsFile = paths->getResourcesFolder()/fs::path("bindings.toml"); @@ -43,7 +43,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) { block.hitboxes = {AABB()}; block.breakable = false; ItemDef& item = builder->items.create(CORE_OBSTACLE+".item"); - item.iconType = item_icon_type::block; + item.iconType = ItemIconType::BLOCK; item.icon = CORE_OBSTACLE; item.placingBlock = CORE_OBSTACLE; item.caption = block.caption; @@ -59,7 +59,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) { block.hitboxes = {AABB()}; block.obstacle = false; ItemDef& item = builder->items.create(CORE_STRUCT_AIR+".item"); - item.iconType = item_icon_type::block; + item.iconType = ItemIconType::BLOCK; item.icon = CORE_STRUCT_AIR; item.placingBlock = CORE_STRUCT_AIR; item.caption = block.caption; diff --git a/src/engine.cpp b/src/engine.cpp index 6ba4fcee..def3cf21 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -20,6 +20,7 @@ #include "frontend/menu.hpp" #include "frontend/screens/Screen.hpp" #include "frontend/screens/MenuScreen.hpp" +#include "graphics/render/ModelsGenerator.hpp" #include "graphics/core/Batch2D.hpp" #include "graphics/core/DrawContext.hpp" #include "graphics/core/ImageData.hpp" @@ -280,6 +281,17 @@ void Engine::loadAssets() { } } assets = std::move(new_assets); + + if (content) { + for (auto& [name, def] : content->items.getDefs()) { + assets->store( + std::make_unique( + ModelsGenerator::generate(*def, *content, *assets) + ), + name + ".model" + ); + } + } } static void load_configs(const fs::path& root) { diff --git a/src/graphics/core/Model.cpp b/src/graphics/core/Model.cpp index 78e15354..3da5d897 100644 --- a/src/graphics/core/Model.cpp +++ b/src/graphics/core/Model.cpp @@ -29,6 +29,11 @@ void Mesh::addBox(glm::vec3 pos, glm::vec3 size) { addPlane(pos-X*size, Z*size, Y*size, -X); } +void Mesh::scale(const glm::vec3& size) { + for (auto& vertex : vertices) { + vertex.coord *= size; + } +} void Model::clean() { meshes.erase( diff --git a/src/graphics/core/Model.hpp b/src/graphics/core/Model.hpp index 786b9ac9..b92fb030 100644 --- a/src/graphics/core/Model.hpp +++ b/src/graphics/core/Model.hpp @@ -17,6 +17,7 @@ namespace model { void addPlane(glm::vec3 pos, glm::vec3 right, glm::vec3 up, glm::vec3 norm); void addBox(glm::vec3 pos, glm::vec3 size); + void scale(const glm::vec3& size); }; struct Model { diff --git a/src/graphics/render/ModelsGenerator.cpp b/src/graphics/render/ModelsGenerator.cpp new file mode 100644 index 00000000..b5f334a4 --- /dev/null +++ b/src/graphics/render/ModelsGenerator.cpp @@ -0,0 +1,71 @@ +#include "ModelsGenerator.hpp" + +#include "assets/Assets.hpp" +#include "items/ItemDef.hpp" +#include "voxels/Block.hpp" +#include "content/Content.hpp" +#include "debug/Logger.hpp" + +static debug::Logger logger("models-generator"); + +static void configure_textures( + model::Model& model, + const Block& blockDef, + const Assets& assets +) { + for (auto& mesh : model.meshes) { + auto& texture = mesh.texture; + if (texture.empty() || texture.at(0) != '$') { + continue; + } + try { + int index = std::stoi(texture.substr(1)); + texture = "blocks:"+blockDef.textureFaces.at(index); + } catch (const std::invalid_argument& err) { + } catch (const std::runtime_error& err) { + logger.error() << err.what(); + } + } +} + +static model::Model create_flat_model( + const std::string& texture, const Assets& assets +) { + auto model = assets.require("drop-item"); + for (auto& mesh : model.meshes) { + if (mesh.texture == "$0") { + mesh.texture = texture; + } + } + return model; +} + +model::Model ModelsGenerator::generate( + const ItemDef& def, const Content& content, const Assets& assets +) { + if (def.iconType == ItemIconType::BLOCK) { + auto model = assets.require("block"); + const auto& blockDef = content.blocks.require(def.icon); + if (blockDef.model == BlockModel::xsprite) { + return create_flat_model( + "blocks:" + blockDef.textureFaces.at(0), assets + ); + } + for (auto& mesh : model.meshes) { + switch (blockDef.model) { + case BlockModel::aabb: + mesh.scale(blockDef.hitboxes.at(0).size()); + break; + default: + break; + } + mesh.scale(glm::vec3(0.3f)); + } + configure_textures(model, blockDef, assets); + return model; + } else if (def.iconType == ItemIconType::SPRITE) { + return create_flat_model(def.icon, assets); + } else { + return model::Model(); + } +} diff --git a/src/graphics/render/ModelsGenerator.hpp b/src/graphics/render/ModelsGenerator.hpp new file mode 100644 index 00000000..ec7ea873 --- /dev/null +++ b/src/graphics/render/ModelsGenerator.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "graphics/core/Model.hpp" + +struct ItemDef; +class Assets; +class Content; + +class ModelsGenerator { +public: + static model::Model generate( + const ItemDef& def, const Content& content, const Assets& assets + ); +}; diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 1b759a57..991a9d5b 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -161,9 +161,9 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) { auto& item = indices->items.require(stack.getItemId()); switch (item.iconType) { - case item_icon_type::none: + case ItemIconType::NONE: break; - case item_icon_type::block: { + case ItemIconType::BLOCK: { const Block& cblock = content->blocks.require(item.icon); batch->texture(previews->getTexture()); @@ -173,7 +173,7 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) { 0, 0, 0, region, false, true, tint); break; } - case item_icon_type::sprite: { + case ItemIconType::SPRITE: { size_t index = item.icon.find(':'); std::string name = item.icon.substr(index+1); UVRegion region(0.0f, 0.0, 1.0f, 1.0f); diff --git a/src/items/ItemDef.hpp b/src/items/ItemDef.hpp index a306dce2..81a9dbb7 100644 --- a/src/items/ItemDef.hpp +++ b/src/items/ItemDef.hpp @@ -12,10 +12,10 @@ struct item_funcs_set { bool on_block_break_by : 1; }; -enum class item_icon_type { - none, // invisible (core:empty) must not be rendered - sprite, // textured quad: icon is `atlas_name:texture_name` - block, // block preview: icon is string block id +enum class ItemIconType { + NONE, // invisible (core:empty) must not be rendered + SPRITE, // textured quad: icon is `atlas_name:texture_name` + BLOCK, // block preview: icon is string block id }; struct ItemDef { @@ -29,7 +29,7 @@ struct ItemDef { bool generated = false; uint8_t emission[4] {0, 0, 0, 0}; - item_icon_type iconType = item_icon_type::sprite; + ItemIconType iconType = ItemIconType::SPRITE; std::string icon = "blocks:notfound"; std::string placingBlock = "core:air"; diff --git a/src/logic/scripting/lua/libs/libitem.cpp b/src/logic/scripting/lua/libs/libitem.cpp index 5a4ef4de..52b15c69 100644 --- a/src/logic/scripting/lua/libs/libitem.cpp +++ b/src/logic/scripting/lua/libs/libitem.cpp @@ -36,11 +36,11 @@ static int l_item_defs_count(lua::State* L) { static int l_item_get_icon(lua::State* L) { if (auto def = get_item_def(L, 1)) { switch (def->iconType) { - case item_icon_type::none: + case ItemIconType::NONE: return 0; - case item_icon_type::sprite: + case ItemIconType::SPRITE: return lua::pushstring(L, def->icon); - case item_icon_type::block: + case ItemIconType::BLOCK: return lua::pushstring(L, "block-previews:" + def->icon); } } diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index e9b91664..90321ee6 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "maths/UVRegion.hpp" #include "maths/aabb.hpp" @@ -111,7 +112,7 @@ public: std::string caption; /// @brief Textures set applied to block sides - std::string textureFaces[6]; // -x,x, -y,y, -z,z + std::array textureFaces; // -x,x, -y,y, -z,z std::vector modelTextures = {}; std::vector modelBoxes = {};