Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skeletal animation (part 1) #290

Merged
merged 9 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/core/shaders/common.shader
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ bgfx_shaders = {
#define BGFX_SHADER_H_HEADER_GUARD

#if !defined(BGFX_CONFIG_MAX_BONES)
# define BGFX_CONFIG_MAX_BONES 32
# define BGFX_CONFIG_MAX_BONES 192
#endif // !defined(BGFX_CONFIG_MAX_BONES)

#ifndef __cplusplus
Expand Down
19 changes: 19 additions & 0 deletions samples/core/shaders/default.shader
Original file line number Diff line number Diff line change
Expand Up @@ -218,19 +218,36 @@ bgfx_shaders = {
vec3 a_position : POSITION;
vec3 a_normal : NORMAL;
vec2 a_texcoord0 : TEXCOORD0;
vec4 a_indices : BLENDINDICES;
vec4 a_weight : BLENDWEIGHT;
"""

vs_input_output = """
#if defined(SKINNING)
$input a_position, a_normal, a_texcoord0, a_indices, a_weight
#else
$input a_position, a_normal, a_texcoord0
#endif
$output v_normal, v_view, v_texcoord0
"""

vs_code = """
void main()
{
#if defined(SKINNING)
mat4 model;
model = a_weight.x * u_model[int(a_indices.x)];
model += a_weight.y * u_model[int(a_indices.y)];
model += a_weight.z * u_model[int(a_indices.z)];
model += a_weight.w * u_model[int(a_indices.w)];
gl_Position = mul(mul(u_modelViewProj, model), vec4(a_position, 1.0));
v_view = mul(mul(u_modelView, model), vec4(a_position, 1.0));
v_normal = normalize(mul(mul(u_modelView, model), vec4(a_normal, 0.0)).xyz);
#else
gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
v_view = mul(u_modelView, vec4(a_position, 1.0));
v_normal = normalize(mul(u_modelView, vec4(a_normal, 0.0)).xyz);
#endif

v_texcoord0 = a_texcoord0;
}
Expand Down Expand Up @@ -561,6 +578,8 @@ static_compile = [
{ shader = "sprite" defines = [] }
{ shader = "mesh" defines = [] }
{ shader = "mesh" defines = ["DIFFUSE_MAP"] }
{ shader = "mesh" defines = ["SKINNING"] }
{ shader = "mesh" defines = ["DIFFUSE_MAP" "SKINNING"] }
{ shader = "mesh" defines = ["DIFFUSE_MAP" "NO_LIGHT"] }
{ shader = "selection" defines = [] }
{ shader = "outline" defines = [] }
Expand Down
1 change: 1 addition & 0 deletions scripts/uncrustify/format-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ format_tools_vala () {
| grep -v 'project_browser.vala' \
| grep -v 'resource_chooser.vala' \
| grep -v 'user.vala' \
| grep -v 'mesh_resource_fbx.vala' \
| tr '\n' '\0' \
| xargs -0 -n1 -P"$1" ./scripts/uncrustify/uncrustify-wrapper.sh scripts/uncrustify/vala.cfg
}
Expand Down
4 changes: 4 additions & 0 deletions src/device/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include "resource/lua_resource.h"
#include "resource/material_resource.h"
#include "resource/mesh_resource.h"
#include "resource/mesh_skeleton_resource.h"
#include "resource/mesh_animation_resource.h"
#include "resource/package_resource.h"
#include "resource/physics_resource.h"
#include "resource/resource_id.inl"
Expand Down Expand Up @@ -584,6 +586,8 @@ void Device::run()
_resource_manager->register_type(RESOURCE_TYPE_LEVEL, RESOURCE_VERSION_LEVEL, NULL, NULL, NULL, NULL);
_resource_manager->register_type(RESOURCE_TYPE_MATERIAL, RESOURCE_VERSION_MATERIAL, NULL, NULL, mtr::online, mtr::offline);
_resource_manager->register_type(RESOURCE_TYPE_MESH, RESOURCE_VERSION_MESH, mhr::load, mhr::unload, mhr::online, mhr::offline);
_resource_manager->register_type(RESOURCE_TYPE_MESH_SKELETON, RESOURCE_VERSION_MESH_SKELETON, NULL, NULL, NULL, NULL);
_resource_manager->register_type(RESOURCE_TYPE_MESH_ANIMATION, RESOURCE_VERSION_MESH_ANIMATION, NULL, NULL, NULL, NULL);
_resource_manager->register_type(RESOURCE_TYPE_PACKAGE, RESOURCE_VERSION_PACKAGE, NULL, NULL, NULL, NULL);
_resource_manager->register_type(RESOURCE_TYPE_PHYSICS_CONFIG, RESOURCE_VERSION_PHYSICS_CONFIG, NULL, NULL, NULL, NULL);
_resource_manager->register_type(RESOURCE_TYPE_SCRIPT, RESOURCE_VERSION_SCRIPT, NULL, NULL, NULL, NULL);
Expand Down
51 changes: 19 additions & 32 deletions src/resource/data_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "resource/lua_resource.h"
#include "resource/material_resource.h"
#include "resource/mesh_resource.h"
#include "resource/mesh_skeleton_resource.h"
#include "resource/mesh_animation_resource.h"
#include "resource/package_resource.h"
#include "resource/physics_resource.h"
#include "resource/resource_id.inl"
Expand Down Expand Up @@ -1534,39 +1536,24 @@ int main_data_compiler(const DeviceOptions &opts)
if (opts._server)
console_server()->listen(CROWN_DEFAULT_COMPILER_PORT, opts._wait_console);

namespace cor = config_resource_internal;
namespace ftr = font_resource_internal;
namespace lur = lua_resource_internal;
namespace lvr = level_resource_internal;
namespace mhr = mesh_resource_internal;
namespace mtr = material_resource_internal;
namespace pcr = physics_config_resource_internal;
namespace phr = physics_resource_internal;
namespace pkr = package_resource_internal;
namespace sar = sprite_animation_resource_internal;
namespace sdr = sound_resource_internal;
namespace shr = shader_resource_internal;
namespace smr = state_machine_internal;
namespace spr = sprite_resource_internal;
namespace txr = texture_resource_internal;
namespace utr = unit_resource_internal;

DataCompiler *dc = CE_NEW(default_allocator(), DataCompiler)(opts, *console_server());
dc->register_compiler("config", RESOURCE_VERSION_CONFIG, cor::compile);
dc->register_compiler("font", RESOURCE_VERSION_FONT, ftr::compile);
dc->register_compiler("level", RESOURCE_VERSION_LEVEL, lvr::compile);
dc->register_compiler("material", RESOURCE_VERSION_MATERIAL, mtr::compile);
dc->register_compiler("mesh", RESOURCE_VERSION_MESH, mhr::compile);
dc->register_compiler("package", RESOURCE_VERSION_PACKAGE, pkr::compile);
dc->register_compiler("physics_config", RESOURCE_VERSION_PHYSICS_CONFIG, pcr::compile);
dc->register_compiler("lua", RESOURCE_VERSION_SCRIPT, lur::compile);
dc->register_compiler("shader", RESOURCE_VERSION_SHADER, shr::compile);
dc->register_compiler("sound", RESOURCE_VERSION_SOUND, sdr::compile);
dc->register_compiler("sprite", RESOURCE_VERSION_SPRITE, spr::compile);
dc->register_compiler("sprite_animation", RESOURCE_VERSION_SPRITE_ANIMATION, sar::compile);
dc->register_compiler("state_machine", RESOURCE_VERSION_STATE_MACHINE, smr::compile);
dc->register_compiler("texture", RESOURCE_VERSION_TEXTURE, txr::compile);
dc->register_compiler("unit", RESOURCE_VERSION_UNIT, utr::compile);
dc->register_compiler("config", RESOURCE_VERSION_CONFIG, config_resource_internal::compile);
dc->register_compiler("font", RESOURCE_VERSION_FONT, font_resource_internal::compile);
dc->register_compiler("level", RESOURCE_VERSION_LEVEL, level_resource_internal::compile);
dc->register_compiler("material", RESOURCE_VERSION_MATERIAL, material_resource_internal::compile);
dc->register_compiler("mesh", RESOURCE_VERSION_MESH, mesh_resource_internal::compile);
dc->register_compiler("mesh_skeleton", RESOURCE_VERSION_MESH_SKELETON, mesh_skeleton_resource_internal::compile);
dc->register_compiler("mesh_animation", RESOURCE_VERSION_MESH_ANIMATION, mesh_animation_resource_internal::compile);
dc->register_compiler("package", RESOURCE_VERSION_PACKAGE, package_resource_internal::compile);
dc->register_compiler("physics_config", RESOURCE_VERSION_PHYSICS_CONFIG, physics_config_resource_internal::compile);
dc->register_compiler("lua", RESOURCE_VERSION_SCRIPT, lua_resource_internal::compile);
dc->register_compiler("shader", RESOURCE_VERSION_SHADER, shader_resource_internal::compile);
dc->register_compiler("sound", RESOURCE_VERSION_SOUND, sound_resource_internal::compile);
dc->register_compiler("sprite", RESOURCE_VERSION_SPRITE, sprite_resource_internal::compile);
dc->register_compiler("sprite_animation", RESOURCE_VERSION_SPRITE_ANIMATION, sprite_animation_resource_internal::compile);
dc->register_compiler("state_machine", RESOURCE_VERSION_STATE_MACHINE, state_machine_internal::compile);
dc->register_compiler("texture", RESOURCE_VERSION_TEXTURE, texture_resource_internal::compile);
dc->register_compiler("unit", RESOURCE_VERSION_UNIT, unit_resource_internal::compile);

dc->map_source_dir("", opts._source_dir.c_str());

Expand Down
140 changes: 140 additions & 0 deletions src/resource/fbx_document.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2012-2025 Daniele Bartolini et al.
* SPDX-License-Identifier: MIT
*/

#include "resource/fbx_document.h"

#if CROWN_CAN_COMPILE
# include "core/containers/array.inl"
# include "core/containers/hash_map.inl"
# include "core/strings/string_id.inl"
# include "resource/compile_options.inl"
# include <ufbx.h>

namespace crown
{
namespace fbx
{
static ufbx_node *find_first_non_bone_parent(ufbx_node *bone_node)
{
while (bone_node && bone_node->bone != NULL)
bone_node = bone_node->parent;

return bone_node;
}

static ufbx_node *find_skeleton_root(ufbx_node *node)
{
if (node->bone != NULL)
return node;

for (size_t i = 0; i < node->children.count; ++i) {
ufbx_node *n = find_skeleton_root(node->children.data[i]);
if (n != NULL)
return find_first_non_bone_parent(n);
}

return NULL;
}

u16 bone_id(const FBXDocument &fbx, StringId32 bone_name)
{
u16 deffault_bone_id = UINT16_MAX;
return hash_map::get(fbx.bone_ids, bone_name, deffault_bone_id);
}

u16 bone_id(const FBXDocument &fbx, const char *bone_name)
{
return bone_id(fbx, StringId32(bone_name));
}

static s32 populate_bone_ids(FBXDocument &fbx, ufbx_node *bone, CompileOptions &opts, u32 *debug_num_bones)
{
u16 bone_id = (u16)hash_map::size(fbx.bone_ids);
StringId32 bone_name = StringId32(bone->name.data);
hash_map::set(fbx.bone_ids, bone_name, bone_id);
(*debug_num_bones)++;

for (size_t i = 0; i < bone->children.count; ++i) {
ufbx_node *child = bone->children.data[i];
s32 err = populate_bone_ids(fbx, child, opts, debug_num_bones);
ENSURE_OR_RETURN(err == 0, opts);
}

return 0;
}

s32 parse(FBXDocument &fbx, Buffer &buf, CompileOptions &opts)
{
// Keep in sync with mesh_resource_fbx.vala!
ufbx_load_opts load_opts = {};
load_opts.target_camera_axes =
{
UFBX_COORDINATE_AXIS_POSITIVE_X,
UFBX_COORDINATE_AXIS_POSITIVE_Z,
UFBX_COORDINATE_AXIS_NEGATIVE_Y
};
load_opts.target_light_axes =
{
UFBX_COORDINATE_AXIS_POSITIVE_X,
UFBX_COORDINATE_AXIS_POSITIVE_Y,
UFBX_COORDINATE_AXIS_POSITIVE_Z
};
load_opts.target_axes = ufbx_axes_right_handed_z_up;
load_opts.target_unit_meters = 1.0f;
load_opts.space_conversion = UFBX_SPACE_CONVERSION_TRANSFORM_ROOT;

ufbx_error error;
fbx.scene = ufbx_load_memory(array::begin(buf)
, array::size(buf)
, &load_opts
, &error
);
RETURN_IF_FALSE(fbx.scene != NULL
, opts
, "ufbx: %s"
, error.description.data
);

fbx.skeleton_root_node = find_skeleton_root(fbx.scene->root_node);
if (fbx.skeleton_root_node != NULL) {
u32 debug_num_bones = 0;
s32 err = populate_bone_ids(fbx, fbx.skeleton_root_node, opts, &debug_num_bones);
ENSURE_OR_RETURN(err == 0, opts);
RETURN_IF_FALSE(debug_num_bones == hash_map::size(fbx.bone_ids)
, opts
, "Bone mismatch expected/actual %u/%u"
, debug_num_bones
, hash_map::size(fbx.bone_ids)
);
}

return 0;
}

///
s32 parse(FBXDocument &fbx, const char *path, CompileOptions &opts)
{
RETURN_IF_FILE_MISSING(path, opts);
Buffer buf = opts.read(path);
return parse(fbx, buf, opts);
}

} // namespace fbx

FBXDocument::FBXDocument(Allocator &a)
: scene(NULL)
, skeleton_root_node(NULL)
, bone_ids(a)
{
}

FBXDocument::~FBXDocument()
{
ufbx_free_scene(scene);
}

} // namespace crown

#endif // if CROWN_CAN_COMPILE
53 changes: 53 additions & 0 deletions src/resource/fbx_document.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2012-2025 Daniele Bartolini et al.
* SPDX-License-Identifier: MIT
*/

#pragma once

#include "config.h"

#if CROWN_CAN_COMPILE
# include "core/filesystem/types.h"
# include "core/math/types.h"
# include "core/memory/types.h"
# include "core/strings/dynamic_string.h"
# include "resource/types.h"

struct ufbx_scene; // Avoids #include <ufbx.h>
struct ufbx_node; // Ditto.

namespace crown
{
struct FBXDocument
{
ufbx_scene *scene;
ufbx_node *skeleton_root_node;
HashMap<StringId32, u16> bone_ids;

///
explicit FBXDocument(Allocator &a);

///
~FBXDocument();
};

namespace fbx
{
/// Returns the node ID for @a bone_name.
u16 bone_id(const FBXDocument &fbx, StringId32 bone_name);

/// Returns the node ID for @a bone_name.
u16 bone_id(const FBXDocument &fbx, const char *bone_name);

///
s32 parse(FBXDocument &fbx, Buffer &buf, CompileOptions &opts);

///
s32 parse(FBXDocument &fbx, const char *path, CompileOptions &opts);

} // namespace fbx

} // namespace crown

#endif // if CROWN_CAN_COMPILE
Loading
Loading