initial commit
This commit is contained in:
1
src/godot
Submodule
1
src/godot
Submodule
Submodule src/godot added at db8700e8f8
17
src/modules/character/SCsub
Normal file
17
src/modules/character/SCsub
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_character = env_modules.Clone()
|
||||
|
||||
# Godot source files
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_character.add_source_files(module_obj, "*.cpp")
|
||||
env_character.add_source_files(module_obj, "flecs/*.c")
|
||||
env_character.Prepend(CPPPATH=["flecs"])
|
||||
env_character.Append(CPPFLAGS=["-UNDEBUG", "-g", "-O0"])
|
||||
env.modules_sources += module_obj
|
||||
|
||||
635
src/modules/character/character.cpp
Normal file
635
src/modules/character/character.cpp
Normal file
@@ -0,0 +1,635 @@
|
||||
#include <cassert>
|
||||
#include <flecs.h>
|
||||
#include <core/rid.h>
|
||||
#include <scene/3d/collision_shape.h>
|
||||
#include <core/engine.h>
|
||||
#include <core/variant_parser.h>
|
||||
#include <scene/3d/mesh_instance.h>
|
||||
#include <scene/resources/shape.h>
|
||||
#include <scene/resources/packed_scene.h>
|
||||
#include <servers/physics_server.h>
|
||||
#include <servers/visual_server.h>
|
||||
#include <scene/resources/animation.h>
|
||||
#include <scene/resources/skin.h>
|
||||
#include <scene/animation/animation_player.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include "character.h"
|
||||
#include "skeleton-prep.h"
|
||||
|
||||
namespace ECS {
|
||||
Skeleton::Skeleton()
|
||||
{
|
||||
bone_count = 0;
|
||||
skeleton = RID();
|
||||
dirty = true;
|
||||
process_order_dirty = true;
|
||||
}
|
||||
Skeleton::~Skeleton()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
ECS::RigidBody::RigidBody(RID rid, enum type type)
|
||||
{
|
||||
this->body = rid;
|
||||
this->type = type;
|
||||
// body = ps->body_create(PhysicsServer::BODY_MODE_KINEMATIC, true);
|
||||
// print_line("created body");
|
||||
}
|
||||
|
||||
ECS::RigidBody::~RigidBody()
|
||||
{
|
||||
/*
|
||||
if (initialized && body != RID()) {
|
||||
PhysicsServer *ps = PhysicsServer::get_singleton();
|
||||
ps->free(body);
|
||||
body = RID();
|
||||
}
|
||||
*/
|
||||
// print_line("destroyed body");
|
||||
}
|
||||
|
||||
ECS::CShape::CShape(RID body, const Transform &offset, Ref<Shape> shape)
|
||||
{
|
||||
PhysicsServer *ps = PhysicsServer::get_singleton();
|
||||
this->offset = offset;
|
||||
this->shape = shape;
|
||||
ps->body_add_shape(body, shape->get_rid(), offset, false);
|
||||
}
|
||||
|
||||
ECS::CShape::~CShape()
|
||||
{
|
||||
shape = Ref<Shape>(nullptr);
|
||||
}
|
||||
|
||||
ECS::CharacterSlot::CharacterSlot(Ref<ArrayMesh> mesh, Ref<Skin> skin)
|
||||
{
|
||||
this->instance = RID();
|
||||
this->name = "";
|
||||
this->mesh = mesh;
|
||||
this->skin = skin;
|
||||
#if 0
|
||||
if (!skin.is_null())
|
||||
this->skin_internal = skin;
|
||||
#endif
|
||||
this->bound = false;
|
||||
}
|
||||
|
||||
ECS::BoneComponent::BoneComponent(int index, int parent_index, const Transform &rest)
|
||||
{
|
||||
this->index = index;
|
||||
this->parent_index = parent_index;
|
||||
this->rest = rest;
|
||||
}
|
||||
|
||||
int Character::create_character(int id)
|
||||
{
|
||||
int i;
|
||||
if (id != 0 && id != 1)
|
||||
return -1;
|
||||
if (!initialized) {
|
||||
print_line("not initialized");
|
||||
return -1;
|
||||
}
|
||||
print_line("creating the character");
|
||||
flecs::entity root = ecs.entity();
|
||||
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
SceneTree *st = SceneTree::get_singleton();
|
||||
PhysicsServer *ps = PhysicsServer::get_singleton();
|
||||
|
||||
RID body = ps->body_create(PhysicsServer::BODY_MODE_KINEMATIC, true);
|
||||
root.emplace<ECS::MetaData>();
|
||||
root.emplace<Transform>();
|
||||
root.emplace<ECS::RigidBody>(body, ECS::RigidBody::TYPE_KINEMATIC);
|
||||
root.emplace<ECS::Skeleton>();
|
||||
root.emplace<ECS::AnimationTree>();
|
||||
root.add<ECS::Dirty>();
|
||||
ECS::MetaData *md = root.get_mut<ECS::MetaData>();
|
||||
md->type_index = id;
|
||||
root.modified<ECS::MetaData>();
|
||||
|
||||
print_line("body created for root");
|
||||
for (i = 0; i < scene_data[id].shapes.size(); i++) {
|
||||
ecs.entity()
|
||||
.child_of(root)
|
||||
.emplace<ECS::CShape>(body, scene_data[id].shapes[i].offset, scene_data[id].shapes[i].shape);
|
||||
}
|
||||
for (i = 0; i < scene_data[id].bones.size(); i++) {
|
||||
int index = i, parent_index = scene_data[id].bones[i].parent;
|
||||
const Transform &rest = scene_data[id].bones[i].rest;
|
||||
ecs.entity(scene_data[id].bones[i].name.ascii().get_data())
|
||||
.child_of(root)
|
||||
.emplace<ECS::BoneComponent>(index, parent_index, rest)
|
||||
.set<ECS::BonePose>({index, Transform()});
|
||||
}
|
||||
for (i = 0; i < scene_data[id].meshes.size(); i++) {
|
||||
// flecs::log::trace("creating slot -");
|
||||
flecs::entity entity = ecs.entity(scene_data[id].meshes[i].slot_name.ascii().get_data())
|
||||
.child_of(root)
|
||||
.emplace<ECS::CharacterSlot>(scene_data[id].meshes[i].mesh,
|
||||
scene_data[id].meshes[i].skin);
|
||||
#if 0
|
||||
flecs::log::trace("created slot - ");
|
||||
if (entity.get<ECS::CharacterSlot>()->instance.is_valid())
|
||||
print_line("instance is valid 1");
|
||||
else
|
||||
print_line("instance is invalid 1");
|
||||
#endif
|
||||
}
|
||||
// print_line("character created");
|
||||
int xid = entities.size();
|
||||
// print_line(itos(xid) + ":" + itos(root.id()));
|
||||
entities[xid] = root.id();
|
||||
return xid;
|
||||
}
|
||||
|
||||
void Character::destroy_character(int xid)
|
||||
{
|
||||
if (!entities.has(xid)) {
|
||||
print_error("No such entity");
|
||||
return;
|
||||
}
|
||||
flecs::entity_t id = entities[xid];
|
||||
// print_line("destroy: " + itos(xid) + ":" + itos(id));
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
PhysicsServer *ps = PhysicsServer::get_singleton();
|
||||
|
||||
flecs::entity entity = ecs.entity(id);
|
||||
if (!entity.is_alive()) {
|
||||
// print_error("Entity already destroyed");
|
||||
return;
|
||||
}
|
||||
print_line("destroying character");
|
||||
ECS::RigidBody *pb = entity.get_mut<ECS::RigidBody>();
|
||||
if (pb->body.is_valid()) {
|
||||
ps->body_clear_shapes(pb->body);
|
||||
ps->body_set_space(pb->body, RID());
|
||||
ps->free(pb->body);
|
||||
pb->body = RID();
|
||||
entity.modified<ECS::RigidBody>();
|
||||
}
|
||||
#if 0
|
||||
entity.children([&](flecs::entity child) {
|
||||
if (child.has<ECS::CharacterSlot>()) {
|
||||
ECS::CharacterSlot *cs = child.get_mut<ECS::CharacterSlot>();
|
||||
print_line("entity is CharacterSlot");
|
||||
if (cs->instance.is_valid())
|
||||
print_line("instance is valid 2");
|
||||
else
|
||||
print_line("instance is invalid 2");
|
||||
} else if (child.has<ECS::CShape>()) {
|
||||
print_line("entity is CShape");
|
||||
}
|
||||
});
|
||||
#endif
|
||||
entity.destruct();
|
||||
print_line("character destroyed");
|
||||
}
|
||||
Character *Character::singleton = nullptr;
|
||||
|
||||
Character *Character::get_singleton()
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = memnew(Character);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void Character::cleanup()
|
||||
{
|
||||
if (singleton)
|
||||
memdelete(singleton);
|
||||
singleton = nullptr;
|
||||
}
|
||||
void Character::set_scene(int id, const Ref<PackedScene> &scene)
|
||||
{
|
||||
if (id < 0 || id > 1)
|
||||
return;
|
||||
scene_data[id].scene = scene;
|
||||
List<Node *> queue;
|
||||
Node *node = scene_data[id].scene->instance();
|
||||
queue.push_back(node);
|
||||
while (!queue.empty()) {
|
||||
int i;
|
||||
Node *tmp = queue.front()->get();
|
||||
queue.pop_front();
|
||||
|
||||
MeshInstance *mi = Object::cast_to<MeshInstance>(tmp);
|
||||
if (mi) {
|
||||
Transform xform = mi->get_transform();
|
||||
Node *tmp2 = mi->get_parent();
|
||||
/* calculating transform */
|
||||
while (tmp2) {
|
||||
Spatial *mi2 = Object::cast_to<Spatial>(tmp2);
|
||||
if (mi2)
|
||||
xform = mi2->get_transform() * xform;
|
||||
tmp2 = tmp2->get_parent();
|
||||
}
|
||||
struct mesh_data md;
|
||||
md.slot_name = mi->get_name();
|
||||
md.mesh = mi->get_mesh();
|
||||
md.offset = xform;
|
||||
scene_data[id].meshes.push_back(md);
|
||||
#if 0
|
||||
Ref<Skin> skin = mi->get_skin();
|
||||
bool found = false;
|
||||
for (Set<SkinReference *>::Element *e =
|
||||
scene_data[id].skin_bindings.front(); e; e = e->next()) {
|
||||
if (e->get()->skin == skin) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (skin.is_null()) {
|
||||
#error GENERATE SKIN
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
CollisionShape *cshape = Object::cast_to<CollisionShape>(tmp);
|
||||
if (cshape) {
|
||||
Transform xform = cshape->get_transform();
|
||||
Node *tmp2 = cshape->get_parent();
|
||||
/* calculating transform */
|
||||
while (tmp2) {
|
||||
Spatial *mi2 = Object::cast_to<Spatial>(tmp2);
|
||||
if (mi2)
|
||||
xform = mi2->get_transform() * xform;
|
||||
tmp2 = tmp2->get_parent();
|
||||
}
|
||||
struct shape_data sd;
|
||||
sd.shape = cshape->get_shape();
|
||||
sd.offset = xform;
|
||||
scene_data[id].shapes.push_back(sd);
|
||||
}
|
||||
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(tmp);
|
||||
if (anim) {
|
||||
List<StringName> anim_list;
|
||||
anim->get_animation_list(&anim_list);
|
||||
List<StringName>::Element *e = anim_list.front();
|
||||
while (e) {
|
||||
StringName anim_name = e->get();
|
||||
Ref<Animation> animation = anim->get_animation(anim_name);
|
||||
scene_data[id].animations.push_back(animation);
|
||||
e = e->next();
|
||||
}
|
||||
}
|
||||
Skeleton *skel = Object::cast_to<Skeleton>(tmp);
|
||||
if (skel) {
|
||||
int bone_count = skel->get_bone_count();
|
||||
scene_data[id].bones.resize(bone_count);
|
||||
for (i = 0; i < bone_count; i++) {
|
||||
scene_data[id].bones.write[i].name = skel->get_bone_name(i);
|
||||
scene_data[id].bones.write[i].index = i;
|
||||
scene_data[id].bones.write[i].parent = skel->get_bone_parent(i);
|
||||
scene_data[id].bones.write[i].rest = skel->get_bone_rest(i);
|
||||
// print_line("added bone: " + scene_data[id].bones.write[i].name + " " + itos(i));
|
||||
}
|
||||
}
|
||||
for (i = 0; i < tmp->get_child_count(); i++)
|
||||
queue.push_back(tmp->get_child(i));
|
||||
}
|
||||
memdelete(node);
|
||||
print_line("meshes loaded: " + itos(id) + " " + itos(scene_data[id].meshes.size()));
|
||||
print_line("shapes loaded: " + itos(id) + " " + itos(scene_data[id].shapes.size()));
|
||||
print_line("animations loaded: " + itos(id) + " " + itos(scene_data[id].animations.size()));
|
||||
}
|
||||
Ref<PackedScene> Character::get_scene(int id) const
|
||||
{
|
||||
if (id < 0 || id > 1)
|
||||
return Ref<PackedScene>(nullptr);
|
||||
return scene_data[id].scene;
|
||||
}
|
||||
Character::Character()
|
||||
{
|
||||
call_deferred("__initialize");
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
void Character::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("__initialize"), &Character::initialize);
|
||||
ClassDB::bind_method(D_METHOD("create_character", "id"), &Character::create_character);
|
||||
ClassDB::bind_method(D_METHOD("destroy_character", "id"), &Character::destroy_character);
|
||||
ClassDB::bind_method(D_METHOD("_progress"), &Character::progress);
|
||||
}
|
||||
void Character::init_bone()
|
||||
{
|
||||
ecs.component<ECS::BoneComponent>()
|
||||
.on_add([](flecs::entity e, ECS::BoneComponent &s)
|
||||
{
|
||||
flecs::log::trace("added bonecomponent %s", e.name().c_str());
|
||||
flecs::entity parent = e.parent();
|
||||
parent.add<ECS::Dirty>();
|
||||
if (parent.has<ECS::Bound>()) {
|
||||
parent.remove<ECS::SkeletonOrderPrepared>();
|
||||
parent.remove<ECS::SkeletonTransformReady>();
|
||||
parent.remove<ECS::Bound>();
|
||||
parent.remove<ECS::Skinned>();
|
||||
}
|
||||
})
|
||||
.on_set([](flecs::entity e, ECS::BoneComponent &s)
|
||||
{
|
||||
flecs::entity parent = e.parent();
|
||||
ECS::Skeleton *skel = parent.get_mut<ECS::Skeleton>();
|
||||
if (s.index >= skel->bone_count) {
|
||||
skel->bone_count = s.index + 1;
|
||||
skel->bones.resize(skel->bone_count);
|
||||
}
|
||||
skel->bones.write[s.index].enabled = true;
|
||||
skel->bones.write[s.index].rest = s.rest;
|
||||
skel->bones.write[s.index].pose = Transform();
|
||||
skel->bones.write[s.index].parent = s.parent_index;
|
||||
skel->bones.write[s.index].disable_rest = false;
|
||||
skel->bones.write[s.index].custom_pose_enable = false;
|
||||
skel->dirty = true;
|
||||
String out;
|
||||
VariantWriter::write_to_string(s.rest, out);
|
||||
flecs::log::trace("bonecomponent set %s (%d) [%s]", e.name().c_str(), skel->bone_count, out.ascii().get_data());
|
||||
parent.remove<ECS::SkeletonOrderPrepared>();
|
||||
parent.add<ECS::Dirty>();
|
||||
});
|
||||
ecs.component<ECS::BonePose>()
|
||||
.on_add([](flecs::entity e, ECS::BonePose &s)
|
||||
{
|
||||
// flecs::log::trace("added bonepose %s", e.name().c_str());
|
||||
})
|
||||
.on_set([](flecs::entity e, ECS::BonePose &s)
|
||||
{
|
||||
const Transform &xform = s.pose;
|
||||
String out;
|
||||
VariantWriter::write_to_string(xform, out);
|
||||
flecs::log::trace("bone pose set %s: %d %s",
|
||||
e.name().c_str(), s.index, out.ascii().get_data());
|
||||
e.add<ECS::Dirty>();
|
||||
});
|
||||
ecs.system<ECS::BonePose, ECS::Dirty>()
|
||||
.with<ECS::Skeleton>().parent()
|
||||
.with<ECS::Bound>().parent()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::BonePose &s, const ECS::Dirty &d)
|
||||
{
|
||||
flecs::entity parent = e.parent();
|
||||
/* Don't update unbound skeleton */
|
||||
if (!parent.has<ECS::Bound>()) {
|
||||
flecs::log::err("the skeleton is not bound");
|
||||
return;
|
||||
}
|
||||
ECS::Skeleton *skel = parent.get_mut<ECS::Skeleton>();
|
||||
skel->bones.write[s.index].pose = s.pose;
|
||||
skel->dirty = true;
|
||||
String out;
|
||||
VariantWriter::write_to_string(s.pose, out);
|
||||
flecs::log::trace("set bonepose %s %d %s", e.name().c_str(), s.index, out.ascii().get_data());
|
||||
parent.modified<ECS::Skeleton>();
|
||||
parent.add<ECS::Dirty>();
|
||||
parent.remove<ECS::SkeletonTransformReady>();
|
||||
e.remove<ECS::Dirty>();
|
||||
});
|
||||
}
|
||||
void Character::initialize()
|
||||
{
|
||||
Error err;
|
||||
flecs::log::set_level(0);
|
||||
SceneTree *st = SceneTree::get_singleton();
|
||||
ecs.import<skeleton_prep>();
|
||||
init_skeleton();
|
||||
ecs.component<ECS::MetaData>()
|
||||
.on_add([](flecs::entity e, ECS::MetaData &s)
|
||||
{
|
||||
flecs::log::trace("added metadata %s", e.name().c_str());
|
||||
});
|
||||
init_bone();
|
||||
init_slot();
|
||||
ecs.component<ECS::AnimationTree>()
|
||||
.on_add([](flecs::entity e, ECS::AnimationTree &s)
|
||||
{
|
||||
flecs::log::trace("animationtree slot %s", e.name().c_str());
|
||||
});
|
||||
ecs.component<ECS::RigidBody>()
|
||||
.on_add([](flecs::entity e, ECS::RigidBody &s)
|
||||
{
|
||||
flecs::log::trace("added rigidbody %s", e.name().c_str());
|
||||
});
|
||||
const String path = "res://characters/";
|
||||
Ref<PackedScene> scene1 = ResourceLoader::load(path + "male-base.tscn", "PackedScene", true, &err);
|
||||
if (err == OK && scene1.is_valid())
|
||||
set_scene(0, scene1);
|
||||
Ref<PackedScene> scene2 = ResourceLoader::load(path + "female-base.tscn", "PackedScene", true, &err);
|
||||
if (err == OK && scene2.is_valid())
|
||||
set_scene(1, scene2);
|
||||
initialized = true;
|
||||
#if 0
|
||||
ecs.system<ECS::CharacterSlot>("BindSkin")
|
||||
.without<ECS::Bound>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::CharacterSlot &slot)
|
||||
{
|
||||
flecs::entity parent = e.parent();
|
||||
ECS::Skeleton *skel = parent.get_mut<ECS::Skeleton>();
|
||||
const struct ECS::Skeleton::bone_data *bonesptr = skel->bones.ptr();
|
||||
const int *order = skel->process_order.ptr();
|
||||
if (skel->skin.is_null() {
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
#endif
|
||||
#if 0
|
||||
ecs.system<ECS::CharacterSlot>("BindSkeleton")
|
||||
.without<ECS::Bound>()
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([this](flecs::entity e, ECS::CharacterSlot &slot)
|
||||
{
|
||||
flecs::entity parent = e.parent();
|
||||
if (!parent.get<ECS::SkeletonTransformReady>())
|
||||
return;
|
||||
if (parent.get<ECS::Bound>())
|
||||
return;
|
||||
flecs::log::trace("unbound skeleton at %s", e.name().c_str());
|
||||
int i;
|
||||
ECS::Skeleton *skel = parent.get_mut<ECS::Skeleton>();
|
||||
if (!skel->skin.is_null())
|
||||
return;
|
||||
const struct ECS::Skeleton::bone_data *bonesptr = skel->bones.ptr();
|
||||
const int *order = skel->process_order.ptr();
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
int len = skel->bones.size();
|
||||
if (slot.skin.is_null() || slot.skin_internal.is_null()) {
|
||||
flecs::log::err("skin is null for %s", e.name().c_str());
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
if (!skel->skin.is_null()) {
|
||||
slot.skin = skel->skin;
|
||||
vs->instance_attach_skeleton(slot.instance, skel->skeleton);
|
||||
parent.add<ECS::Bound>();
|
||||
e.add<ECS::Bound>();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
assert(skel->skeleton.is_valid());
|
||||
uint32_t bind_count = 0U;
|
||||
bind_count = skel->skin->get_bind_count();
|
||||
skel->skin_bone_indices.resize(bind_count);
|
||||
skel->skin_bone_indices_ptrs = skel->skin_bone_indices.ptrw();
|
||||
for (i = 0; i < bind_count; i++) {
|
||||
StringName bind_name = skel->skin->get_bind_name(i);
|
||||
if (bind_name != StringName()) {
|
||||
int j;
|
||||
bool found = false;
|
||||
for (j = 0; j < len; j++) {
|
||||
if (bonesptr[j].name == bind_name) {
|
||||
skel->skin_bone_indices_ptrs[i] = j;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
flecs::log::err("no bind name %s in skeleton", String(bind_name).ascii().get_data());
|
||||
}
|
||||
} else if (skel->skin->get_bind_bone(i) >= 0) {
|
||||
uint32_t bind_index = skel->skin->get_bind_bone(i);
|
||||
if (bind_index >= len) {
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
flecs::log::err("bind %d bad index %d", i, bind_index);
|
||||
} else
|
||||
skel->skin_bone_indices_ptrs[i] = bind_index;
|
||||
} else {
|
||||
flecs::log::err("no bind name for %d", i);
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
}
|
||||
}
|
||||
assert(bind_count > 0);
|
||||
vs->skeleton_allocate(skel->skeleton, bind_count);
|
||||
flecs::log::trace("skeltton is prepared and bound for %s", e.name().c_str());
|
||||
parent.modified<ECS::Skeleton>();
|
||||
parent.add<ECS::Bound>();
|
||||
assert(false);
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("Check2")
|
||||
.kind(flecs::PostUpdate)
|
||||
.each([this](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
if (e.has<ECS::Dirty>())
|
||||
flecs::log::trace("is dirty");
|
||||
if (e.has<ECS::Bound>())
|
||||
flecs::log::trace("is bound");
|
||||
if (e.has<ECS::SkeletonTransformReady>())
|
||||
flecs::log::trace("transform ready");
|
||||
flecs::log::trace("end of frame systems");
|
||||
});
|
||||
#endif
|
||||
#if 0
|
||||
ecs.system<ECS::CharacterSlot>("PrepareSkins2")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::CharacterSlot &slot)
|
||||
{
|
||||
int i;
|
||||
flecs::entity parent = e.parent();
|
||||
ECS::Skeleton *skel = parent.get_mut<ECS::Skeleton>();
|
||||
if (slot.bound && !skel->dirty)
|
||||
return;
|
||||
const struct ECS::Skeleton::bone_data *bonesptr = skel->bones.ptr();
|
||||
const int *order = skel->process_order.ptr();
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
uint32_t bind_count = 0U;
|
||||
if (!slot.bound) {
|
||||
int len = skel->bones.size();
|
||||
if (slot.skin.is_null())
|
||||
flecs::log::trace("skin is null for %s", e.name().c_str());
|
||||
if (slot.skin_internal.is_null() && skel->skin.is_null()) {
|
||||
flecs::log::trace("creating skin for %s", e.name().c_str());
|
||||
slot.skin_internal.instance();
|
||||
slot.skin_internal->set_bind_count(skel->bones.size());
|
||||
for (i = 0; i < len; i++) {
|
||||
const struct ECS::Skeleton::bone_data &b = bonesptr[order[i]];
|
||||
if (b.parent >= 0)
|
||||
slot.skin_internal->set_bind_pose(order[i], slot.skin_internal->get_bind_pose(b.parent) * b.rest);
|
||||
else
|
||||
slot.skin_internal->set_bind_pose(order[i], b.rest);
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
slot.skin_internal->set_bind_bone(i, i);
|
||||
slot.skin_internal->set_bind_pose(i, slot.skin_internal->get_bind_pose(i).affine_inverse());
|
||||
}
|
||||
flecs::log::trace("created skin for %s: %d", e.name().c_str(), len);
|
||||
}
|
||||
assert(skel->skeleton.is_valid());
|
||||
skel->skin = slot.skin_internal;
|
||||
bind_count = skel->skin->get_bind_count();
|
||||
assert(bind_count > 0);
|
||||
skel->skin_bone_indices.resize(bind_count);
|
||||
skel->skin_bone_indices_ptrs = skel->skin_bone_indices.ptrw();
|
||||
for (i = 0; i < bind_count; i++) {
|
||||
StringName bind_name = skel->skin->get_bind_name(i);
|
||||
if (bind_name != StringName()) {
|
||||
int j;
|
||||
bool found = false;
|
||||
for (j = 0; j < len; j++) {
|
||||
if (bonesptr[j].name == bind_name) {
|
||||
skel->skin_bone_indices_ptrs[i] = j;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
flecs::log::err("no bind name %s in skeleton", String(bind_name).ascii().get_data());
|
||||
}
|
||||
} else if (skel->skin->get_bind_bone(i) >= 0) {
|
||||
uint32_t bind_index = skel->skin->get_bind_bone(i);
|
||||
if (bind_index >= len) {
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
flecs::log::err("bind %d bad index %d", i, bind_index);
|
||||
} else
|
||||
skel->skin_bone_indices_ptrs[i] = bind_index;
|
||||
} else {
|
||||
flecs::log::err("no bind name for %d", i);
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
}
|
||||
}
|
||||
vs->skeleton_allocate(skel->skeleton, bind_count);
|
||||
vs->instance_attach_skeleton(slot.instance, skel->skeleton);
|
||||
slot.bound = true;
|
||||
flecs::log::trace("skeltton is prepared and bound for %s", e.name().c_str());
|
||||
e.modified<ECS::Skeleton>();
|
||||
}
|
||||
bind_count = skel->skin->get_bind_count();
|
||||
for (i = 0; i < (int)bind_count; i++) {
|
||||
uint32_t bone_index = skel->skin_bone_indices_ptrs[i];
|
||||
vs->skeleton_bone_set_transform(skel->skeleton,
|
||||
i, bonesptr[bone_index].pose_global *skel->skin->get_bind_pose(i));
|
||||
}
|
||||
skel->dirty = false;
|
||||
});
|
||||
#endif
|
||||
ecs.system<ECS::Skeleton>("UpdateBone")
|
||||
.with<ECS::Bound>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, ECS::Skeleton &sk)
|
||||
{
|
||||
flecs::entity root = e.lookup("Root");
|
||||
if (!root.is_valid() || !root.is_alive())
|
||||
return;
|
||||
if (!root.has<ECS::BonePose>())
|
||||
return;
|
||||
float delta = SceneTree::get_singleton()->get_physics_process_time();
|
||||
struct ECS::BonePose *bp = root.get_mut<ECS::BonePose>();
|
||||
// bp->pose.basis = bp->pose.basis.rotated(Vector3(0, 1, 0), 0.016f);
|
||||
bp->pose.origin += Vector3(0.1f * delta, 0.0f, 0.0f);
|
||||
root.modified<ECS::BonePose>();
|
||||
});
|
||||
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||
err = st->connect("physics_frame", this, "_progress");
|
||||
assert(err == OK);
|
||||
}
|
||||
print_line("initialized");
|
||||
}
|
||||
void Character::progress()
|
||||
{
|
||||
ecs.progress(SceneTree::get_singleton()->get_physics_process_time());
|
||||
}
|
||||
150
src/modules/character/character.h
Normal file
150
src/modules/character/character.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#ifndef CHARACTER_H
|
||||
#define CHARACTER_H
|
||||
#include <core/object.h>
|
||||
#include <flecs.h>
|
||||
|
||||
class PackedScene;
|
||||
class Shape;
|
||||
class ArrayMesh;
|
||||
class Animation;
|
||||
class Skin;
|
||||
class SkinReference;
|
||||
namespace ECS {
|
||||
struct Skeleton {
|
||||
bool dirty;
|
||||
RID skeleton;
|
||||
Ref<Skin> skin;
|
||||
int bone_count;
|
||||
Vector<int> process_order;
|
||||
bool process_order_dirty;
|
||||
struct bone_data {
|
||||
String name;
|
||||
bool enabled;
|
||||
int parent;
|
||||
bool disable_rest;
|
||||
bool custom_pose_enable;
|
||||
Transform
|
||||
custom_pose,
|
||||
rest,
|
||||
pose,
|
||||
pose_global,
|
||||
pose_global_no_override;
|
||||
int sort_index;
|
||||
};
|
||||
Vector<uint32_t> skin_bone_indices;
|
||||
uint32_t *skin_bone_indices_ptrs;
|
||||
Vector<struct bone_data> bones;
|
||||
Skeleton();
|
||||
~Skeleton();
|
||||
};
|
||||
struct Bound {};
|
||||
struct Skinned {};
|
||||
struct Dirty {};
|
||||
struct SkeletonOrderPrepared {};
|
||||
struct SkeletonTransformReady {};
|
||||
struct MetaData {
|
||||
int type_index;
|
||||
};
|
||||
struct BoneComponent {
|
||||
flecs::entity_t skeleton;
|
||||
int index, parent_index;
|
||||
Transform rest, pose;
|
||||
BoneComponent(int index, int parent_index, const Transform &rest);
|
||||
};
|
||||
struct BonePose {
|
||||
int index;
|
||||
Transform pose;
|
||||
};
|
||||
struct AnimationTree {
|
||||
void *root;
|
||||
AnimationTree(): root(nullptr)
|
||||
{
|
||||
}
|
||||
~AnimationTree()
|
||||
{
|
||||
}
|
||||
};
|
||||
struct CharacterSlot {
|
||||
String name;
|
||||
RID instance;
|
||||
RID skeleton;
|
||||
Ref<ArrayMesh> mesh;
|
||||
Ref<Skin> skin, skin_internal;
|
||||
bool bound;
|
||||
CharacterSlot(Ref<ArrayMesh> mesh, Ref<Skin> skin);
|
||||
#if 0
|
||||
CharacterSlot(const CharacterSlot &obj);
|
||||
CharacterSlot(CharacterSlot &&obj);
|
||||
CharacterSlot &operator=(const CharacterSlot &obj);
|
||||
CharacterSlot &operator=(CharacterSlot &&obj);
|
||||
~CharacterSlot();
|
||||
#endif
|
||||
};
|
||||
struct RigidBody {
|
||||
enum type {
|
||||
TYPE_NONE = 0,
|
||||
TYPE_STATIC = 1,
|
||||
TYPE_KINEMATIC,
|
||||
TYPE_RIGID
|
||||
};
|
||||
bool initialized;
|
||||
RID body;
|
||||
Vector3 velocity;
|
||||
enum type type;
|
||||
RigidBody(RID rid, enum type type);
|
||||
~RigidBody();
|
||||
};
|
||||
struct CShape {
|
||||
Transform offset;
|
||||
Ref<Shape> shape;
|
||||
CShape(RID body, const Transform &offset, Ref<Shape> shape);
|
||||
~CShape();
|
||||
};
|
||||
}
|
||||
|
||||
class Character: public Object {
|
||||
GDCLASS(Character, Object)
|
||||
public:
|
||||
int create_character(int type_id);
|
||||
void destroy_character(int id);
|
||||
static Character *singleton;
|
||||
static Character *get_singleton();
|
||||
static void cleanup();
|
||||
void set_scene(int id, const Ref<PackedScene> &scene);
|
||||
Ref<PackedScene> get_scene(int id) const;
|
||||
Character();
|
||||
protected:
|
||||
flecs::world ecs;
|
||||
struct shape_data {
|
||||
Ref<Shape> shape;
|
||||
Transform offset;
|
||||
};
|
||||
struct mesh_data {
|
||||
Ref<Skin> skin;
|
||||
String slot_name;
|
||||
Ref<ArrayMesh> mesh;
|
||||
Transform offset;
|
||||
};
|
||||
struct bone_data {
|
||||
String name;
|
||||
int index, parent;
|
||||
Transform rest;
|
||||
};
|
||||
struct scene_data {
|
||||
Ref<PackedScene> scene;
|
||||
Vector<struct shape_data> shapes;
|
||||
Vector<struct mesh_data> meshes;
|
||||
Vector<Ref<Animation> > animations;
|
||||
Vector<struct bone_data> bones;
|
||||
Set<SkinReference *> skin_bindings;
|
||||
} scene_data[2];
|
||||
static void _bind_methods();
|
||||
void init_skeleton();
|
||||
void init_bone();
|
||||
void init_slot();
|
||||
void initialize();
|
||||
HashMap<int, flecs::entity_t> entities;
|
||||
bool initialized;
|
||||
void progress();
|
||||
};
|
||||
#endif
|
||||
212
src/modules/character/character_skeleton.cpp
Normal file
212
src/modules/character/character_skeleton.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <flecs.h>
|
||||
#include <servers/visual_server.h>
|
||||
#include <scene/main/scene_tree.h>
|
||||
#include <core/reference.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include <scene/resources/skin.h>
|
||||
#include <core/variant_parser.h>
|
||||
#include "character.h"
|
||||
|
||||
void Character::init_skeleton()
|
||||
{
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
ecs.component<ECS::Skeleton>()
|
||||
.on_add([](flecs::entity e, ECS::Skeleton &s)
|
||||
{
|
||||
// flecs::log::trace("added skeleton %s", e.name().c_str());
|
||||
if (e.has<ECS::SkeletonOrderPrepared>())
|
||||
e.remove<ECS::SkeletonOrderPrepared>();
|
||||
})
|
||||
.on_set([](flecs::entity e, ECS::Skeleton &s)
|
||||
{
|
||||
// flecs::log::trace("on set: set skeleton %s", e.name().c_str());
|
||||
// s.process_order_dirty = true;
|
||||
e.add<ECS::Dirty>();
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("CreateSkeleton")
|
||||
.without<ECS::Bound>()
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([vs](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
if (!skel.skeleton.is_valid()) {
|
||||
skel.skeleton = vs->skeleton_create();
|
||||
flecs::log::trace("created skeleton");
|
||||
}
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("PrepareSkeletonsOrder")
|
||||
.with<ECS::Dirty>()
|
||||
.without<ECS::SkeletonOrderPrepared>()
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([](flecs::entity e, ECS::Skeleton &sk)
|
||||
{
|
||||
if (sk.process_order_dirty) {
|
||||
flecs::log::trace("skeletons: %d dirty: sorting bones", sk.bone_count);
|
||||
int i;
|
||||
struct ECS::Skeleton::bone_data *bonesptr = sk.bones.ptrw();
|
||||
int len = sk.bones.size();
|
||||
sk.process_order.resize(len);
|
||||
int *order = sk.process_order.ptrw();
|
||||
for (i = 0; i < len; i++) {
|
||||
if (bonesptr[i].parent >= len) {
|
||||
flecs::log::err("Bone %d has bad parent %d", i, bonesptr[i].parent);
|
||||
bonesptr[i].parent = -1;
|
||||
}
|
||||
order[i] = i;
|
||||
bonesptr[i].sort_index = i;
|
||||
}
|
||||
int pass_count = 0;
|
||||
while (pass_count < len * len) {
|
||||
// fucking bubblesort
|
||||
bool swapped = false;
|
||||
for (i = 0; i < len; i++) {
|
||||
int parent_idx = bonesptr[order[i]].parent;
|
||||
if (parent_idx < 0)
|
||||
continue;
|
||||
int parent_order = bonesptr[parent_idx].sort_index;
|
||||
if (parent_order > i) {
|
||||
bonesptr[order[i]].sort_index = parent_order;
|
||||
bonesptr[parent_idx].sort_index = i;
|
||||
SWAP(order[i], order[parent_order]);
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
if (!swapped)
|
||||
break;
|
||||
pass_count++;
|
||||
}
|
||||
if (pass_count >= len * len)
|
||||
flecs::log::err("Skeleton parenthood graph is cyclic");
|
||||
sk.process_order_dirty = false;
|
||||
}
|
||||
e.add<ECS::SkeletonOrderPrepared>();
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("PrepSkeletonTransform")
|
||||
.with<ECS::Dirty>()
|
||||
.with<ECS::SkeletonOrderPrepared>()
|
||||
.without<ECS::SkeletonTransformReady>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, ECS::Skeleton &sk)
|
||||
{
|
||||
int i;
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
// flecs::log::trace("skeletons: %d dirty: update try", sk.bone_count);
|
||||
if (sk.process_order_dirty)
|
||||
return;
|
||||
flecs::log::trace("skeletons: %d dirty: update", sk.bone_count);
|
||||
struct ECS::Skeleton::bone_data *bonesptr = sk.bones.ptrw();
|
||||
int len = sk.bones.size();
|
||||
const int *order = sk.process_order.ptr();
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
struct ECS::Skeleton::bone_data &b = bonesptr[order[i]];
|
||||
if (b.disable_rest) {
|
||||
if (b.enabled) {
|
||||
Transform pose = b.pose;
|
||||
if (b.custom_pose_enable)
|
||||
pose = b.custom_pose * pose;
|
||||
if (b.parent >= 0) {
|
||||
b.pose_global = bonesptr[b.parent].pose_global * pose;
|
||||
b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * pose;
|
||||
} else {
|
||||
b.pose_global = pose;
|
||||
b.pose_global_no_override = pose;
|
||||
}
|
||||
} else {
|
||||
if (b.parent >= 0) {
|
||||
b.pose_global = bonesptr[b.parent].pose_global;
|
||||
b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override;
|
||||
} else {
|
||||
b.pose_global = Transform();
|
||||
b.pose_global_no_override = Transform();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (b.enabled) {
|
||||
Transform pose = b.pose;
|
||||
if (b.custom_pose_enable)
|
||||
pose = b.custom_pose * pose;
|
||||
if (b.parent >= 0) {
|
||||
b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
|
||||
b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * (b.rest * pose);
|
||||
} else {
|
||||
b.pose_global = b.rest * pose;
|
||||
b.pose_global_no_override = b.rest * pose;
|
||||
}
|
||||
} else {
|
||||
if (b.parent >= 0) {
|
||||
b.pose_global = bonesptr[b.parent].pose_global * b.rest;
|
||||
b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * b.rest;
|
||||
} else {
|
||||
b.pose_global = b.rest;
|
||||
b.pose_global_no_override = b.rest;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
flecs::log::trace("transform should be ready");
|
||||
e.add<ECS::SkeletonTransformReady>();
|
||||
assert(sk.skin_bone_indices_ptrs);
|
||||
uint32_t bind_count = sk.skin->get_bind_count();
|
||||
for (i = 0; i < (int)bind_count; i++) {
|
||||
uint32_t bone_index = sk.skin_bone_indices_ptrs[i];
|
||||
Transform xform = bonesptr[bone_index].pose_global * sk.skin->get_bind_pose(i);
|
||||
if (i == 0) {
|
||||
String out;
|
||||
VariantWriter::write_to_string(xform, out);
|
||||
flecs::log::trace("dirty bone: set skeleton %d %s %s",
|
||||
i, bonesptr[bone_index].name.ascii().get_data(),
|
||||
out.ascii().get_data());
|
||||
}
|
||||
vs->skeleton_bone_set_transform(sk.skeleton,
|
||||
i, bonesptr[bone_index].pose_global * sk.skin->get_bind_pose(i));
|
||||
}
|
||||
sk.dirty = false;
|
||||
e.remove<ECS::Dirty>();
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("c1")
|
||||
.with<ECS::Bound>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
flecs::log::trace("is bound");
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("c2")
|
||||
.with<ECS::Dirty>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
flecs::log::trace("is dirty");
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("c3")
|
||||
.with<ECS::SkeletonTransformReady>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
flecs::log::trace("transform ready");
|
||||
});
|
||||
ecs.system<ECS::Skeleton>("c4")
|
||||
.with<ECS::SkeletonOrderPrepared>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
flecs::log::trace("order prepared");
|
||||
});
|
||||
#if 0
|
||||
ecs.system<ECS::Skeleton>("Check_")
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([this](flecs::entity e, ECS::Skeleton &skel)
|
||||
{
|
||||
if (e.has<ECS::Dirty>())
|
||||
flecs::log::trace("is dirty");
|
||||
if (e.has<ECS::Bound>())
|
||||
flecs::log::trace("is bound");
|
||||
if (e.has<ECS::SkeletonOrderPrepared>())
|
||||
flecs::log::trace("order is prepared");
|
||||
if (e.has<ECS::SkeletonTransformReady>())
|
||||
flecs::log::trace("transform ready");
|
||||
flecs::log::trace("start of frame systems");
|
||||
});
|
||||
#endif
|
||||
}
|
||||
154
src/modules/character/character_slot.cpp
Normal file
154
src/modules/character/character_slot.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include <cassert>
|
||||
#include <flecs.h>
|
||||
#include <servers/visual_server.h>
|
||||
#include <scene/main/scene_tree.h>
|
||||
#include <core/reference.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include <scene/resources/skin.h>
|
||||
#include "character.h"
|
||||
|
||||
void Character::init_slot()
|
||||
{
|
||||
SceneTree *st = SceneTree::get_singleton();
|
||||
VisualServer *vs = VS::get_singleton();
|
||||
ecs.component<ECS::CharacterSlot>()
|
||||
.on_add([](flecs::entity e, ECS::CharacterSlot &s)
|
||||
{
|
||||
flecs::log::trace("added slot %s", e.name().c_str());
|
||||
})
|
||||
.on_remove([vs](flecs::entity e, ECS::CharacterSlot &s)
|
||||
{
|
||||
if (s.instance.is_valid()) {
|
||||
vs->instance_set_scenario(s.instance, RID());
|
||||
vs->instance_attach_skeleton(s.instance, RID());
|
||||
vs->instance_set_base(s.instance, RID());
|
||||
vs->free(s.instance);
|
||||
s.instance = RID();
|
||||
// print_line("mesh instance slot removed " + s.name);
|
||||
}
|
||||
// flecs::log::trace("removed slot %s", e.name().c_str());
|
||||
})
|
||||
.on_set([st](flecs::entity e, ECS::CharacterSlot &s)
|
||||
{
|
||||
flecs::log::trace("set slot %s", e.name().c_str());
|
||||
if (s.mesh.is_null() || !s.mesh.is_valid())
|
||||
flecs::log::trace("invalid mesh %s", e.name().c_str());
|
||||
});
|
||||
ecs.system<ECS::CharacterSlot>("UpdateSlot")
|
||||
.without<ECS::Bound>()
|
||||
.with<ECS::Skeleton>().parent()
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([vs, st](flecs::entity e, ECS::CharacterSlot &slot)
|
||||
{
|
||||
assert(e.parent().has<ECS::Skeleton>());
|
||||
if (!slot.instance.is_valid()) {
|
||||
slot.name = e.name().c_str();
|
||||
RID scenario = st->get_root()->get_world()->get_scenario();
|
||||
slot.instance = vs->instance_create();
|
||||
vs->instance_set_scenario(slot.instance, scenario);
|
||||
vs->instance_set_base(slot.instance, slot.mesh->get_rid());
|
||||
flecs::log::trace("created instance for %s", e.name().c_str());
|
||||
}
|
||||
});
|
||||
ecs.system<ECS::CharacterSlot>("AttachToSkeleton")
|
||||
.without<ECS::Bound>()
|
||||
.with<ECS::Skeleton>().parent()
|
||||
.with<ECS::Skinned>()
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([vs, st](flecs::entity e, ECS::CharacterSlot &slot)
|
||||
{
|
||||
flecs::entity parent = e.parent();
|
||||
assert(parent.has<ECS::Skeleton>());
|
||||
assert(!e.has<ECS::Bound>());
|
||||
assert(slot.instance.is_valid());
|
||||
const ECS::Skeleton *skel = parent.get<ECS::Skeleton>();
|
||||
assert(skel->skeleton.is_valid());
|
||||
flecs::log::trace("binding slot for %s", e.name().c_str());
|
||||
if (skel->skeleton.is_valid())
|
||||
slot.skeleton = skel->skeleton;
|
||||
if (slot.skin.is_null() && !skel->skin.is_null())
|
||||
slot.skin_internal = skel->skin;
|
||||
if (skel->skeleton.is_valid() && !skel->skin.is_null()) {
|
||||
uint32_t bind_count = skel->skin->get_bind_count();
|
||||
vs->skeleton_allocate(skel->skeleton, bind_count);
|
||||
vs->instance_attach_skeleton(slot.instance, skel->skeleton);
|
||||
slot.bound = true;
|
||||
e.add<ECS::Bound>();
|
||||
parent.add<ECS::Bound>();
|
||||
flecs::log::trace("bound slot for %s", e.name().c_str());
|
||||
}
|
||||
});
|
||||
ecs.system<ECS::CharacterSlot>("BindSlotsToSkeleton")
|
||||
.with<ECS::Skeleton>().parent()
|
||||
.without<ECS::Bound>()
|
||||
.without<ECS::Skinned>()
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([vs](flecs::entity e, ECS::CharacterSlot &slot)
|
||||
{
|
||||
flecs::entity parent = e.parent();
|
||||
int i;
|
||||
assert(!e.has<ECS::Bound>());
|
||||
assert(!e.has<ECS::Skinned>());
|
||||
ECS::Skeleton *skel = parent.get_mut<ECS::Skeleton>();
|
||||
if (skel->skin.is_null() && slot.skin_internal.is_null()) {
|
||||
const struct ECS::Skeleton::bone_data *bonesptr = skel->bones.ptr();
|
||||
const int *order = skel->process_order.ptr();
|
||||
flecs::log::trace("binding slot for %s", e.name().c_str());
|
||||
slot.skin_internal.instance();
|
||||
slot.skin_internal->set_bind_count(skel->bones.size());
|
||||
int len = skel->bones.size();
|
||||
flecs::log::trace("creating skin for %s", e.name().c_str());
|
||||
for (i = 0; i < len; i++) {
|
||||
const struct ECS::Skeleton::bone_data &b = bonesptr[order[i]];
|
||||
if (b.parent >= 0)
|
||||
slot.skin_internal->set_bind_pose(order[i], slot.skin_internal->get_bind_pose(b.parent) * b.rest);
|
||||
else
|
||||
slot.skin_internal->set_bind_pose(order[i], b.rest);
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
slot.skin_internal->set_bind_bone(i, i);
|
||||
slot.skin_internal->set_bind_pose(i, slot.skin_internal->get_bind_pose(i).affine_inverse());
|
||||
}
|
||||
skel->skin = slot.skin_internal;
|
||||
flecs::log::trace("created skin for %s: %d", e.name().c_str(), len);
|
||||
assert(skel->skeleton.is_valid());
|
||||
skel->skin = slot.skin_internal;
|
||||
uint32_t bind_count = skel->skin->get_bind_count();
|
||||
assert(bind_count > 0);
|
||||
skel->skin_bone_indices.resize(bind_count);
|
||||
skel->skin_bone_indices_ptrs = skel->skin_bone_indices.ptrw();
|
||||
for (i = 0; i < bind_count; i++) {
|
||||
StringName bind_name = skel->skin->get_bind_name(i);
|
||||
if (bind_name != StringName()) {
|
||||
int j;
|
||||
bool found = false;
|
||||
for (j = 0; j < len; j++) {
|
||||
if (bonesptr[j].name == bind_name) {
|
||||
skel->skin_bone_indices_ptrs[i] = j;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
flecs::log::err("no bind name %s in skeleton", String(bind_name).ascii().get_data());
|
||||
}
|
||||
} else if (skel->skin->get_bind_bone(i) >= 0) {
|
||||
uint32_t bind_index = skel->skin->get_bind_bone(i);
|
||||
if (bind_index >= len) {
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
flecs::log::err("bind %d bad index %d", i, bind_index);
|
||||
} else
|
||||
skel->skin_bone_indices_ptrs[i] = bind_index;
|
||||
} else {
|
||||
flecs::log::err("no bind name for %d", i);
|
||||
skel->skin_bone_indices_ptrs[i] = 0;
|
||||
}
|
||||
}
|
||||
e.add<ECS::Skinned>();
|
||||
} else if (!skel->skin.is_null() && slot.skin_internal.is_null()) {
|
||||
slot.skin_internal = skel->skin;
|
||||
e.add<ECS::Skinned>();
|
||||
}
|
||||
});
|
||||
}
|
||||
14
src/modules/character/config.py
Normal file
14
src/modules/character/config.py
Normal file
@@ -0,0 +1,14 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return []
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
||||
1
src/modules/character/flecs
Submodule
1
src/modules/character/flecs
Submodule
Submodule src/modules/character/flecs added at bbf695607e
44
src/modules/character/register_types.cpp
Normal file
44
src/modules/character/register_types.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <core/engine.h>
|
||||
#include "character.h"
|
||||
#include "register_types.h"
|
||||
|
||||
void register_character_types()
|
||||
{
|
||||
#if 0
|
||||
ClassDB::register_class<AnimScene>();
|
||||
ClassDB::register_virtual_class<CharAnimStepCommon>();
|
||||
ClassDB::register_class<CharAnimStepBase>();
|
||||
ClassDB::register_class<CharAnimData>();
|
||||
ClassDB::register_class<AnimatedScene>();
|
||||
ClassDB::register_class<SmartObjectStep>();
|
||||
ClassDB::register_class<SmartObjectSteps>();
|
||||
ClassDB::register_class<GoapGoal>();
|
||||
ClassDB::register_class<GoapAction>();
|
||||
ClassDB::register_class<SmartObjectAction>();
|
||||
ClassDB::register_class<GoapActionPlanner>();
|
||||
ClassDB::register_class<GoapActionData>();
|
||||
ClassDB::register_class<GoapRunner>();
|
||||
ClassDB::register_class<NPCClimb>();
|
||||
ClassDB::register_class<ContextSteering>();
|
||||
ClassDB::register_class<SceneComps>();
|
||||
ClassDB::register_class<NPCMotion>();
|
||||
ClassDB::register_class<NPCBackground>();
|
||||
ClassDB::register_class<NPC_Data>();
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("SceneComps", SceneComps::get_singleton()));
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("Profile", Profile::get_singleton()));
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("NPC_Data", NPC_Data::get_singleton()));
|
||||
#endif
|
||||
ClassDB::register_class<Character>();
|
||||
Character::get_singleton();
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("Character", Character::get_singleton()));
|
||||
}
|
||||
|
||||
void unregister_character_types()
|
||||
{
|
||||
#if 0
|
||||
SceneComps::cleanup();
|
||||
Profile::cleanup();
|
||||
NPC_Data::cleanup();
|
||||
#endif
|
||||
Character::cleanup();
|
||||
}
|
||||
7
src/modules/character/register_types.h
Normal file
7
src/modules/character/register_types.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef ANIMATION_REGISTER_TYPES_H
|
||||
#define ANIMATION_REGISTER_TYPES_H
|
||||
|
||||
void register_character_types();
|
||||
void unregister_character_types();
|
||||
|
||||
#endif // ANIMATION_REGISTER_TYPES_H
|
||||
11
src/modules/character/skeleton-prep.h
Normal file
11
src/modules/character/skeleton-prep.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef SKELETON_PREP_H
|
||||
#define SKELETON_PREP_H
|
||||
#include <flecs.h>
|
||||
|
||||
struct skeleton_prep {
|
||||
skeleton_prep(flecs::world &world)
|
||||
{
|
||||
world.module<skeleton_prep>();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
From 29a376ed6ad549cf80aa1fd215aa5d34e9b9c29f Mon Sep 17 00:00:00 2001
|
||||
From: Sergey Lapin <slapinid@gmail.com>
|
||||
Date: Fri, 13 Jan 2023 19:09:56 +0300
|
||||
Subject: [PATCH] Shut up and fix some errors breaking engine
|
||||
|
||||
---
|
||||
drivers/gles2/rasterizer_storage_gles2.cpp | 2 +-
|
||||
drivers/gles3/rasterizer_storage_gles3.cpp | 2 +-
|
||||
scene/animation/skeleton_ik.cpp | 6 +++++-
|
||||
3 files changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
|
||||
index 028b399a59..807b95fe57 100644
|
||||
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
|
||||
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
|
||||
@@ -2833,7 +2833,7 @@ AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const {
|
||||
const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr();
|
||||
|
||||
int sbs = sk->size;
|
||||
- ERR_CONTINUE(bs > sbs);
|
||||
+// ERR_CONTINUE(bs > sbs);
|
||||
const float *texture = sk->bone_data.ptr();
|
||||
|
||||
bool first = true;
|
||||
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
|
||||
index c865c77bf8..bacc78d02d 100644
|
||||
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
|
||||
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
|
||||
@@ -4153,7 +4153,7 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const {
|
||||
const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr();
|
||||
|
||||
int sbs = sk->size;
|
||||
- ERR_CONTINUE(bs > sbs);
|
||||
+// ERR_CONTINUE(bs > sbs);
|
||||
const float *texture = sk->skel_texture.ptr();
|
||||
|
||||
bool first = true;
|
||||
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
|
||||
index 954ec66a84..a4ad34fa2d 100644
|
||||
--- a/scene/animation/skeleton_ik.cpp
|
||||
+++ b/scene/animation/skeleton_ik.cpp
|
||||
@@ -55,7 +55,7 @@ FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(
|
||||
|
||||
/// Build a chain that starts from the root to tip
|
||||
bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) {
|
||||
- ERR_FAIL_COND_V(-1 == p_task->root_bone, false);
|
||||
+
|
||||
|
||||
Chain &chain(p_task->chain);
|
||||
|
||||
@@ -566,6 +566,10 @@ void SkeletonIK::reload_chain() {
|
||||
if (!skeleton) {
|
||||
return;
|
||||
}
|
||||
+ if (skeleton->find_bone(root_bone) < 0)
|
||||
+ return;
|
||||
+ if (skeleton->find_bone(tip_bone) < 0)
|
||||
+ return;
|
||||
|
||||
task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform());
|
||||
if (task) {
|
||||
--
|
||||
2.34.1
|
||||
|
||||
1262
src/patches/0002-Revert-PopupMenu-rework-and-enhancements.patch
Normal file
1262
src/patches/0002-Revert-PopupMenu-rework-and-enhancements.patch
Normal file
File diff suppressed because it is too large
Load Diff
37
src/patches/0003-Asserts-work-in-debug-builds.patch
Normal file
37
src/patches/0003-Asserts-work-in-debug-builds.patch
Normal file
@@ -0,0 +1,37 @@
|
||||
From 0c7a32d332d352544d797f3909604f49c6ba40b8 Mon Sep 17 00:00:00 2001
|
||||
From: Sergey Lapin <slapinid@gmail.com>
|
||||
Date: Thu, 6 Apr 2023 19:35:47 +0300
|
||||
Subject: [PATCH] Asserts work in debug builds
|
||||
|
||||
---
|
||||
modules/gdscript/gdscript_function.cpp | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
|
||||
index d58164ffa9..9bd955452d 100644
|
||||
--- a/modules/gdscript/gdscript_function.cpp
|
||||
+++ b/modules/gdscript/gdscript_function.cpp
|
||||
@@ -28,6 +28,9 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
+#include <cstdio>
|
||||
+#include <cstdlib>
|
||||
+
|
||||
#include "gdscript_function.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
@@ -1550,6 +1553,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
_err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
|
||||
}
|
||||
|
||||
+#ifndef TOOLS_ENABLED
|
||||
+ fprintf(stderr, "ASSERT failed: %ls\n", err_text.c_str());
|
||||
+ abort();
|
||||
+#endif
|
||||
#endif
|
||||
OPCODE_OUT;
|
||||
}
|
||||
--
|
||||
2.34.1
|
||||
|
||||
Reference in New Issue
Block a user