198 lines
7.7 KiB
C++
198 lines
7.7 KiB
C++
|
|
//----------------------------------------------------------------------------//
|
||
|
|
// //
|
||
|
|
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||
|
|
// and distributed under the MIT License (MIT). //
|
||
|
|
// //
|
||
|
|
// Copyright (c) Guillaume Blanc //
|
||
|
|
// //
|
||
|
|
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||
|
|
// copy of this software and associated documentation files (the "Software"), //
|
||
|
|
// to deal in the Software without restriction, including without limitation //
|
||
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||
|
|
// and/or sell copies of the Software, and to permit persons to whom the //
|
||
|
|
// Software is furnished to do so, subject to the following conditions: //
|
||
|
|
// //
|
||
|
|
// The above copyright notice and this permission notice shall be included in //
|
||
|
|
// all copies or substantial portions of the Software. //
|
||
|
|
// //
|
||
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||
|
|
// DEALINGS IN THE SOFTWARE. //
|
||
|
|
// //
|
||
|
|
//----------------------------------------------------------------------------//
|
||
|
|
|
||
|
|
#include "animation/offline/tools/import2ozz_skel.h"
|
||
|
|
|
||
|
|
#include <cstdlib>
|
||
|
|
#include <cstring>
|
||
|
|
#include <iomanip>
|
||
|
|
|
||
|
|
#include "animation/offline/tools/import2ozz_config.h"
|
||
|
|
|
||
|
|
#include "ozz/animation/offline/tools/import2ozz.h"
|
||
|
|
|
||
|
|
#include "ozz/animation/offline/raw_skeleton.h"
|
||
|
|
#include "ozz/animation/offline/skeleton_builder.h"
|
||
|
|
|
||
|
|
#include "ozz/animation/runtime/skeleton.h"
|
||
|
|
|
||
|
|
#include "ozz/base/containers/map.h"
|
||
|
|
#include "ozz/base/containers/set.h"
|
||
|
|
|
||
|
|
#include "ozz/base/io/archive.h"
|
||
|
|
#include "ozz/base/io/stream.h"
|
||
|
|
|
||
|
|
#include "ozz/base/memory/unique_ptr.h"
|
||
|
|
|
||
|
|
#include "ozz/base/log.h"
|
||
|
|
|
||
|
|
#include <json/json.h>
|
||
|
|
|
||
|
|
namespace ozz {
|
||
|
|
namespace animation {
|
||
|
|
namespace offline {
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
// Uses a set to detect names uniqueness.
|
||
|
|
typedef ozz::set<const char*, ozz::str_less> Names;
|
||
|
|
|
||
|
|
bool ValidateJointNamesUniquenessRecurse(
|
||
|
|
const RawSkeleton::Joint::Children& _joints, Names* _names) {
|
||
|
|
for (size_t i = 0; i < _joints.size(); ++i) {
|
||
|
|
const RawSkeleton::Joint& joint = _joints[i];
|
||
|
|
const char* name = joint.name.c_str();
|
||
|
|
if (!_names->insert(name).second) {
|
||
|
|
ozz::log::Err()
|
||
|
|
<< "Skeleton contains at least one non-unique joint name \"" << name
|
||
|
|
<< "\", which is not supported." << std::endl;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!ValidateJointNamesUniquenessRecurse(_joints[i].children, _names)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ValidateJointNamesUniqueness(const RawSkeleton& _skeleton) {
|
||
|
|
Names joint_names;
|
||
|
|
return ValidateJointNamesUniquenessRecurse(_skeleton.roots, &joint_names);
|
||
|
|
}
|
||
|
|
|
||
|
|
void LogHierarchy(const RawSkeleton::Joint::Children& _children,
|
||
|
|
int _depth = 0) {
|
||
|
|
const std::streamsize pres = ozz::log::LogV().stream().precision();
|
||
|
|
for (size_t i = 0; i < _children.size(); ++i) {
|
||
|
|
const RawSkeleton::Joint& joint = _children[i];
|
||
|
|
ozz::log::LogV() << std::setw(_depth) << std::setfill('.') << "";
|
||
|
|
ozz::log::LogV() << joint.name.c_str() << std::setprecision(4)
|
||
|
|
<< " t: " << joint.transform.translation.x << ", "
|
||
|
|
<< joint.transform.translation.y << ", "
|
||
|
|
<< joint.transform.translation.z
|
||
|
|
<< " r: " << joint.transform.rotation.x << ", "
|
||
|
|
<< joint.transform.rotation.y << ", "
|
||
|
|
<< joint.transform.rotation.z << ", "
|
||
|
|
<< joint.transform.rotation.w
|
||
|
|
<< " s: " << joint.transform.scale.x << ", "
|
||
|
|
<< joint.transform.scale.y << ", "
|
||
|
|
<< joint.transform.scale.z << std::endl;
|
||
|
|
|
||
|
|
// Recurse
|
||
|
|
LogHierarchy(joint.children, _depth + 1);
|
||
|
|
}
|
||
|
|
ozz::log::LogV() << std::setprecision(static_cast<int>(pres));
|
||
|
|
}
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
bool ImportSkeleton(const Json::Value& _config, OzzImporter* _importer,
|
||
|
|
const ozz::Endianness _endianness) {
|
||
|
|
const Json::Value& skeleton_config = _config["skeleton"];
|
||
|
|
const Json::Value& import_config = skeleton_config["import"];
|
||
|
|
|
||
|
|
// First check that we're actually expecting to import a skeleton.
|
||
|
|
if (!import_config["enable"].asBool()) {
|
||
|
|
ozz::log::Log() << "Skeleton build disabled, import will be skipped."
|
||
|
|
<< std::endl;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Setup node types import properties.
|
||
|
|
const Json::Value& types_config = import_config["types"];
|
||
|
|
OzzImporter::NodeType types = {0};
|
||
|
|
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.any = types_config["any"].asBool();
|
||
|
|
|
||
|
|
RawSkeleton raw_skeleton;
|
||
|
|
if (!_importer->Import(&raw_skeleton, types)) {
|
||
|
|
ozz::log::Err() << "Failed to import skeleton." << std::endl;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Log skeleton hierarchy
|
||
|
|
if (ozz::log::GetLevel() == ozz::log::kVerbose) {
|
||
|
|
LogHierarchy(raw_skeleton.roots);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Non unique joint names are not supported.
|
||
|
|
if (!(ValidateJointNamesUniqueness(raw_skeleton))) {
|
||
|
|
// Log Err is done by the validation function.
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Needs to be done before opening the output file, so that if it fails then
|
||
|
|
// there's no invalid file outputted.
|
||
|
|
unique_ptr<Skeleton> skeleton;
|
||
|
|
if (!import_config["raw"].asBool()) {
|
||
|
|
// Builds runtime skeleton.
|
||
|
|
ozz::log::Log() << "Builds runtime skeleton." << std::endl;
|
||
|
|
SkeletonBuilder builder;
|
||
|
|
skeleton = builder(raw_skeleton);
|
||
|
|
if (!skeleton) {
|
||
|
|
ozz::log::Err() << "Failed to build runtime skeleton." << std::endl;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Prepares output stream. File is a RAII so it will close automatically at
|
||
|
|
// the end of this scope.
|
||
|
|
// Once the file is opened, nothing should fail as it would leave an invalid
|
||
|
|
// file on the disk.
|
||
|
|
{
|
||
|
|
const char* filename = skeleton_config["filename"].asCString();
|
||
|
|
ozz::log::Log() << "Opens output file: " << filename << std::endl;
|
||
|
|
ozz::io::File file(filename, "wb");
|
||
|
|
if (!file.opened()) {
|
||
|
|
ozz::log::Err() << "Failed to open output file: \"" << filename << "\"."
|
||
|
|
<< std::endl;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initializes output archive.
|
||
|
|
ozz::io::OArchive archive(&file, _endianness);
|
||
|
|
|
||
|
|
// Fills output archive with the skeleton.
|
||
|
|
if (import_config["raw"].asBool()) {
|
||
|
|
ozz::log::Log() << "Outputs RawSkeleton to binary archive." << std::endl;
|
||
|
|
archive << raw_skeleton;
|
||
|
|
} else {
|
||
|
|
ozz::log::Log() << "Outputs Skeleton to binary archive." << std::endl;
|
||
|
|
archive << *skeleton;
|
||
|
|
}
|
||
|
|
ozz::log::Log() << "Skeleton binary archive successfully outputted."
|
||
|
|
<< std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
} // namespace offline
|
||
|
|
} // namespace animation
|
||
|
|
} // namespace ozz
|