feature: bone model overriding

This commit is contained in:
MihailRis 2024-07-16 10:00:40 +03:00
parent 4a0bc016ce
commit d5877a342f
7 changed files with 74 additions and 33 deletions

View File

@ -118,6 +118,10 @@ local rig = entity.skeleton
-- Returns the model name assigned to the bone at the specified index -- Returns the model name assigned to the bone at the specified index
rig:get_model(index: int) -> str rig:get_model(index: int) -> str
-- Reassigns the bone model at the specified index
-- Resets to original if name is not specified
rig:set_model(index: int, name: str)
-- Returns the bone transformation matrix at the specified index -- Returns the bone transformation matrix at the specified index
rig:get_matrix(index: int) -> mat4 rig:get_matrix(index: int) -> mat4
-- Sets the bone transformation matrix at the specified index -- Sets the bone transformation matrix at the specified index

View File

@ -119,6 +119,10 @@ local rig = entity.skeleton
-- Возвращает имя модели, назначенной на кость с указанным индексом -- Возвращает имя модели, назначенной на кость с указанным индексом
rig:get_model(index: int) -> str rig:get_model(index: int) -> str
-- Переназначает модель кости с указанным индексом
-- Сбрасывает до изначальной, если не указывать имя
rig:set_model(index: int, name: str)
-- Возвращает матрицу трансформации кости с указанным индексом -- Возвращает матрицу трансформации кости с указанным индексом
rig:get_matrix(index: int) -> mat4 rig:get_matrix(index: int) -> mat4
-- Устанавливает матрицу трансформации кости с указанным индексом -- Устанавливает матрицу трансформации кости с указанным индексом

View File

@ -39,6 +39,7 @@ end
local Skeleton = {__index={ local Skeleton = {__index={
get_model=function(self, i) return __skeleton.get_model(self.eid, i) end, get_model=function(self, i) return __skeleton.get_model(self.eid, i) end,
set_model=function(self, i, s) return __skeleton.set_model(self.eid, i, s) end,
get_matrix=function(self, i) return __skeleton.get_matrix(self.eid, i) end, get_matrix=function(self, i) return __skeleton.get_matrix(self.eid, i) end,
set_matrix=function(self, i, m) return __skeleton.set_matrix(self.eid, i, m) end, set_matrix=function(self, i, m) return __skeleton.set_matrix(self.eid, i, m) end,
get_texture=function(self, s) return __skeleton.get_texture(self.eid, s) end, get_texture=function(self, s) return __skeleton.get_texture(self.eid, s) end,

View File

@ -20,6 +20,7 @@ enum class BlockInteraction {
placing placing
}; };
/// @brief Player argument is nullable
using on_block_interaction = std::function<void( using on_block_interaction = std::function<void(
Player*, glm::ivec3, const Block*, BlockInteraction type Player*, glm::ivec3, const Block*, BlockInteraction type
)>; )>;
@ -76,6 +77,7 @@ public:
BlockInteraction type BlockInteraction type
); );
/// @brief Add block interaction callback
void listenBlockInteraction(const on_block_interaction& callback); void listenBlockInteraction(const on_block_interaction& callback);
}; };

View File

