feat: item models generation simple & remove core:item_models

This commit is contained in:
MihailRis 2024-10-26 18:42:21 +03:00
parent 7a5fe3b2b0
commit fae372d19f
16 changed files with 136 additions and 63 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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,
}

View File

@ -5,11 +5,13 @@
#include <optional>
#include <stdexcept>
#include <string>
#include <stdexcept>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <vector>
#include "util/stringutil.hpp"
#include "graphics/core/TextureAnimation.hpp"
class Assets;
@ -84,6 +86,15 @@ public:
return static_cast<T*>(found->second.get());
}
template <class T>
T& require(const std::string& name) const {
T* asset = get<T>(name);
if (asset == nullptr) {
throw std::runtime_error(util::quote(name) + " not found");
}
return *asset;
}
template <class T>
std::optional<const assets_map*> getMap() const {
const auto& mapIter = assets.find(typeid(T));

View File

@ -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;

View File

@ -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;

View File

@ -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<model::Model>(
ModelsGenerator::generate(*def, *content, *assets)
),
name + ".model"
);
}
}
}
static void load_configs(const fs::path& root) {

View File

@ -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(

View File

@ -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 {

View File

@ -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<model::Model>("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<model::Model>("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();
}
}

View File

@ -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
);
};

View File

@ -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);

View File

@ -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";

View File

@ -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);
}
}

View File

@ -4,6 +4,7 @@
#include <optional>
#include <string>
#include <vector>
#include <array>
#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<std::string, 6> textureFaces; // -x,x, -y,y, -z,z
std::vector<std::string> modelTextures = {};
std::vector<BoxModel> modelBoxes = {};