initial commit

This commit is contained in:
2023-09-13 03:04:01 +03:00
commit 22482cc9b2
58 changed files with 2051448 additions and 0 deletions

1
src/godot Submodule

Submodule src/godot added at db8700e8f8

View 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

View 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());
}

View 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

View 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
}

View 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>();
}
});
}

View 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"

View 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();
}

View 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

View 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

View File

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

File diff suppressed because it is too large Load Diff

View 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