@ -16,7 +16,25 @@ static int l_get_model(lua::State* L) {
auto& skeleton = entity->getSkeleton(); auto& skeleton = entity->getSkeleton();
auto* rigConfig = skeleton.config; auto* rigConfig = skeleton.config;
auto index = index_range_check(skeleton, lua::tointeger(L, 2)); auto index = index_range_check(skeleton, lua::tointeger(L, 2));
return lua::pushstring(L, rigConfig->getNodes()[index]->getModelName()); const auto& modelOverride = skeleton.modelOverrides[index];
if (!modelOverride.model) {
return lua::pushstring(L, modelOverride.name);
}
return lua::pushstring(L, rigConfig->getNodes()[index]->model.name);
}
return 0;
}
static int l_set_model(lua::State* L) {
if (auto entity = get_entity(L, 1)) {
auto& skeleton = entity->getSkeleton();
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
auto& modelOverride = skeleton.modelOverrides[index];
if (lua::isnoneornil(L, 3)) {
modelOverride = {"", nullptr, true};
} else {
modelOverride = {lua::require_string(L, 3), nullptr, true};
}
} }
return 0; return 0;
} }
@ -96,6 +114,7 @@ static int l_set_visible(lua::State* L) {
const luaL_Reg skeletonlib [] = { const luaL_Reg skeletonlib [] = {
{"get_model", lua::wrap<l_get_model>}, {"get_model", lua::wrap<l_get_model>},
{"set_model", lua::wrap<l_set_model>},
{"get_matrix", lua::wrap<l_get_matrix>}, {"get_matrix", lua::wrap<l_get_matrix>},
{"set_matrix", lua::wrap<l_set_matrix>}, {"set_matrix", lua::wrap<l_set_matrix>},
{"get_texture", lua::wrap<l_get_texture>}, {"get_texture", lua::wrap<l_get_texture>},

View File

@ -7,6 +7,13 @@
using namespace rigging; using namespace rigging;
void ModelReference::refresh(const Assets* assets) {
if (updateFlag) {
model = assets->get<model::Model>(name);
updateFlag = false;
}
}
Bone::Bone( Bone::Bone(
size_t index, size_t index,
std::string name, std::string name,
@ -14,22 +21,27 @@ Bone::Bone(
std::vector<std::unique_ptr<Bone>> bones) std::vector<std::unique_ptr<Bone>> bones)
: index(index), : index(index),
name(std::move(name)), name(std::move(name)),
modelName(std::move(model)), bones(std::move(bones)),
bones(std::move(bones)) model({model, nullptr, true})
{} {}
void Bone::setModel(const std::string& name) { void Bone::setModel(const std::string& name) {
if (modelName == name) { if (model.name == name) {
return; return;
} }
modelName = name; model = {name, nullptr, true};
modelUpdated = true;
} }
void Bone::refreshModel(const Assets* assets) { Skeleton::Skeleton(const SkeletonConfig* config)
if (modelUpdated) { : config(config),
model = assets->get<model::Model>(modelName); pose(config->getNodes().size()),
modelUpdated = false; calculated(config->getNodes().size()),
flags(config->getNodes().size()),
textures(),
modelOverrides(config->getNodes().size()),
visible(true) {
for (size_t i = 0; i < config->getNodes().size(); i++) {
flags[i].visible = true;
} }
} }
@ -76,11 +88,17 @@ void SkeletonConfig::render(
} }
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
auto* node = nodes[i]; auto* node = nodes[i];
node->refreshModel(assets);
if (!skeleton.flags[i].visible) { if (!skeleton.flags[i].visible) {
continue; continue;
} }
if (auto model = node->getModel()) { node->model.refresh(assets);
auto model = node->model.model;
auto& modelOverride = skeleton.modelOverrides.at(i);
if (!modelOverride.updateFlag) {
modelOverride.refresh(assets);
}
model = modelOverride.model ? modelOverride.model : model;
if (model) {
batch.pushMatrix(skeleton.calculated.matrices[i]); batch.pushMatrix(skeleton.calculated.matrices[i]);
batch.draw(model, &skeleton.textures); batch.draw(model, &skeleton.textures);
batch.popMatrix(); batch.popMatrix();

View File

@ -28,14 +28,20 @@ namespace rigging {
} }
}; };
struct ModelReference {
std::string name;
model::Model* model;
bool updateFlag;
void refresh(const Assets* assets);
};
class Bone { class Bone {
size_t index; size_t index;
std::string name; std::string name;
std::string modelName;
std::vector<std::unique_ptr<Bone>> bones; std::vector<std::unique_ptr<Bone>> bones;
model::Model* model = nullptr;
bool modelUpdated = true;
public: public:
ModelReference model;
Bone( Bone(
size_t index, size_t index,
std::string name, std::string name,
@ -44,20 +50,10 @@ namespace rigging {
void setModel(const std::string& name); void setModel(const std::string& name);
void refreshModel(const Assets* assets);
const std::string& getName() const { const std::string& getName() const {
return name; return name;
} }
const std::string& getModelName() const {
return modelName;
}
model::Model* getModel() const {
return model;
}
size_t getIndex() const { size_t getIndex() const {
return index; return index;
} }
@ -77,7 +73,10 @@ namespace rigging {
Pose calculated; Pose calculated;
std::vector<BoneFlags> flags; std::vector<BoneFlags> flags;
std::unordered_map<std::string, std::string> textures; std::unordered_map<std::string, std::string> textures;
std::vector<ModelReference> modelOverrides;
bool visible; bool visible;
Skeleton(const SkeletonConfig* config);
}; };
class SkeletonConfig { class SkeletonConfig {
@ -110,13 +109,7 @@ namespace rigging {
const glm::mat4& matrix) const; const glm::mat4& matrix) const;
Skeleton instance() const { Skeleton instance() const {
auto rig = Skeleton { return Skeleton(this);
this, Pose(nodes.size()), Pose(nodes.size()), {}, {}, true
};
for (size_t i = 0; i < nodes.size(); i++) {
rig.flags.push_back({true});
}
return rig;
} }
Bone* find(std::string_view str) const; Bone* find(std::string_view str) const;