Updated ozz-animation to version 0.14.1 @35b2efd4

This commit is contained in:
Martin Felis
2023-03-26 13:28:12 +02:00
parent bf3189ff49
commit 15871f349c
194 changed files with 3495 additions and 1957 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
# Directory src is available from the implementation files.
include_directories(./)
add_subdirectory(animation)
add_subdirectory(geometry)
add_subdirectory(base)
add_subdirectory(options)
add_subdirectory(animation)
add_subdirectory(geometry)
+2 -2
View File
@@ -1,2 +1,2 @@
add_subdirectory(offline)
add_subdirectory(runtime)
add_subdirectory(runtime)
add_subdirectory(offline)
@@ -1,4 +1,6 @@
add_library(ozz_animation_offline STATIC
add_library(ozz_animation_offline
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/export.h
decimate.h
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/raw_animation.h
raw_animation.cc
@@ -22,8 +24,10 @@ add_library(ozz_animation_offline STATIC
track_builder.cc
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/track_optimizer.h
track_optimizer.cc)
target_link_libraries(ozz_animation_offline
ozz_animation)
target_compile_definitions(ozz_animation_offline PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_ANIMOFFLINE_LIB>)
target_link_libraries(ozz_animation_offline ozz_animation)
set_target_properties(ozz_animation_offline PROPERTIES FOLDER "ozz")
@@ -31,7 +35,7 @@ install(TARGETS ozz_animation_offline DESTINATION lib)
fuse_target("ozz_animation_offline")
add_subdirectory(tools) # tools target need to be defined before other targets that uses them
add_subdirectory(fbx)
add_subdirectory(gltf)
add_subdirectory(tools)
@@ -89,6 +89,7 @@ bool AdditiveAnimationBuilder::operator()(const RawAnimation& _input,
}
// Rebuilds output animation.
_output->name = _input.name;
_output->duration = _input.duration;
_output->tracks.resize(_input.tracks.size());
@@ -143,6 +144,7 @@ bool AdditiveAnimationBuilder::operator()(
}
// Rebuilds output animation.
_output->name = _input.name;
_output->duration = _input.duration;
_output->tracks.resize(_input.tracks.size());
@@ -163,7 +163,7 @@ void CompressQuat(const ozz::math::Quaternion& _src,
ozz::animation::QuaternionKey* _dest) {
// Finds the largest quaternion component.
const float quat[4] = {_src.x, _src.y, _src.z, _src.w};
const size_t largest = std::max_element(quat, quat + 4, LessAbs) - quat;
const ptrdiff_t largest = std::max_element(quat, quat + 4, LessAbs) - quat;
assert(largest <= 3);
_dest->largest = largest & 0x3;
@@ -269,7 +269,7 @@ unique_ptr<Animation> AnimationBuilder::operator()(
// Declares and preallocates tracks to sort.
size_t translations = 0, rotations = 0, scales = 0;
for (int i = 0; i < num_tracks; ++i) {
for (uint16_t i = 0; i < num_tracks; ++i) {
const RawAnimation::JointTrack& raw_track = _input.tracks[i];
translations += raw_track.translations.size() + 2; // +2 because worst case
rotations += raw_track.rotations.size() + 2; // needs to add the
@@ -2,22 +2,20 @@ if(NOT ozz_build_fbx)
return()
endif()
add_library(ozz_animation_fbx STATIC
add_library(ozz_animation_fbx
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/fbx/export.h
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/fbx/fbx.h
fbx.cc
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/fbx/fbx_animation.h
fbx_animation.cc
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/fbx/fbx_skeleton.h
fbx_skeleton.cc)
target_include_directories(ozz_animation_fbx
PUBLIC $<BUILD_INTERFACE:${FBX_INCLUDE_DIRS}>)
target_compile_definitions(ozz_animation_fbx PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_ANIMATIONFBX_LIB>)
target_link_libraries(ozz_animation_fbx
ozz_animation_offline
debug ${FBX_LIBRARIES_DEBUG}
optimized ${FBX_LIBRARIES})
target_compile_options(ozz_animation_fbx
PUBLIC $<$<BOOL:${W_NULL_DEREFERENCE}>:-Wno-null-dereference>
PUBLIC $<$<BOOL:${W_PRAGMA_PACK}>:-Wno-pragma-pack>)
fbx::sdk)
set_target_properties(ozz_animation_fbx PROPERTIES FOLDER "ozz/tools")
install(TARGETS ozz_animation_fbx DESTINATION lib)
@@ -32,6 +30,7 @@ add_executable(fbx2ozz
target_link_libraries(fbx2ozz
ozz_animation_tools
ozz_animation_fbx)
target_copy_shared_libraries(fbx2ozz)
set_target_properties(fbx2ozz
PROPERTIES FOLDER "ozz/tools")
@@ -45,6 +44,7 @@ set(build_configurations
"/fbx/pab/locomotions.fbx\;{\"skeleton\":{\"filename\":\"pab_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"pab_*.ozz\"}]}\;output:pab_walk.ozz\;output:pab_jog.ozz\;output:pab_run.ozz\;depend:pab_skeleton.ozz"
"/fbx/pab/crossarms.fbx\;{\"skeleton\":{\"filename\":\"pab_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"pab_crossarms.ozz\"}]}\;output:pab_crossarms.ozz\;depend:pab_skeleton.ozz"
"/fbx/pab/crackhead.fbx\;{\"skeleton\":{\"filename\":\"pab_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"pab_crackhead.ozz\"},{\"filename\":\"pab_crackhead_additive.ozz\",\"additive\":true}]}\;output:pab_crackhead_additive.ozz\;output:pab_crackhead.ozz\;depend:pab_skeleton.ozz"
"/fbx/pab/hand.fbx\;{\"skeleton\":{\"filename\":\"pab_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"clip\":\"curl\",\"filename\":\"pab_curl_additive.ozz\",\"additive\":true,\"additive_reference\":\"skeleton\"},{\"clip\":\"splay\",\"filename\":\"pab_splay_additive.ozz\",\"additive\":true,\"additive_reference\":\"skeleton\"}]}\;output:pab_curl_additive.ozz\;output:pab_splay_additive.ozz\;depend:pab_skeleton.ozz"
# Robot user channels
"/fbx/robot.fbx\;\;config_file:${PROJECT_SOURCE_DIR}/samples/user_channel/config.json\;output:robot_skeleton.ozz\;output:robot_animation.ozz\;output:robot_track_grasp.ozz"
@@ -28,15 +28,12 @@
#include "ozz/animation/offline/fbx/fbx_animation.h"
#include "ozz/animation/offline/fbx/fbx.h"
#include "ozz/animation/offline/raw_animation.h"
#include "ozz/animation/offline/raw_animation_utils.h"
#include "ozz/animation/offline/raw_track.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/animation/runtime/skeleton_utils.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/transform.h"
@@ -157,16 +154,16 @@ bool ExtractAnimation(FbxSceneLoader& _scene_loader, const SamplingInfo& _info,
if (node == nullptr) {
ozz::log::LogV() << "No animation track found for joint \""
<< _skeleton.joint_names()[i]
<< "\". Using skeleton bind pose instead." << std::endl;
<< "\". Using skeleton rest pose instead." << std::endl;
const math::Transform& bind_pose =
ozz::animation::GetJointLocalBindPose(_skeleton, i);
const math::Transform& rest_pose =
ozz::animation::GetJointLocalRestPose(_skeleton, i);
const math::SimdFloat4 t =
math::simd_float4::Load3PtrU(&bind_pose.translation.x);
math::simd_float4::Load3PtrU(&rest_pose.translation.x);
const math::SimdFloat4 q =
math::simd_float4::LoadPtrU(&bind_pose.rotation.x);
math::simd_float4::LoadPtrU(&rest_pose.rotation.x);
const math::SimdFloat4 s =
math::simd_float4::Load3PtrU(&bind_pose.scale.x);
math::simd_float4::Load3PtrU(&rest_pose.scale.x);
const math::Float4x4 local_matrix = math::Float4x4::FromAffine(t, q, s);
ozz::vector<math::Float4x4>& node_matrices = world_matrices[i];
@@ -201,7 +198,7 @@ bool ExtractAnimation(FbxSceneLoader& _scene_loader, const SamplingInfo& _info,
// Builds local space animation tracks.
// Allocates all tracks with the same number of joints as the skeleton.
// Tracks that would not be found will be set to skeleton bind-pose
// Tracks that would not be found will be set to skeleton rest-pose
// transformation.
_animation->tracks.resize(_skeleton.num_joints());
for (int i = 0; i < _skeleton.num_joints(); i++) {
@@ -28,7 +28,6 @@
#include "ozz/animation/offline/fbx/fbx_skeleton.h"
#include "ozz/animation/offline/raw_skeleton.h"
#include "ozz/base/log.h"
namespace ozz {
@@ -78,9 +77,12 @@ bool IsTypeSelected(const OzzImporter::NodeType& _types,
case FbxNodeAttribute::eLight:
return _types.light;
// Null
case FbxNodeAttribute::eNull:
return _types.null;
// Others
case FbxNodeAttribute::eUnknown:
case FbxNodeAttribute::eNull:
case FbxNodeAttribute::eCameraSwitcher:
case FbxNodeAttribute::eOpticalReference:
case FbxNodeAttribute::eOpticalMarker:
@@ -116,7 +118,7 @@ RecurseReturn RecurseNode(FbxNode* _node, FbxSystemConverter* _converter,
this_joint = &sibling->back(); // Will not be resized inside recursion.
this_joint->name = _node->GetName();
// Extract bind pose.
// Extract rest pose.
const FbxAMatrix node_global = _node->EvaluateGlobalTransform();
const FbxAMatrix node_local = _parent_global_inv * node_global;
@@ -7,6 +7,7 @@ add_executable(gltf2ozz
target_link_libraries(gltf2ozz PRIVATE
ozz_animation_tools)
target_copy_shared_libraries(gltf2ozz)
set_target_properties(gltf2ozz
PROPERTIES FOLDER "ozz/tools")
@@ -9745,7 +9745,7 @@ class binary_writer
static CharType to_char_type(std::uint8_t x) noexcept
{
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
static_assert(std::is_pod<CharType>::value, "CharType must be POD");
static_assert(std::is_standard_layout<CharType>::value && std::is_trivial<CharType>::value, "CharType must be POD");
CharType result;
std::memcpy(&result, &x, sizeof(x));
return result;
+37 -35
View File
@@ -358,7 +358,7 @@ bool SampleChannel(const tinygltf::Model& _model,
}
ozz::animation::offline::RawAnimation::TranslationKey
CreateTranslationBindPoseKey(const tinygltf::Node& _node) {
CreateTranslationRestPoseKey(const tinygltf::Node& _node) {
ozz::animation::offline::RawAnimation::TranslationKey key;
key.time = 0.0f;
@@ -373,7 +373,7 @@ CreateTranslationBindPoseKey(const tinygltf::Node& _node) {
return key;
}
ozz::animation::offline::RawAnimation::RotationKey CreateRotationBindPoseKey(
ozz::animation::offline::RawAnimation::RotationKey CreateRotationRestPoseKey(
const tinygltf::Node& _node) {
ozz::animation::offline::RawAnimation::RotationKey key;
key.time = 0.0f;
@@ -389,7 +389,7 @@ ozz::animation::offline::RawAnimation::RotationKey CreateRotationBindPoseKey(
return key;
}
ozz::animation::offline::RawAnimation::ScaleKey CreateScaleBindPoseKey(
ozz::animation::offline::RawAnimation::ScaleKey CreateScaleRestPoseKey(
const tinygltf::Node& _node) {
ozz::animation::offline::RawAnimation::ScaleKey key;
key.time = 0.0f;
@@ -430,8 +430,8 @@ bool CreateNodeTransform(const tinygltf::Node& _node,
ozz::math::SimdFloat4 translation, rotation, scale;
if (ToAffine(matrix, &translation, &rotation, &scale)) {
ozz::math::Store3PtrU(translation, &_transform->translation.x);
ozz::math::StorePtrU(translation, &_transform->rotation.x);
ozz::math::Store3PtrU(translation, &_transform->scale.x);
ozz::math::StorePtrU(rotation, &_transform->rotation.x);
ozz::math::Store3PtrU(scale, &_transform->scale.x);
return true;
}
@@ -521,30 +521,38 @@ class GltfImporter : public ozz::animation::offline::OzzImporter {
return success;
}
// Given a skin find which of its joints is the skeleton root and return it
// returns -1 if the skin has no associated joints
int FindSkinRootJointIndex(const tinygltf::Skin& skin) {
if (skin.joints.empty()) {
return -1;
}
if (skin.skeleton != -1) {
return skin.skeleton;
}
ozz::map<int, int> parents;
for (int node : skin.joints) {
// Find all unique root joints of skeletons used by given skins and add them
// to `roots`
void FindSkinRootJointIndices(const ozz::vector<tinygltf::Skin>& skins,
ozz::vector<int>& roots) {
static constexpr int no_parent = -1;
static constexpr int visited = -2;
ozz::vector<int> parents(m_model.nodes.size(), no_parent);
for (int node = 0; node < static_cast<int>(m_model.nodes.size()); node++) {
for (int child : m_model.nodes[node].children) {
parents[child] = node;
}
}
int root = skin.joints[0];
while (parents.find(root) != parents.end()) {
root = parents[root];
}
for (const tinygltf::Skin& skin : skins) {
if (skin.joints.empty()) {
continue;
}
return root;
if (skin.skeleton != -1) {
parents[skin.skeleton] = visited;
roots.push_back(skin.skeleton);
continue;
}
int root = skin.joints[0];
while (root != visited && parents[root] != no_parent) {
root = parents[root];
}
if (root != visited) {
roots.push_back(root);
}
}
}
bool Import(ozz::animation::offline::RawSkeleton* _skeleton,
@@ -591,14 +599,8 @@ class GltfImporter : public ozz::animation::offline::OzzImporter {
<< std::endl;
}
// Uses all skins root
for (auto& skin : skins) {
const int root = FindSkinRootJointIndex(skin);
if (root == -1) {
continue;
}
roots.push_back(root);
}
// Uses all skins roots.
FindSkinRootJointIndices(skins, roots);
}
// Remove nodes listed multiple times.
@@ -745,16 +747,16 @@ class GltfImporter : public ozz::animation::offline::OzzImporter {
const tinygltf::Node* node = FindNodeByName(joint_names[i]);
assert(node != nullptr);
// Pads the bind pose transform for any joints which do not have an
// Pads the rest pose transform for any joints which do not have an
// associated channel for this animation
if (track.translations.empty()) {
track.translations.push_back(CreateTranslationBindPoseKey(*node));
track.translations.push_back(CreateTranslationRestPoseKey(*node));
}
if (track.rotations.empty()) {
track.rotations.push_back(CreateRotationBindPoseKey(*node));
track.rotations.push_back(CreateRotationRestPoseKey(*node));
}
if (track.scales.empty()) {
track.scales.push_back(CreateScaleBindPoseKey(*node));
track.scales.push_back(CreateScaleRestPoseKey(*node));
}
}
@@ -144,9 +144,9 @@ unique_ptr<ozz::animation::Skeleton> SkeletonBuilder::operator()(
}
// Fills the SoaTransform structure.
math::Transpose4x3(translations,
&skeleton->joint_bind_poses_[i].translation.x);
math::Transpose4x4(rotations, &skeleton->joint_bind_poses_[i].rotation.x);
math::Transpose4x3(scales, &skeleton->joint_bind_poses_[i].scale.x);
&skeleton->joint_rest_poses_[i].translation.x);
math::Transpose4x4(rotations, &skeleton->joint_rest_poses_[i].rotation.x);
math::Transpose4x3(scales, &skeleton->joint_rest_poses_[i].scale.x);
}
return skeleton; // Success.
@@ -4,7 +4,8 @@ endif()
add_subdirectory(${PROJECT_SOURCE_DIR}/extern/jsoncpp json)
add_library(ozz_animation_tools STATIC
add_library(ozz_animation_tools
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/tools/export.h
${PROJECT_SOURCE_DIR}/include/ozz/animation/offline/tools/import2ozz.h
import2ozz.cc
import2ozz_anim.h
@@ -15,10 +16,14 @@ add_library(ozz_animation_tools STATIC
import2ozz_skel.cc
import2ozz_track.h
import2ozz_track.cc)
target_compile_definitions(ozz_animation_tools PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_ANIMATIONTOOLS_LIB>)
target_link_libraries(ozz_animation_tools
ozz_animation_offline
ozz_options
json)
set_target_properties(ozz_animation_tools
PROPERTIES FOLDER "ozz/tools")
@@ -32,6 +37,7 @@ if(NOT EMSCRIPTEN)
target_link_libraries(dump2ozz
ozz_animation_tools
ozz_options)
target_copy_shared_libraries(dump2ozz)
# Uses a fake import file to dump reference and default configurations.
add_custom_command(TARGET dump2ozz POST_BUILD
@@ -39,4 +45,5 @@ if(NOT EMSCRIPTEN)
set_target_properties(dump2ozz
PROPERTIES FOLDER "ozz/tools")
endif()
@@ -137,11 +137,11 @@ unique_ptr<ozz::animation::Skeleton> LoadSkeleton(const char* _path) {
return skeleton;
}
vector<math::Transform> SkeletonBindPoseSoAToAoS(const Skeleton& _skeleton) {
// Copy skeleton bind pose to AoS form.
vector<math::Transform> SkeletonRestPoseSoAToAoS(const Skeleton& _skeleton) {
// Copy skeleton rest pose to AoS form.
vector<math::Transform> transforms(_skeleton.num_joints());
for (int i = 0; i < _skeleton.num_soa_joints(); ++i) {
const math::SoaTransform& soa_transform = _skeleton.joint_bind_poses()[i];
const math::SoaTransform& soa_transform = _skeleton.joint_rest_poses()[i];
math::SimdFloat4 translation[4];
math::SimdFloat4 rotation[4];
math::SimdFloat4 scale[4];
@@ -248,7 +248,7 @@ bool Export(OzzImporter& _importer, const RawAnimation& _input_animation,
bool succeeded = false;
if (enum_found && reference == AdditiveReferenceEnum::kSkeleton) {
const vector<math::Transform> transforms =
SkeletonBindPoseSoAToAoS(_skeleton);
SkeletonRestPoseSoAToAoS(_skeleton);
succeeded =
additive_builder(raw_animation, make_span(transforms), &raw_additive);
} else {
@@ -371,9 +371,12 @@ bool ImportAnimations(const Json::Value& _config, OzzImporter* _importer,
LoadSkeleton(skeleton_config["filename"].asCString()));
success &= skeleton.get() != nullptr;
if (!success)
return false;
// Loop though all existing animations, and export those who match
// configuration.
for (Json::ArrayIndex i = 0; success && i < animations_config.size(); ++i) {
for (Json::ArrayIndex i = 0; i < animations_config.size(); ++i) {
const Json::Value& animation_config = animations_config[i];
const char* clip_match = animation_config["clip"].asCString();
@@ -384,28 +387,45 @@ bool ImportAnimations(const Json::Value& _config, OzzImporter* _importer,
continue;
}
bool matched = false;
for (size_t j = 0; success && j < import_animation_names.size(); ++j) {
size_t num_not_clip_animation = 0, num_valid_animation = 0;
for (size_t j = 0; j < import_animation_names.size(); ++j) {
const char* animation_name = import_animation_names[j].c_str();
if (!strmatch(animation_name, clip_match)) {
continue;
}
++num_not_clip_animation;
const bool anisuccess = ProcessAnimation(*_importer, animation_name, *skeleton,
animation_config, _endianness);
if(anisuccess){
++num_valid_animation;
}
matched = true;
success = ProcessAnimation(*_importer, animation_name, *skeleton,
animation_config, _endianness);
size_t num_valid_track = 0;
const Json::Value& tracks_config = animation_config["tracks"];
for (Json::ArrayIndex t = 0; success && t < tracks_config.size(); ++t) {
success = ProcessTracks(*_importer, animation_name, *skeleton,
tracks_config[t], _endianness);
for (Json::ArrayIndex t = 0; t < tracks_config.size(); ++t) {
if (ProcessTracks(*_importer, animation_name, *skeleton,
tracks_config[t], _endianness)){
++num_valid_track;
}
}
if (num_valid_track != tracks_config.size()){
ozz::log::Log() << "One of track failed when import: \"" << animation_name
<< "\"" << std::endl;
success = false;
}
}
// Don't display any message if no animation is supposed to be imported.
if (!matched && *clip_match != 0) {
if (0 == num_not_clip_animation && *clip_match != 0) {
ozz::log::Log() << "No matching animation found for \"" << clip_match
<< "\"." << std::endl;
}
if (num_valid_animation != num_not_clip_animation){
ozz::log::Log() << "One of animation failed when import, animation index: \"" << i
<< "\"" << std::endl;
success = false;
}
}
return success;
@@ -28,6 +28,7 @@
#ifndef OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_ANIM_H_
#define OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_ANIM_H_
#include "ozz/animation/offline/tools/export.h"
#include "ozz/base/endianness.h"
#include "ozz/base/platform.h"
@@ -43,14 +44,15 @@ namespace animation {
namespace offline {
class OzzImporter;
bool ImportAnimations(const Json::Value& _config, OzzImporter* _importer,
OZZ_ANIMTOOLS_DLL bool ImportAnimations(const Json::Value& _config,
OzzImporter* _importer,
const ozz::Endianness _endianness);
// Additive reference enum to config string conversions.
struct AdditiveReferenceEnum {
enum Value { kAnimation, kSkeleton };
};
struct AdditiveReference
struct OZZ_ANIMTOOLS_DLL AdditiveReference
: JsonEnum<AdditiveReference, AdditiveReferenceEnum::Value> {
static EnumNames GetNames();
};
@@ -27,24 +27,21 @@
#include "animation/offline/tools/import2ozz_config.h"
#include <json/json.h>
#include <cstring>
#include <fstream>
#include <sstream>
#include "animation/offline/tools/import2ozz_anim.h"
#include "animation/offline/tools/import2ozz_track.h"
#include "ozz/animation/offline/tools/import2ozz.h"
#include "ozz/animation/offline/animation_optimizer.h"
#include "ozz/animation/offline/tools/import2ozz.h"
#include "ozz/animation/offline/track_optimizer.h"
#include "ozz/base/containers/string.h"
#include "ozz/base/log.h"
#include "ozz/options/options.h"
#include <json/json.h>
bool ValidateExclusiveConfigOption(const ozz::options::Option& _option,
int _argc);
OZZ_OPTIONS_DECLARE_STRING_FN(
@@ -365,14 +362,14 @@ bool SanitizeAnimation(Json::Value& _root, bool _all_options) {
MakeDefault(_root, "additive_reference", "animation",
"Select reference pose to use to build additive/delta animation. "
"Can be \"animation\" to use the 1st animation keyframe as "
"reference, or \"skeleton\" to use skeleton bind pose.");
"reference, or \"skeleton\" to use skeleton rest pose.");
if (!AdditiveReference::IsValidEnumName(
_root["additive_reference"].asCString())) {
ozz::log::Err() << "Invalid additive reference pose \""
<< _root["additive_reference"].asCString() << "\". \""
<< "Can be \"animation\" to use the 1st animation keyframe "
"as reference, or \"skeleton\" to use skeleton bind "
"as reference, or \"skeleton\" to use skeleton rest "
"pose."
<< std::endl;
return false;
@@ -28,6 +28,7 @@
#ifndef OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_CONFIG_H_
#define OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_CONFIG_H_
#include "ozz/animation/offline/tools/export.h"
#include "ozz/base/platform.h"
#include <json/json-forwards.h>
@@ -37,10 +38,10 @@ namespace animation {
namespace offline {
// Get the sanitized (all members are set, with the right types) configuration.
bool ProcessConfiguration(Json::Value* _config);
OZZ_ANIMTOOLS_DLL bool ProcessConfiguration(Json::Value* _config);
// Internal function used to compare enum names.
bool CompareName(const char* _a, const char* _b);
OZZ_ANIMTOOLS_DLL bool CompareName(const char* _a, const char* _b);
// Struct allowing inheriting class to provide enum names.
template <typename _Type, typename _Enum>
@@ -122,12 +122,13 @@ bool ImportSkeleton(const Json::Value& _config, OzzImporter* _importer,
// Setup node types import properties.
const Json::Value& types_config = import_config["types"];
OzzImporter::NodeType types = {0};
OzzImporter::NodeType types = {};
types.skeleton = types_config["skeleton"].asBool();
types.marker = types_config["marker"].asBool();
types.camera = types_config["camera"].asBool();
types.geometry = types_config["geometry"].asBool();
types.light = types_config["light"].asBool();
types.null = types_config["null"].asBool();
types.any = types_config["any"].asBool();
RawSkeleton raw_skeleton;
@@ -28,6 +28,7 @@
#ifndef OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_SKEL_H_
#define OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_SKEL_H_
#include "ozz/animation/offline/tools/export.h"
#include "ozz/base/endianness.h"
#include "ozz/base/platform.h"
@@ -41,8 +42,9 @@ namespace offline {
class OzzImporter;
bool ImportSkeleton(const Json::Value& _config, OzzImporter* _importer,
const ozz::Endianness _endianness);
OZZ_ANIMTOOLS_DLL bool ImportSkeleton(const Json::Value& _config,
OzzImporter* _importer,
const ozz::Endianness _endianness);
} // namespace offline
} // namespace animation
@@ -28,12 +28,12 @@
#ifndef OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_TRACK_H_
#define OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_TRACK_H_
#include "animation/offline/tools/import2ozz_config.h"
#include "ozz/animation/offline/tools/export.h"
#include "ozz/animation/offline/tools/import2ozz.h"
#include "ozz/base/endianness.h"
#include "ozz/base/platform.h"
#include "animation/offline/tools/import2ozz_config.h"
#include "ozz/animation/offline/tools/import2ozz.h"
namespace Json {
class Value;
}
@@ -44,12 +44,14 @@ class Skeleton;
namespace offline {
class OzzImporter;
bool ProcessTracks(OzzImporter& _importer, const char* _animation_name,
const Skeleton& _skeleton, const Json::Value& _config,
const ozz::Endianness _endianness);
OZZ_ANIMTOOLS_DLL bool ProcessTracks(OzzImporter& _importer,
const char* _animation_name,
const Skeleton& _skeleton,
const Json::Value& _config,
const ozz::Endianness _endianness);
// Property type enum to config string conversions.
struct PropertyTypeConfig
struct OZZ_ANIMTOOLS_DLL PropertyTypeConfig
: JsonEnum<PropertyTypeConfig, OzzImporter::NodeProperty::Type> {
static EnumNames GetNames();
};
@@ -29,7 +29,7 @@
"filename" : "*.ozz", // Specifies animation output filename. Use a '*' character to specify part(s) of the filename that should be replaced by the clip name.
"raw" : false, // Outputs raw animation.
"additive" : false, // Creates a delta animation that can be used for additive blending.
"additive_reference" : "animation", // Select reference pose to use to build additive/delta animation. Can be "animation" to use the 1st animation keyframe as reference, or "skeleton" to use skeleton bind pose.
"additive_reference" : "animation", // Select reference pose to use to build additive/delta animation. Can be "animation" to use the 1st animation keyframe as reference, or "skeleton" to use skeleton rest pose.
"sampling_rate" : 0, // Selects animation sampling rate in hertz. Set a value <= 0 to use imported scene default frame rate.
"optimize" : true, // Activates keyframes reduction optimization.
"optimization_settings" :
@@ -1,4 +1,6 @@
add_library(ozz_animation STATIC
add_library(ozz_animation
${PROJECT_SOURCE_DIR}/include/ozz/animation/runtime/export.h
${PROJECT_SOURCE_DIR}/include/ozz/animation/runtime/animation.h
animation.cc
animation_keyframe.h
@@ -25,7 +27,11 @@ add_library(ozz_animation STATIC
${PROJECT_SOURCE_DIR}/include/ozz/animation/runtime/track_triggering_job.h
${PROJECT_SOURCE_DIR}/include/ozz/animation/runtime/track_triggering_job_trait.h
track_triggering_job.cc)
target_compile_definitions(ozz_animation PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_ANIMATION_LIB>)
target_link_libraries(ozz_animation
PUBLIC
ozz_base)
set_target_properties(ozz_animation
+14 -1
View File
@@ -46,6 +46,19 @@ namespace animation {
Animation::Animation() : duration_(0.f), num_tracks_(0), name_(nullptr) {}
Animation::Animation(Animation&& _other) { *this = std::move(_other); }
Animation& Animation::operator=(Animation&& _other) {
std::swap(duration_, _other.duration_);
std::swap(num_tracks_, _other.num_tracks_);
std::swap(name_, _other.name_);
std::swap(translations_, _other.translations_);
std::swap(rotations_, _other.rotations_);
std::swap(scales_, _other.scales_);
return *this;
}
Animation::~Animation() { Deallocate(); }
void Animation::Allocate(size_t _name_len, size_t _translation_count,
@@ -65,7 +78,7 @@ void Animation::Allocate(size_t _name_len, size_t _translation_count,
_translation_count * sizeof(Float3Key) +
_rotation_count * sizeof(QuaternionKey) +
_scale_count * sizeof(Float3Key);
span<char> buffer = {static_cast<char*>(memory::default_allocator()->Allocate(
span<byte> buffer = {static_cast<byte*>(memory::default_allocator()->Allocate(
buffer_size, alignof(Float3Key))),
buffer_size};
@@ -28,7 +28,9 @@
#ifndef OZZ_ANIMATION_RUNTIME_ANIMATION_KEYFRAME_H_
#define OZZ_ANIMATION_RUNTIME_ANIMATION_KEYFRAME_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h"
#ifndef OZZ_INCLUDE_PRIVATE_HEADER
#error "This header is private, it cannot be included from public headers."
#endif // OZZ_INCLUDE_PRIVATE_HEADER
@@ -46,7 +48,7 @@ namespace animation {
// Defines the float3 key frame type, used for translations and scales.
// Translation values are stored as half precision floats with 16 bits per
// component.
struct Float3Key {
struct OZZ_ANIMATION_DLL Float3Key {
float ratio;
uint16_t track;
uint16_t value[3];
@@ -67,7 +69,7 @@ struct Float3Key {
// Quantization could be reduced to 11-11-10 bits as often used for animation
// key frames, but in this case RotationKey structure would induce 16 bits of
// padding.
struct QuaternionKey {
struct OZZ_ANIMATION_DLL QuaternionKey {
float ratio;
uint16_t track : 13; // The track this key frame belongs to.
uint16_t largest : 2; // The largest component of the quaternion.
+15 -15
View File
@@ -69,12 +69,12 @@ bool BlendingJob::Validate() const {
// Test for nullptr begin pointers.
// Blending layers are mandatory, additive aren't.
valid &= !bind_pose.empty();
valid &= !rest_pose.empty();
valid &= !output.empty();
// The bind pose size defines the ranges of transforms to blend, so all
// The rest pose size defines the ranges of transforms to blend, so all
// other buffers should be bigger.
const size_t min_range = bind_pose.size();
const size_t min_range = rest_pose.size();
valid &= output.size() >= min_range;
// Validates layers.
@@ -160,7 +160,7 @@ namespace {
struct ProcessArgs {
ProcessArgs(const BlendingJob& _job)
: job(_job),
num_soa_joints(_job.bind_pose.size()),
num_soa_joints(_job.rest_pose.size()),
num_passes(0),
num_partial_passes(0),
accumulated_weight(0.f) {
@@ -182,7 +182,7 @@ struct ProcessArgs {
// The job to process.
const BlendingJob& job;
// The number of transforms to process as defined by the size of the bind
// The number of transforms to process as defined by the size of the rest
// pose.
size_t num_soa_joints;
@@ -271,24 +271,24 @@ void BlendLayers(ProcessArgs* _args) {
}
}
// Blends bind pose to the output if accumulated weight is less than the
// Blends rest pose to the output if accumulated weight is less than the
// threshold value.
void BlendBindPose(ProcessArgs* _args) {
void BlendRestPose(ProcessArgs* _args) {
assert(_args);
// Asserts buffer sizes, which must never fail as it has been validated.
assert(_args->job.bind_pose.size() >= _args->num_soa_joints);
assert(_args->job.rest_pose.size() >= _args->num_soa_joints);
if (_args->num_partial_passes == 0) {
// No partial blending pass detected, threshold can be tested globally.
const float bp_weight = _args->job.threshold - _args->accumulated_weight;
if (bp_weight > 0.f) { // The bind-pose is needed if it has a weight.
if (bp_weight > 0.f) { // The rest-pose is needed if it has a weight.
if (_args->num_passes == 0) {
// Strictly copying bind-pose.
// Strictly copying rest-pose.
_args->accumulated_weight = 1.f;
for (size_t i = 0; i < _args->num_soa_joints; ++i) {
_args->job.output[i] = _args->job.bind_pose[i];
_args->job.output[i] = _args->job.rest_pose[i];
}
} else {
// Updates global accumulated weight, but not per-joint weight any more
@@ -299,7 +299,7 @@ void BlendBindPose(ProcessArgs* _args) {
math::simd_float4::Load1(bp_weight);
for (size_t i = 0; i < _args->num_soa_joints; ++i) {
const math::SoaTransform& src = _args->job.bind_pose[i];
const math::SoaTransform& src = _args->job.rest_pose[i];
math::SoaTransform* dest = _args->job.output.begin() + i;
OZZ_BLEND_N_PASS(src, simd_bp_weight, dest);
}
@@ -315,7 +315,7 @@ void BlendBindPose(ProcessArgs* _args) {
assert(_args->num_passes != 0);
for (size_t i = 0; i < _args->num_soa_joints; ++i) {
const math::SoaTransform& src = _args->job.bind_pose[i];
const math::SoaTransform& src = _args->job.rest_pose[i];
math::SoaTransform* dest = _args->job.output.begin() + i;
const math::SimdFloat4 bp_weight =
math::Max0(threshold - _args->accumulated_weights[i]);
@@ -442,8 +442,8 @@ bool BlendingJob::Run() const {
// Blends all layers to the job output buffers.
BlendLayers(&process_args);
// Applies bind pose.
BlendBindPose(&process_args);
// Applies rest pose.
BlendRestPose(&process_args);
// Normalizes output.
Normalize(&process_args);
+40 -36
View File
@@ -60,22 +60,21 @@ bool SamplingJob::Validate() const {
bool valid = true;
// Test for nullptr pointers.
if (!animation || !cache) {
if (!animation || !context) {
return false;
}
valid &= !output.empty();
const int num_soa_tracks = animation->num_soa_tracks();
valid &= output.size() >= static_cast<size_t>(num_soa_tracks);
// Tests cache size.
valid &= cache->max_soa_tracks() >= num_soa_tracks;
// Tests context size.
valid &= context->max_soa_tracks() >= num_soa_tracks;
return valid;
}
namespace {
// Loops through the sorted key frames and update cache structure.
// Loops through the sorted key frames and update context structure.
template <typename _Key>
void UpdateCacheCursor(float _ratio, int _num_soa_tracks,
const ozz::span<const _Key>& _keys, int* _cursor,
@@ -118,16 +117,16 @@ void UpdateCacheCursor(float _ratio, int _num_soa_tracks,
}
// Search for the keys that matches _ratio.
// Iterates while the cache is not updated with left and right keys required
// Iterates while the context is not updated with left and right keys required
// for interpolation at time ratio _ratio, for all tracks. Thanks to the
// keyframe sorting, the loop can end as soon as it finds a key greater that
// _ratio. It will mean that all the keys lower than _ratio have been
// processed, meaning all cache entries are up to date.
// processed, meaning all context entries are up to date.
while (cursor < _keys.end() &&
_keys[_cache[cursor->track * 2 + 1]].ratio <= _ratio) {
// Flag this soa entry as outdated.
_outdated[cursor->track / 32] |= (1 << ((cursor->track & 0x1f) / 4));
// Updates cache.
// Updates context.
const int base = cursor->track * 2;
_cache[base] = _cache[base + 1];
_cache[base + 1] = static_cast<int>(cursor - _keys.begin());
@@ -293,7 +292,7 @@ void Interpolates(float _anim_ratio, int _num_soa_tracks,
}
} // namespace
SamplingJob::SamplingJob() : ratio(0.f), animation(nullptr), cache(nullptr) {}
SamplingJob::SamplingJob() : ratio(0.f), animation(nullptr), context(nullptr) {}
bool SamplingJob::Run() const {
if (!Validate()) {
@@ -308,60 +307,64 @@ bool SamplingJob::Run() const {
// Clamps ratio in range [0,duration].
const float anim_ratio = math::Clamp(0.f, ratio, 1.f);
// Step the cache to this potentially new animation and ratio.
assert(cache->max_soa_tracks() >= num_soa_tracks);
cache->Step(*animation, anim_ratio);
// Step the context to this potentially new animation and ratio.
assert(context->max_soa_tracks() >= num_soa_tracks);
context->Step(*animation, anim_ratio);
// Fetch key frames from the animation to the cache a r = anim_ratio.
// Fetch key frames from the animation to the context at r = anim_ratio.
// Then updates outdated soa hot values.
UpdateCacheCursor(anim_ratio, num_soa_tracks, animation->translations(),
&cache->translation_cursor_, cache->translation_keys_,
cache->outdated_translations_);
&context->translation_cursor_, context->translation_keys_,
context->outdated_translations_);
UpdateInterpKeyframes(num_soa_tracks, animation->translations(),
cache->translation_keys_, cache->outdated_translations_,
cache->soa_translations_, &DecompressFloat3);
context->translation_keys_,
context->outdated_translations_,
context->soa_translations_, &DecompressFloat3);
UpdateCacheCursor(anim_ratio, num_soa_tracks, animation->rotations(),
&cache->rotation_cursor_, cache->rotation_keys_,
cache->outdated_rotations_);
&context->rotation_cursor_, context->rotation_keys_,
context->outdated_rotations_);
UpdateInterpKeyframes(num_soa_tracks, animation->rotations(),
cache->rotation_keys_, cache->outdated_rotations_,
cache->soa_rotations_, &DecompressQuaternion);
context->rotation_keys_, context->outdated_rotations_,
context->soa_rotations_, &DecompressQuaternion);
UpdateCacheCursor(anim_ratio, num_soa_tracks, animation->scales(),
&cache->scale_cursor_, cache->scale_keys_,
cache->outdated_scales_);
UpdateInterpKeyframes(num_soa_tracks, animation->scales(), cache->scale_keys_,
cache->outdated_scales_, cache->soa_scales_,
&DecompressFloat3);
&context->scale_cursor_, context->scale_keys_,
context->outdated_scales_);
UpdateInterpKeyframes(num_soa_tracks, animation->scales(),
context->scale_keys_, context->outdated_scales_,
context->soa_scales_, &DecompressFloat3);
// only interp as much as we have output for.
const int num_soa_interp_tracks = math::Min(static_cast< int >(output.size()), num_soa_tracks);
// Interpolates soa hot data.
Interpolates(anim_ratio, num_soa_tracks, cache->soa_translations_,
cache->soa_rotations_, cache->soa_scales_, output.begin());
Interpolates(anim_ratio, num_soa_interp_tracks, context->soa_translations_,
context->soa_rotations_, context->soa_scales_, output.begin());
return true;
}
SamplingCache::SamplingCache()
SamplingJob::Context::Context()
: max_soa_tracks_(0),
soa_translations_(
nullptr) { // soa_translations_ is the allocation pointer.
Invalidate();
}
SamplingCache::SamplingCache(int _max_tracks)
SamplingJob::Context::Context(int _max_tracks)
: max_soa_tracks_(0),
soa_translations_(
nullptr) { // soa_translations_ is the allocation pointer.
Resize(_max_tracks);
}
SamplingCache::~SamplingCache() {
SamplingJob::Context::~Context() {
// Deallocates everything at once.
memory::default_allocator()->Deallocate(soa_translations_);
}
void SamplingCache::Resize(int _max_tracks) {
void SamplingJob::Context::Resize(int _max_tracks) {
using internal::InterpSoaFloat3;
using internal::InterpSoaQuaternion;
@@ -372,7 +375,7 @@ void SamplingCache::Resize(int _max_tracks) {
// Updates maximum supported soa tracks.
max_soa_tracks_ = (_max_tracks + 3) / 4;
// Allocate all cache data at once in a single allocation.
// Allocate all context data at once in a single allocation.
// Alignment is guaranteed because memory is dispatch from the highest
// alignment requirement (Soa data: SimdFloat4) to the lowest (outdated
// flag: unsigned char).
@@ -430,8 +433,9 @@ void SamplingCache::Resize(int _max_tracks) {
assert(alloc_cursor == alloc_begin + size);
}
void SamplingCache::Step(const Animation& _animation, float _ratio) {
// The cache is invalidated if animation has changed or if it is being rewind.
void SamplingJob::Context::Step(const Animation& _animation, float _ratio) {
// The context is invalidated if animation has changed or if it is being
// rewind.
if (animation_ != &_animation || _ratio < ratio_) {
animation_ = &_animation;
translation_cursor_ = 0;
@@ -441,7 +445,7 @@ void SamplingCache::Step(const Animation& _animation, float _ratio) {
ratio_ = _ratio;
}
void SamplingCache::Invalidate() {
void SamplingJob::Context::Invalidate() {
animation_ = nullptr;
ratio_ = 0.f;
translation_cursor_ = 0;
+23 -12
View File
@@ -41,6 +41,16 @@ namespace animation {
Skeleton::Skeleton() {}
Skeleton::Skeleton(Skeleton&& _other) { *this = std::move(_other); }
Skeleton& Skeleton::operator=(Skeleton&& _other) {
std::swap(joint_rest_poses_, _other.joint_rest_poses_);
std::swap(joint_parents_, _other.joint_parents_);
std::swap(joint_names_, _other.joint_names_);
return *this;
}
Skeleton::~Skeleton() { Deallocate(); }
char* Skeleton::Allocate(size_t _chars_size, size_t _num_joints) {
@@ -51,7 +61,7 @@ char* Skeleton::Allocate(size_t _chars_size, size_t _num_joints) {
alignof(int16_t) >= alignof(char),
"Must serve larger alignment values first)");
assert(joint_bind_poses_.size() == 0 && joint_names_.size() == 0 &&
assert(joint_rest_poses_.size() == 0 && joint_names_.size() == 0 &&
joint_parents_.size() == 0);
// Early out if no joint.
@@ -59,23 +69,23 @@ char* Skeleton::Allocate(size_t _chars_size, size_t _num_joints) {
return nullptr;
}
// Bind poses have SoA format
// Rest poses have SoA format
const size_t num_soa_joints = (_num_joints + 3) / 4;
const size_t joint_bind_poses_size =
const size_t joint_rest_poses_size =
num_soa_joints * sizeof(math::SoaTransform);
const size_t names_size = _num_joints * sizeof(char*);
const size_t joint_parents_size = _num_joints * sizeof(int16_t);
const size_t buffer_size =
names_size + _chars_size + joint_parents_size + joint_bind_poses_size;
names_size + _chars_size + joint_parents_size + joint_rest_poses_size;
// Allocates whole buffer.
span<char> buffer = {static_cast<char*>(memory::default_allocator()->Allocate(
span<byte> buffer = {static_cast<byte*>(memory::default_allocator()->Allocate(
buffer_size, alignof(math::SoaTransform))),
buffer_size};
// Serves larger alignment values first.
// Bind pose first, biggest alignment.
joint_bind_poses_ = fill_span<math::SoaTransform>(buffer, num_soa_joints);
// Rest pose first, biggest alignment.
joint_rest_poses_ = fill_span<math::SoaTransform>(buffer, num_soa_joints);
// Then names array, second biggest alignment.
joint_names_ = fill_span<char*>(buffer, _num_joints);
@@ -86,12 +96,13 @@ char* Skeleton::Allocate(size_t _chars_size, size_t _num_joints) {
// Remaning buffer will be used to store joint names.
assert(buffer.size_bytes() == _chars_size &&
"Whole buffer should be consumned");
return buffer.data();
return reinterpret_cast<char*>(buffer.data());
}
void Skeleton::Deallocate() {
memory::default_allocator()->Deallocate(as_writable_bytes(joint_bind_poses_).data());
joint_bind_poses_ = {};
memory::default_allocator()->Deallocate(
as_writable_bytes(joint_rest_poses_).data());
joint_rest_poses_ = {};
joint_names_ = {};
joint_parents_ = {};
}
@@ -114,7 +125,7 @@ void Skeleton::Save(ozz::io::OArchive& _archive) const {
_archive << static_cast<int32_t>(chars_count);
_archive << ozz::io::MakeArray(joint_names_[0], chars_count);
_archive << ozz::io::MakeArray(joint_parents_);
_archive << ozz::io::MakeArray(joint_bind_poses_);
_archive << ozz::io::MakeArray(joint_rest_poses_);
}
void Skeleton::Load(ozz::io::IArchive& _archive, uint32_t _version) {
@@ -155,7 +166,7 @@ void Skeleton::Load(ozz::io::IArchive& _archive, uint32_t _version) {
joint_names_[num_joints - 1] = cursor;
_archive >> ozz::io::MakeArray(joint_parents_);
_archive >> ozz::io::MakeArray(joint_bind_poses_);
_archive >> ozz::io::MakeArray(joint_rest_poses_);
}
} // namespace animation
} // namespace ozz
@@ -27,21 +27,33 @@
#include "ozz/animation/runtime/skeleton_utils.h"
#include "ozz/base/maths/soa_transform.h"
#include <assert.h>
#include <cstring>
#include "ozz/base/maths/soa_transform.h"
namespace ozz {
namespace animation {
// Unpacks skeleton bind pose stored in soa format by the skeleton.
ozz::math::Transform GetJointLocalBindPose(const Skeleton& _skeleton,
int FindJoint(const Skeleton& _skeleton, const char* _name) {
const auto& names = _skeleton.joint_names();
for (size_t i = 0; i < names.size(); ++i) {
if (std::strcmp(names[i], _name) == 0) {
return static_cast<int>(i);
}
}
return -1;
}
// Unpacks skeleton rest pose stored in soa format by the skeleton.
ozz::math::Transform GetJointLocalRestPose(const Skeleton& _skeleton,
int _joint) {
assert(_joint >= 0 && _joint < _skeleton.num_joints() &&
"Joint index out of range.");
const ozz::math::SoaTransform& soa_transform =
_skeleton.joint_bind_poses()[_joint / 4];
_skeleton.joint_rest_poses()[_joint / 4];
// Transpose SoA data to AoS.
ozz::math::SimdFloat4 translations[4];
@@ -52,13 +64,13 @@ ozz::math::Transform GetJointLocalBindPose(const Skeleton& _skeleton,
ozz::math::Transpose3x4(&soa_transform.scale.x, scales);
// Stores to the Transform object.
math::Transform bind_pose;
math::Transform rest_pose;
const int offset = _joint % 4;
ozz::math::Store3PtrU(translations[offset], &bind_pose.translation.x);
ozz::math::StorePtrU(rotations[offset], &bind_pose.rotation.x);
ozz::math::Store3PtrU(scales[offset], &bind_pose.scale.x);
ozz::math::Store3PtrU(translations[offset], &rest_pose.translation.x);
ozz::math::StorePtrU(rotations[offset], &rest_pose.rotation.x);
ozz::math::Store3PtrU(scales[offset], &rest_pose.scale.x);
return bind_pose;
return rest_pose;
}
} // namespace animation
} // namespace ozz
+20 -6
View File
@@ -43,6 +43,20 @@ namespace internal {
template <typename _ValueType>
Track<_ValueType>::Track() : name_(nullptr) {}
template <typename _ValueType>
Track<_ValueType>::Track(Track<_ValueType>&& _other) {
*this = std::move(_other);
}
template <typename _ValueType>
Track<_ValueType>& Track<_ValueType>::operator=(Track<_ValueType>&& _other) {
std::swap(ratios_, _other.ratios_);
std::swap(values_, _other.values_);
std::swap(steps_, _other.steps_);
std::swap(name_, _other.name_);
return *this;
}
template <typename _ValueType>
Track<_ValueType>::~Track() {
Deallocate();
@@ -63,7 +77,7 @@ void Track<_ValueType>::Allocate(size_t _keys_count, size_t _name_len) {
_keys_count * sizeof(float) + // ratios
(_keys_count + 7) * sizeof(uint8_t) / 8 + // steps
(_name_len > 0 ? _name_len + 1 : 0);
span<char> buffer = {static_cast<char*>(memory::default_allocator()->Allocate(
span<byte> buffer = {static_cast<byte*>(memory::default_allocator()->Allocate(
buffer_size, alignof(_ValueType))),
buffer_size};
@@ -142,11 +156,11 @@ void Track<_ValueType>::Load(ozz::io::IArchive& _archive, uint32_t _version) {
}
// Explicitly instantiate supported tracks.
template class Track<float>;
template class Track<math::Float2>;
template class Track<math::Float3>;
template class Track<math::Float4>;
template class Track<math::Quaternion>;
template class OZZ_ANIMATION_DLL Track<float>;
template class OZZ_ANIMATION_DLL Track<math::Float2>;
template class OZZ_ANIMATION_DLL Track<math::Float3>;
template class OZZ_ANIMATION_DLL Track<math::Float4>;
template class OZZ_ANIMATION_DLL Track<math::Quaternion>;
} // namespace internal
} // namespace animation
+11 -1
View File
@@ -1,4 +1,6 @@
add_library(ozz_base STATIC
add_library(ozz_base
${PROJECT_SOURCE_DIR}/include/ozz/base/export.h
${PROJECT_SOURCE_DIR}/include/ozz/base/endianness.h
${PROJECT_SOURCE_DIR}/include/ozz/base/gtest_helper.h
${PROJECT_SOURCE_DIR}/include/ozz/base/memory/allocator.h
@@ -54,11 +56,19 @@ add_library(ozz_base STATIC
maths/soa_math_archive.cc
${PROJECT_SOURCE_DIR}/include/ozz/base/maths/simd_math_archive.h
maths/simd_math_archive.cc)
target_compile_definitions(ozz_base
PUBLIC $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_USE_DYNAMIC_LINKING>
PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_BASE_LIB>)
target_compile_options(ozz_base PUBLIC $<$<CXX_COMPILER_ID:MSVC>:/wd4251>)
target_include_directories(ozz_base PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>)
set_target_properties(ozz_base PROPERTIES FOLDER "ozz")
install(TARGETS ozz_base DESTINATION lib)
fuse_target("ozz_base")
+5 -3
View File
@@ -182,7 +182,7 @@ int MemoryStream::Seek(int _offset, Origin _origin) {
// Exit if seeking before file begin or beyond max file size.
if (origin < -_offset ||
(_offset > 0 && origin > static_cast<int>(kMaxSize - _offset))) {
(_offset > 0 && origin > static_cast<int>(kMaxSize) - _offset)) {
return -1;
}
@@ -204,9 +204,11 @@ bool MemoryStream::Resize(size_t _size) {
(MemoryStream::kBufferSizeIncrement & (kBufferSizeIncrement - 1)) == 0,
"kBufferSizeIncrement must be a power of 2");
const size_t new_size = ozz::Align(_size, kBufferSizeIncrement);
char* new_buffer = reinterpret_cast<char*>(
byte* new_buffer = reinterpret_cast<byte*>(
ozz::memory::default_allocator()->Allocate(new_size, 16));
std::memcpy(new_buffer, buffer_, alloc_size_);
if (buffer_ != nullptr) {
std::memcpy(new_buffer, buffer_, alloc_size_);
}
ozz::memory::default_allocator()->Deallocate(buffer_);
buffer_ = new_buffer;
alloc_size_ = new_size;
+7 -6
View File
@@ -1,10 +1,11 @@
add_library(ozz_geometry STATIC
add_library(ozz_geometry
${PROJECT_SOURCE_DIR}/include/ozz/geometry/runtime/export.h
${PROJECT_SOURCE_DIR}/include/ozz/geometry/runtime/skinning_job.h
skinning_job.cc)
target_link_libraries(ozz_geometry
ozz_base)
set_target_properties(ozz_geometry
PROPERTIES FOLDER "ozz")
skinning_job.cc)
target_compile_definitions(ozz_geometry PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_GEOMETRY_LIB>)
target_link_libraries(ozz_geometry ozz_base)
set_target_properties(ozz_geometry PROPERTIES FOLDER "ozz")
install(TARGETS ozz_geometry DESTINATION lib)
+7 -5
View File
@@ -1,9 +1,11 @@
add_library(ozz_options STATIC
../../include/ozz/options/options.h
add_library(ozz_options
${PROJECT_SOURCE_DIR}/include/ozz/options/export.h
${PROJECT_SOURCE_DIR}/include/ozz/options/options.h
options.cc)
target_include_directories(ozz_options PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>)
target_link_libraries(ozz_options ozz_base)
target_compile_definitions(ozz_options PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:OZZ_BUILD_OPTIONS_LIB>)
set_target_properties(ozz_options PROPERTIES FOLDER "ozz")
install(TARGETS ozz_options DESTINATION lib)
+10 -10
View File
@@ -107,10 +107,10 @@ Registrer<_Option>::~Registrer() {
}
// Explicit instantiation of all supported types of Registrer.
template class Registrer<TypedOption<bool>>;
template class Registrer<TypedOption<int>>;
template class Registrer<TypedOption<float>>;
template class Registrer<TypedOption<const char*>>;
template class OZZ_OPTIONS_DLL Registrer<TypedOption<bool>>;
template class OZZ_OPTIONS_DLL Registrer<TypedOption<int>>;
template class OZZ_OPTIONS_DLL Registrer<TypedOption<float>>;
template class OZZ_OPTIONS_DLL Registrer<TypedOption<const char*>>;
} // namespace internal
// Construct the parser if no option is registered.
@@ -130,10 +130,10 @@ ParseResult ParseCommandLine(int _argc, const char* const* _argv,
// A nullptr parser means that no option is registered and that ParseCommandLine
// has not been called.
std::string ParsedExecutablePath() {
ozz::string ParsedExecutablePath() {
Parser* parser = internal::g_global_registrer.parser();
if (!parser) {
return std::string();
return {};
}
return parser->executable_path();
}
@@ -368,10 +368,10 @@ bool TypedOption<_Type>::ParseImpl(const char* _argv) {
}
template <typename _Type>
std::string TypedOption<_Type>::FormatDefault() const {
ozz::string TypedOption<_Type>::FormatDefault() const {
std::stringstream str;
str << "\"" << std::boolalpha << default_ << "\"";
return str.str();
return str.str().c_str();
}
template <typename _Type>
@@ -648,8 +648,8 @@ const char* Parser::usage() const { return usage_; }
const char* Parser::version() const { return version_; }
std::string Parser::executable_path() const {
return std::string(executable_path_begin_, executable_path_end_);
ozz::string Parser::executable_path() const {
return ozz::string(executable_path_begin_, executable_path_end_);
}
const char* Parser::executable_name() const { return executable_name_; }