mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-23 09:37:17 +01:00
removed the fbx module.
This commit is contained in:
parent
27210500ef
commit
8f2388f9d8
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_fbx = env_modules.Clone()
|
||||
|
||||
# Make includes relative to the folder path specified here so our includes are clean
|
||||
env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
|
||||
|
||||
if env["builtin_zlib"]:
|
||||
env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"])
|
||||
|
||||
# Godot's own source files
|
||||
env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "fbx_parser/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "*.cpp")
|
@ -1,16 +0,0 @@
|
||||
def can_build(env, platform):
|
||||
return env["tools"]
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"EditorSceneImporterFBX",
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
@ -1,46 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_anim_container.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_ANIM_CONTAINER_H
|
||||
#define FBX_ANIM_CONTAINER_H
|
||||
|
||||
#include "core/vector.h"
|
||||
|
||||
// Generic keyframes 99.99 percent of files will be vector3, except if quat interp is used, or visibility tracks
|
||||
// FBXTrack is used in a map in the implementation in fbx/editor_scene_importer_fbx.cpp
|
||||
// to avoid having to rewrite the entire logic I refactored this into the code instead.
|
||||
// once it works I can rewrite so we can add the fun misc features / small features
|
||||
struct FBXTrack {
|
||||
bool has_default = false;
|
||||
Vector3 default_value;
|
||||
std::map<int64_t, Vector3> keyframes;
|
||||
};
|
||||
|
||||
#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H
|
@ -1,56 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_bone.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "fbx_bone.h"
|
||||
|
||||
#include "fbx_node.h"
|
||||
#include "import_state.h"
|
||||
|
||||
Ref<FBXNode> FBXSkinDeformer::get_link(const ImportState &state) const {
|
||||
print_verbose("bone name: " + bone->bone_name);
|
||||
|
||||
// safe for when deformers must be polyfilled when skin has different count of binds to bones in the scene ;)
|
||||
if (!cluster) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node");
|
||||
|
||||
Ref<FBXNode> link_node;
|
||||
uint64_t id = cluster->TargetNode()->ID();
|
||||
if (state.fbx_target_map.has(id)) {
|
||||
link_node = state.fbx_target_map[id];
|
||||
} else {
|
||||
print_error("link node not found for " + itos(id));
|
||||
}
|
||||
|
||||
// the node in space this is for, like if it's FOR a target.
|
||||
return link_node;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_bone.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_BONE_H
|
||||
#define FBX_BONE_H
|
||||
|
||||
#include "fbx_node.h"
|
||||
#include "import_state.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
struct PivotTransform;
|
||||
|
||||
struct FBXBone : public Reference {
|
||||
uint64_t parent_bone_id = 0;
|
||||
uint64_t bone_id = 0;
|
||||
|
||||
bool valid_parent = false; // if the parent bone id is set up.
|
||||
String bone_name = String(); // bone name
|
||||
|
||||
bool is_root_bone() const {
|
||||
return !valid_parent;
|
||||
}
|
||||
|
||||
// Godot specific data
|
||||
int godot_bone_id = -2; // godot internal bone id assigned after import
|
||||
|
||||
// if a bone / armature is the root then FBX skeleton will contain the bone not any other skeleton.
|
||||
// this is to support joints by themselves in scenes
|
||||
bool valid_armature_id = false;
|
||||
uint64_t armature_id = 0;
|
||||
|
||||
/* link node is the parent bone */
|
||||
mutable const FBXDocParser::Geometry *geometry = nullptr;
|
||||
mutable const FBXDocParser::ModelLimbNode *limb_node = nullptr;
|
||||
|
||||
void set_node(Ref<FBXNode> p_node) {
|
||||
node = p_node;
|
||||
}
|
||||
|
||||
// Stores the pivot xform for this bone
|
||||
|
||||
Ref<FBXNode> node = nullptr;
|
||||
Ref<FBXBone> parent_bone = nullptr;
|
||||
Ref<FBXSkeleton> fbx_skeleton = nullptr;
|
||||
};
|
||||
|
||||
struct FBXSkinDeformer {
|
||||
FBXSkinDeformer(Ref<FBXBone> p_bone, const FBXDocParser::Cluster *p_cluster) :
|
||||
cluster(p_cluster), bone(p_bone) {}
|
||||
~FBXSkinDeformer() {}
|
||||
const FBXDocParser::Cluster *cluster;
|
||||
Ref<FBXBone> bone;
|
||||
|
||||
/* get associate model - the model can be invalid sometimes */
|
||||
Ref<FBXBone> get_associate_model() const {
|
||||
return bone->parent_bone;
|
||||
}
|
||||
|
||||
Ref<FBXNode> get_link(const ImportState &state) const;
|
||||
};
|
||||
|
||||
#endif // FBX_BONE_H
|
@ -1,592 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_material.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "fbx_material.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/texture.h"
|
||||
#include "tools/validation_tools.h"
|
||||
|
||||
String FBXMaterial::get_material_name() const {
|
||||
return material_name;
|
||||
}
|
||||
|
||||
void FBXMaterial::set_imported_material(FBXDocParser::Material *p_material) {
|
||||
material = p_material;
|
||||
}
|
||||
|
||||
void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths) {
|
||||
if (search_directory.empty()) {
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(p_filename));
|
||||
} else {
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(search_directory + "/" + p_filename));
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file("../" + search_directory + "/" + p_filename));
|
||||
}
|
||||
}
|
||||
|
||||
String find_file(const String &p_base, const String &p_file_to_find) {
|
||||
_Directory dir;
|
||||
dir.open(p_base);
|
||||
|
||||
dir.list_dir_begin();
|
||||
String n = dir.get_next();
|
||||
while (n != String()) {
|
||||
if (n == "." || n == "..") {
|
||||
n = dir.get_next();
|
||||
continue;
|
||||
}
|
||||
if (dir.current_is_dir()) {
|
||||
// Don't use `path_to` or the returned path will be wrong.
|
||||
const String f = find_file(p_base + "/" + n, p_file_to_find);
|
||||
if (f != "") {
|
||||
return f;
|
||||
}
|
||||
} else if (n == p_file_to_find) {
|
||||
return p_base + "/" + n;
|
||||
}
|
||||
n = dir.get_next();
|
||||
}
|
||||
dir.list_dir_end();
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
// fbx will not give us good path information and let's not regex them to fix them
|
||||
// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK.
|
||||
String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) {
|
||||
_Directory dir;
|
||||
Vector<String> paths;
|
||||
add_search_string(p_filename, p_current_directory, "", paths);
|
||||
add_search_string(p_filename, p_current_directory, "texture", paths);
|
||||
add_search_string(p_filename, p_current_directory, "textures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "Textures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "materials", paths);
|
||||
add_search_string(p_filename, p_current_directory, "mats", paths);
|
||||
add_search_string(p_filename, p_current_directory, "pictures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "images", paths);
|
||||
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
if (dir.file_exists(paths[i])) {
|
||||
return paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
// We were not able to find the texture in the common locations,
|
||||
// try to find it into the project globally.
|
||||
// The common textures can be stored into one of those folders:
|
||||
// res://asset
|
||||
// res://texture
|
||||
// res://material
|
||||
// res://mat
|
||||
// res://image
|
||||
// res://picture
|
||||
//
|
||||
// Note the folders can also be called with custom names, like:
|
||||
// res://my_assets
|
||||
// since the keyword `asset` is into the directory name the textures will be
|
||||
// searched there too.
|
||||
|
||||
dir.open("res://");
|
||||
dir.list_dir_begin();
|
||||
String n = dir.get_next();
|
||||
while (n != String()) {
|
||||
if (n == "." || n == "..") {
|
||||
n = dir.get_next();
|
||||
continue;
|
||||
}
|
||||
if (dir.current_is_dir()) {
|
||||
const String lower_n = n.to_lower();
|
||||
if (
|
||||
// Don't need to use plural.
|
||||
lower_n.find("asset") >= 0 ||
|
||||
lower_n.find("texture") >= 0 ||
|
||||
lower_n.find("material") >= 0 ||
|
||||
lower_n.find("mat") >= 0 ||
|
||||
lower_n.find("image") >= 0 ||
|
||||
lower_n.find("picture") >= 0) {
|
||||
// Don't use `path_to` or the returned path will be wrong.
|
||||
const String f = find_file(String("res://") + n, p_filename);
|
||||
if (f != "") {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
n = dir.get_next();
|
||||
}
|
||||
dir.list_dir_end();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
FBXMaterial::MaterialInfo FBXMaterial::extract_material_info(const FBXDocParser::Material *material) const {
|
||||
MaterialInfo mat_info;
|
||||
|
||||
// TODO Layered textures are a collection on textures stored into an array.
|
||||
// Extract layered textures is not yet supported. Per each texture in the
|
||||
// layered texture array you want to use the below method to extract those.
|
||||
|
||||
for (std::pair<std::string, const FBXDocParser::Texture *> texture : material->Textures()) {
|
||||
const std::string &fbx_mapping_name = texture.first;
|
||||
|
||||
if (fbx_feature_mapping_desc.count(fbx_mapping_name) > 0) {
|
||||
// This is a feature not a normal texture.
|
||||
mat_info.features.push_back(fbx_feature_mapping_desc.at(fbx_mapping_name));
|
||||
continue;
|
||||
}
|
||||
|
||||
ERR_CONTINUE_MSG(fbx_texture_mapping_desc.count(fbx_mapping_name) <= 0, "This FBX has a material with mapping name: " + String(fbx_mapping_name.c_str()) + " which is not yet supported by this importer. Consider open an issue so we can support it.");
|
||||
|
||||
const String absoulte_fbx_file_path = texture.second->FileName().c_str();
|
||||
const String file_extension = absoulte_fbx_file_path.get_extension().to_upper();
|
||||
|
||||
const String file_extension_uppercase = file_extension.to_upper();
|
||||
|
||||
// TODO: one day we can add this
|
||||
if (file_extension.empty()) {
|
||||
continue; // skip it
|
||||
}
|
||||
|
||||
// TODO: we don't support EMBED for DDS and TGA.
|
||||
ERR_CONTINUE_MSG(
|
||||
file_extension_uppercase != "PNG" &&
|
||||
file_extension_uppercase != "JPEG" &&
|
||||
file_extension_uppercase != "JPG" &&
|
||||
file_extension_uppercase != "TGA" &&
|
||||
file_extension_uppercase != "WEBP" &&
|
||||
file_extension_uppercase != "DDS",
|
||||
"The FBX file contains a texture with an unrecognized extension: " + file_extension_uppercase);
|
||||
|
||||
const String texture_name = absoulte_fbx_file_path.get_file();
|
||||
print_verbose("Getting FBX mapping mode for " + String(fbx_mapping_name.c_str()));
|
||||
const SpatialMaterial::TextureParam mapping_mode = fbx_texture_mapping_desc.at(fbx_mapping_name);
|
||||
print_verbose("Set FBX mapping mode to " + get_texture_param_name(mapping_mode));
|
||||
TextureFileMapping file_mapping;
|
||||
file_mapping.map_mode = mapping_mode;
|
||||
file_mapping.name = texture_name;
|
||||
file_mapping.texture = texture.second;
|
||||
mat_info.textures.push_back(file_mapping);
|
||||
|
||||
// Make sure to active the various features.
|
||||
switch (mapping_mode) {
|
||||
case SpatialMaterial::TextureParam::TEXTURE_ALBEDO:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_METALLIC:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_FLOWMAP:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_REFRACTION:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_MAX:
|
||||
// No features required.
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_EMISSION:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_EMISSION);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_NORMAL:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_RIM:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_RIM);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_CLEARCOAT:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_AMBIENT_OCCLUSION);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DEPTH:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_DEPTH_MAPPING);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_SUBSURFACE_SCATTERING:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_SUBSURACE_SCATTERING);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_TRANSMISSION:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_TRANSMISSION);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DETAIL_ALBEDO:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DETAIL_MASK:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DETAIL_NORMAL:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_DETAIL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mat_info;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T extract_from_prop(FBXDocParser::PropertyPtr prop, const T &p_default, const std::string &p_name, const String &p_type) {
|
||||
ERR_FAIL_COND_V_MSG(prop == nullptr, p_default, "invalid property passed to extractor");
|
||||
const FBXDocParser::TypedProperty<T> *val = dynamic_cast<const FBXDocParser::TypedProperty<T> *>(prop);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(val == nullptr, p_default, "The FBX is corrupted, the property `" + String(p_name.c_str()) + "` is a `" + String(typeid(*prop).name()) + "` but should be a " + p_type);
|
||||
// Make sure to not lost any eventual opacity.
|
||||
return val->Value();
|
||||
}
|
||||
|
||||
Ref<SpatialMaterial> FBXMaterial::import_material(ImportState &state) {
|
||||
ERR_FAIL_COND_V(material == nullptr, nullptr);
|
||||
|
||||
const String p_fbx_current_directory = state.path;
|
||||
|
||||
Ref<SpatialMaterial> spatial_material;
|
||||
|
||||
// read the material file
|
||||
// is material two sided
|
||||
// read material name
|
||||
print_verbose("[material] material name: " + ImportUtils::FBXNodeToName(material->Name()));
|
||||
material_name = ImportUtils::FBXNodeToName(material->Name());
|
||||
|
||||
// Extract info.
|
||||
MaterialInfo material_info = extract_material_info(material);
|
||||
|
||||
// Extract other parameters info.
|
||||
for (FBXDocParser::LazyPropertyMap::value_type iter : material->Props()->GetLazyProperties()) {
|
||||
const std::string name = iter.first;
|
||||
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyDesc desc = PROPERTY_DESC_NOT_FOUND;
|
||||
if (fbx_properties_desc.count(name) > 0) {
|
||||
desc = fbx_properties_desc.at(name);
|
||||
}
|
||||
|
||||
// check if we can ignore this it will be done at the next phase
|
||||
if (desc == PROPERTY_DESC_NOT_FOUND || desc == PROPERTY_DESC_IGNORE) {
|
||||
// count the texture mapping references. Skip this one if it's found and we can't look up a property value.
|
||||
if (fbx_texture_mapping_desc.count(name) > 0) {
|
||||
continue; // safe to ignore it's a texture mapping.
|
||||
}
|
||||
}
|
||||
|
||||
if (desc == PROPERTY_DESC_IGNORE) {
|
||||
//WARN_PRINT("[Ignored] The FBX material parameter: `" + String(name.c_str()) + "` is ignored.");
|
||||
continue;
|
||||
} else {
|
||||
print_verbose("FBX Material parameter: " + String(name.c_str()));
|
||||
|
||||
// Check for Diffuse material system / lambert materials / legacy basically
|
||||
if (name == "Diffuse" && !warning_non_pbr_material) {
|
||||
ValidationTracker::get_singleton()->add_validation_error(state.path, "Invalid material settings change to Ai Standard Surface shader, mat name: " + material_name.c_escape());
|
||||
warning_non_pbr_material = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DISABLE when adding support for all weird and wonderful material formats
|
||||
if (desc == PROPERTY_DESC_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
|
||||
|
||||
const FBXDocParser::PropertyTable *tbl = material->Props();
|
||||
FBXDocParser::PropertyPtr prop = tbl->Get(name);
|
||||
|
||||
ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));
|
||||
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no data no material is created.
|
||||
spatial_material.instance();
|
||||
}
|
||||
|
||||
const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop);
|
||||
const FBXDocParser::TypedProperty<Vector3> *vector_value = dynamic_cast<const FBXDocParser::TypedProperty<Vector3> *>(prop);
|
||||
|
||||
if (!real_value && !vector_value) {
|
||||
//WARN_PRINT("unsupported datatype in property: " + String(name.c_str()));
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Zero / default value properties
|
||||
// TODO: implement fields correctly tomorrow so we check 'has x mapping' before 'read x mapping' etc.
|
||||
|
||||
// if(real_value)
|
||||
// {
|
||||
// if(real_value->Value() == 0 && !vector_value)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (vector_value && !real_value) {
|
||||
if (vector_value->Value() == Vector3(0, 0, 0) && !real_value) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (desc) {
|
||||
case PROPERTY_DESC_ALBEDO_COLOR: {
|
||||
if (vector_value) {
|
||||
const Vector3 &color = vector_value->Value();
|
||||
// Make sure to not lost any eventual opacity.
|
||||
if (color != Vector3(0, 0, 0)) {
|
||||
Color c = Color();
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_albedo(c);
|
||||
}
|
||||
|
||||
} else if (real_value) {
|
||||
print_error("albedo is unsupported format?");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_TRANSPARENT: {
|
||||
if (real_value) {
|
||||
const real_t opacity = real_value->Value();
|
||||
if (opacity < (1.0 - CMP_EPSILON)) {
|
||||
Color c = spatial_material->get_albedo();
|
||||
c.a = opacity;
|
||||
spatial_material->set_albedo(c);
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_TRANSPARENT);
|
||||
spatial_material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
|
||||
}
|
||||
} else if (vector_value) {
|
||||
print_error("unsupported transparent desc type vector!");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_SPECULAR: {
|
||||
if (real_value) {
|
||||
print_verbose("specular real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_specular(MIN(1.0, real_value->Value()));
|
||||
}
|
||||
|
||||
if (vector_value) {
|
||||
print_error("unsupported specular vector value: " + vector_value->Value());
|
||||
}
|
||||
} break;
|
||||
|
||||
case PROPERTY_DESC_SPECULAR_COLOR: {
|
||||
if (vector_value) {
|
||||
print_error("unsupported specular color: " + vector_value->Value());
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_SHINYNESS: {
|
||||
if (real_value) {
|
||||
print_error("unsupported shinyness:" + rtos(real_value->Value()));
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_METALLIC: {
|
||||
if (real_value) {
|
||||
print_verbose("metallic real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_metallic(MIN(1.0f, real_value->Value()));
|
||||
} else {
|
||||
print_error("unsupported value type for metallic");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_ROUGHNESS: {
|
||||
if (real_value) {
|
||||
print_verbose("roughness real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_roughness(MIN(1.0f, real_value->Value()));
|
||||
} else {
|
||||
print_error("unsupported value type for roughness");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_COAT: {
|
||||
if (real_value) {
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT);
|
||||
print_verbose("clearcoat real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_clearcoat(MIN(1.0f, real_value->Value()));
|
||||
} else {
|
||||
print_error("unsupported value type for clearcoat");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_COAT_ROUGHNESS: {
|
||||
// meaning is that approx equal to zero is disabled not actually zero. ;)
|
||||
if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) {
|
||||
print_verbose("clearcoat real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_clearcoat_gloss(1.0 - real_value->Value());
|
||||
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT);
|
||||
} else {
|
||||
print_error("unsupported value type for clearcoat gloss");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_EMISSIVE: {
|
||||
if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) {
|
||||
print_verbose("Emissive real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_emission_energy(real_value->Value());
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_EMISSION);
|
||||
} else if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) {
|
||||
const Vector3 &color = vector_value->Value();
|
||||
Color c;
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_emission(c);
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_EMISSION);
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_EMISSIVE_COLOR: {
|
||||
if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) {
|
||||
const Vector3 &color = vector_value->Value();
|
||||
Color c;
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_emission(c);
|
||||
} else {
|
||||
print_error("unsupported value type for emissive color");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_NOT_FOUND:
|
||||
case PROPERTY_DESC_IGNORE:
|
||||
// Already checked, can't happen.
|
||||
CRASH_NOW();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the material features.
|
||||
for (int x = 0; x < material_info.features.size(); x++) {
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no textures no material is created.
|
||||
spatial_material.instance();
|
||||
}
|
||||
spatial_material->set_feature(material_info.features[x], true);
|
||||
}
|
||||
|
||||
// Set the textures.
|
||||
for (int x = 0; x < material_info.textures.size(); x++) {
|
||||
TextureFileMapping mapping = material_info.textures[x];
|
||||
Ref<Texture> texture;
|
||||
print_verbose("texture mapping name: " + mapping.name);
|
||||
|
||||
if (state.cached_image_searches.has(mapping.name)) {
|
||||
texture = state.cached_image_searches[mapping.name];
|
||||
} else {
|
||||
String path = find_texture_path_by_filename(mapping.name, p_fbx_current_directory);
|
||||
if (!path.empty()) {
|
||||
Error err;
|
||||
Ref<Texture> image_texture = ResourceLoader::load(path, "Texture", false, &err);
|
||||
|
||||
ERR_CONTINUE_MSG(err != OK, "unable to import image file not loaded yet: " + path);
|
||||
ERR_CONTINUE(image_texture == nullptr || image_texture.is_null());
|
||||
|
||||
texture = image_texture;
|
||||
state.cached_image_searches.insert(mapping.name, texture);
|
||||
print_verbose("Created texture from loaded image file.");
|
||||
|
||||
} else if (mapping.texture != nullptr && mapping.texture->Media() != nullptr && mapping.texture->Media()->IsEmbedded()) {
|
||||
// This is an embedded texture. Extract it.
|
||||
Ref<Image> image;
|
||||
image.instance();
|
||||
|
||||
const String extension = mapping.name.get_extension().to_upper();
|
||||
if (extension == "PNG") {
|
||||
// The stored file is a PNG.
|
||||
image = Image::_png_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded PNG image load fail.");
|
||||
|
||||
} else if (
|
||||
extension == "JPEG" ||
|
||||
extension == "JPG") {
|
||||
// The stored file is a JPEG.
|
||||
image = Image::_jpg_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded JPEG image load fail.");
|
||||
|
||||
} else if (extension == "TGA") {
|
||||
// The stored file is a TGA.
|
||||
image = Image::_tga_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail.");
|
||||
|
||||
} else if (extension == "WEBP") {
|
||||
// The stored file is a WEBP.
|
||||
image = Image::_webp_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded WEBP image load fail.");
|
||||
|
||||
// } else if (extension == "DDS") {
|
||||
// // In this moment is not possible to extract a DDS from a buffer, TODO consider add it to godot. See `textureloader_dds.cpp::load().
|
||||
// // The stored file is a DDS.
|
||||
} else {
|
||||
ERR_CONTINUE_MSG(true, "The embedded image with extension: " + extension + " is not yet supported. Open an issue please.");
|
||||
}
|
||||
|
||||
Ref<ImageTexture> image_texture;
|
||||
image_texture.instance();
|
||||
image_texture->create_from_image(image);
|
||||
|
||||
const int32_t flags = Texture::FLAGS_DEFAULT;
|
||||
image_texture->set_flags(flags);
|
||||
|
||||
texture = image_texture;
|
||||
state.cached_image_searches[mapping.name] = texture;
|
||||
print_verbose("Created texture from embedded image.");
|
||||
} else {
|
||||
ERR_CONTINUE_MSG(true, "The FBX texture, with name: `" + mapping.name + "`, is not found into the project nor is stored as embedded file. Make sure to insert the texture as embedded file or into the project, then reimport.");
|
||||
}
|
||||
}
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no textures no material is created.
|
||||
spatial_material.instance();
|
||||
}
|
||||
|
||||
switch (mapping.map_mode) {
|
||||
case SpatialMaterial::TextureParam::TEXTURE_METALLIC:
|
||||
if (mapping.name.to_lower().find("ser") >= 0) {
|
||||
// SER shader.
|
||||
spatial_material->set_metallic_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_RED);
|
||||
} else {
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_metallic_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
}
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS:
|
||||
if (mapping.name.to_lower().find("ser") >= 0) {
|
||||
// SER shader.
|
||||
spatial_material->set_roughness_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_BLUE);
|
||||
} else {
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_roughness_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
}
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION:
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_ao_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_REFRACTION:
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_refraction_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
break;
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
|
||||
print_verbose("Texture mapping mode: " + itos(mapping.map_mode) + " name: " + get_texture_param_name(mapping.map_mode));
|
||||
|
||||
spatial_material->set_texture(mapping.map_mode, texture);
|
||||
}
|
||||
|
||||
if (spatial_material.is_valid()) {
|
||||
spatial_material->set_name(material_name);
|
||||
}
|
||||
|
||||
return spatial_material;
|
||||
}
|
@ -1,294 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_material.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_MATERIAL_H
|
||||
#define FBX_MATERIAL_H
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
#include "core/reference.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
struct FBXMaterial : public Reference {
|
||||
String material_name = String();
|
||||
bool warning_non_pbr_material = false;
|
||||
FBXDocParser::Material *material = nullptr;
|
||||
|
||||
/* Godot materials
|
||||
*** Texture Maps:
|
||||
* Albedo - color, texture
|
||||
* Metallic - specular, metallic, texture
|
||||
* Roughness - roughness, texture
|
||||
* Emission - color, texture
|
||||
* Normal Map - scale, texture
|
||||
* Ambient Occlusion - texture
|
||||
* Refraction - scale, texture
|
||||
*** Has Settings for:
|
||||
* UV1 - SCALE, OFFSET
|
||||
* UV2 - SCALE, OFFSET
|
||||
*** Flags for
|
||||
* Transparent
|
||||
* Cull Mode
|
||||
*/
|
||||
|
||||
enum class MapMode {
|
||||
AlbedoM = 0,
|
||||
MetallicM,
|
||||
SpecularM,
|
||||
EmissionM,
|
||||
RoughnessM,
|
||||
NormalM,
|
||||
AmbientOcclusionM,
|
||||
RefractionM,
|
||||
ReflectionM,
|
||||
};
|
||||
|
||||
/* Returns the string representation of the TextureParam enum */
|
||||
static String get_texture_param_name(SpatialMaterial::TextureParam param) {
|
||||
switch (param) {
|
||||
case SpatialMaterial::TEXTURE_ALBEDO:
|
||||
return "TEXTURE_ALBEDO";
|
||||
case SpatialMaterial::TEXTURE_METALLIC:
|
||||
return "TEXTURE_METALLIC";
|
||||
case SpatialMaterial::TEXTURE_ROUGHNESS:
|
||||
return "TEXTURE_ROUGHNESS";
|
||||
case SpatialMaterial::TEXTURE_EMISSION:
|
||||
return "TEXTURE_EMISSION";
|
||||
case SpatialMaterial::TEXTURE_NORMAL:
|
||||
return "TEXTURE_NORMAL";
|
||||
case SpatialMaterial::TEXTURE_RIM:
|
||||
return "TEXTURE_RIM";
|
||||
case SpatialMaterial::TEXTURE_CLEARCOAT:
|
||||
return "TEXTURE_CLEARCOAT";
|
||||
case SpatialMaterial::TEXTURE_FLOWMAP:
|
||||
return "TEXTURE_FLOWMAP";
|
||||
case SpatialMaterial::TEXTURE_AMBIENT_OCCLUSION:
|
||||
return "TEXTURE_AMBIENT_OCCLUSION";
|
||||
case SpatialMaterial::TEXTURE_DEPTH:
|
||||
return "TEXTURE_DEPTH";
|
||||
case SpatialMaterial::TEXTURE_SUBSURFACE_SCATTERING:
|
||||
return "TEXTURE_SUBSURFACE_SCATTERING";
|
||||
case SpatialMaterial::TEXTURE_TRANSMISSION:
|
||||
return "TEXTURE_TRANSMISSION";
|
||||
case SpatialMaterial::TEXTURE_REFRACTION:
|
||||
return "TEXTURE_REFRACTION";
|
||||
case SpatialMaterial::TEXTURE_DETAIL_MASK:
|
||||
return "TEXTURE_DETAIL_MASK";
|
||||
case SpatialMaterial::TEXTURE_DETAIL_ALBEDO:
|
||||
return "TEXTURE_DETAIL_ALBEDO";
|
||||
case SpatialMaterial::TEXTURE_DETAIL_NORMAL:
|
||||
return "TEXTURE_DETAIL_NORMAL";
|
||||
case SpatialMaterial::TEXTURE_MAX:
|
||||
return "TEXTURE_MAX";
|
||||
default:
|
||||
return "broken horribly";
|
||||
}
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
const std::map<std::string, SpatialMaterial::Feature> fbx_feature_mapping_desc = {
|
||||
/* Transparent */
|
||||
{ "TransparentColor", SpatialMaterial::Feature::FEATURE_TRANSPARENT },
|
||||
{ "Maya|opacity", SpatialMaterial::Feature::FEATURE_TRANSPARENT }
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
const std::map<std::string, SpatialMaterial::TextureParam> fbx_texture_mapping_desc = {
|
||||
/* Diffuse */
|
||||
{ "Maya|base", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "DiffuseColor", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|DiffuseTexture", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|baseColor", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|baseColor|file", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "3dsMax|Parameters|base_color_map", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|TEX_color_map|file", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|TEX_color_map", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
/* Emission */
|
||||
{ "EmissiveColor", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "EmissiveFactor", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|emissionColor", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|emissionColor|file", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "3dsMax|Parameters|emission_map", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|TEX_emissive_map", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|TEX_emissive_map|file", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
/* Metallic */
|
||||
{ "Maya|metalness", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|metalness|file", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "3dsMax|Parameters|metalness_map", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|TEX_metallic_map", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|TEX_metallic_map|file", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "SpecularColor", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|specularColor", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|SpecularTexture", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|SpecularTexture|file", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
|
||||
/* Roughness */
|
||||
// Arnold Roughness Map
|
||||
{ "Maya|specularRoughness", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
|
||||
{ "3dsMax|Parameters|roughness_map", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|TEX_roughness_map", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|TEX_roughness_map|file", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
|
||||
/* Normal */
|
||||
{ "NormalMap", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "Bump", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "3dsMax|Parameters|bump_map", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|NormalTexture", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "Maya|normalCamera", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "Maya|normalCamera|file", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|TEX_normal_map", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|TEX_normal_map|file", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
/* AO */
|
||||
{ "Maya|TEX_ao_map", SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
|
||||
{ "Maya|TEX_ao_map|file", SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
|
||||
|
||||
//{ "Maya|diffuseRoughness", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
//{ "Maya|diffuseRoughness|file", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
//{ "ShininessExponent", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
//{ "ReflectionFactor", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
//{ "TransparentColor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA },
|
||||
//{ "TransparencyFactor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA }
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
enum PropertyDesc {
|
||||
PROPERTY_DESC_NOT_FOUND,
|
||||
PROPERTY_DESC_ALBEDO_COLOR,
|
||||
PROPERTY_DESC_TRANSPARENT,
|
||||
PROPERTY_DESC_METALLIC,
|
||||
PROPERTY_DESC_ROUGHNESS,
|
||||
PROPERTY_DESC_SPECULAR,
|
||||
PROPERTY_DESC_SPECULAR_COLOR,
|
||||
PROPERTY_DESC_SHINYNESS,
|
||||
PROPERTY_DESC_COAT,
|
||||
PROPERTY_DESC_COAT_ROUGHNESS,
|
||||
PROPERTY_DESC_EMISSIVE,
|
||||
PROPERTY_DESC_EMISSIVE_COLOR,
|
||||
PROPERTY_DESC_IGNORE
|
||||
};
|
||||
|
||||
const std::map<std::string, PropertyDesc> fbx_properties_desc = {
|
||||
/* Albedo */
|
||||
{ "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
{ "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
|
||||
/* Specular */
|
||||
{ "Maya|specular", PROPERTY_DESC_SPECULAR },
|
||||
{ "Maya|specularColor", PROPERTY_DESC_SPECULAR_COLOR },
|
||||
|
||||
/* Specular roughness - arnold roughness map */
|
||||
{ "Maya|specularRoughness", PROPERTY_DESC_ROUGHNESS },
|
||||
|
||||
/* Transparent */
|
||||
{ "Opacity", PROPERTY_DESC_TRANSPARENT },
|
||||
{ "TransparencyFactor", PROPERTY_DESC_TRANSPARENT },
|
||||
{ "Maya|opacity", PROPERTY_DESC_TRANSPARENT },
|
||||
|
||||
/* Metallic */
|
||||
{ "Shininess", PROPERTY_DESC_METALLIC },
|
||||
{ "Reflectivity", PROPERTY_DESC_METALLIC },
|
||||
{ "Maya|metalness", PROPERTY_DESC_METALLIC },
|
||||
{ "Maya|metallic", PROPERTY_DESC_METALLIC },
|
||||
|
||||
/* Roughness */
|
||||
{ "Maya|roughness", PROPERTY_DESC_ROUGHNESS },
|
||||
|
||||
/* Coat */
|
||||
//{ "Maya|coat", PROPERTY_DESC_COAT },
|
||||
|
||||
/* Coat roughness */
|
||||
//{ "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS },
|
||||
|
||||
/* Emissive */
|
||||
{ "Maya|emission", PROPERTY_DESC_EMISSIVE },
|
||||
{ "Maya|emissive", PROPERTY_DESC_EMISSIVE },
|
||||
|
||||
/* Emissive color */
|
||||
{ "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR },
|
||||
{ "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR },
|
||||
|
||||
/* Ignore */
|
||||
{ "Maya|diffuseRoughness", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya", PROPERTY_DESC_IGNORE },
|
||||
{ "Diffuse", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
{ "Maya|TypeId", PROPERTY_DESC_IGNORE },
|
||||
{ "Ambient", PROPERTY_DESC_IGNORE },
|
||||
{ "AmbientColor", PROPERTY_DESC_IGNORE },
|
||||
{ "ShininessExponent", PROPERTY_DESC_IGNORE },
|
||||
{ "Specular", PROPERTY_DESC_IGNORE },
|
||||
{ "SpecularColor", PROPERTY_DESC_IGNORE },
|
||||
{ "SpecularFactor", PROPERTY_DESC_IGNORE },
|
||||
//{ "BumpFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|exitToBackground", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|indirectDiffuse", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|indirectSpecular", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|internalReflections", PROPERTY_DESC_IGNORE },
|
||||
{ "DiffuseFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "AmbientFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "ReflectionColor", PROPERTY_DESC_IGNORE },
|
||||
{ "Emissive", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatColor", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatNormal", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatIOR", PROPERTY_DESC_IGNORE },
|
||||
};
|
||||
|
||||
struct TextureFileMapping {
|
||||
SpatialMaterial::TextureParam map_mode = SpatialMaterial::TEXTURE_ALBEDO;
|
||||
String name = String();
|
||||
const FBXDocParser::Texture *texture = nullptr;
|
||||
};
|
||||
|
||||
/* storing the texture properties like color */
|
||||
template <class T>
|
||||
struct TexturePropertyMapping : Reference {
|
||||
SpatialMaterial::TextureParam map_mode = SpatialMaterial::TextureParam::TEXTURE_ALBEDO;
|
||||
const T property = T();
|
||||
};
|
||||
|
||||
static void add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths);
|
||||
|
||||
static String find_texture_path_by_filename(const String p_filename, const String p_current_directory);
|
||||
|
||||
String get_material_name() const;
|
||||
|
||||
void set_imported_material(FBXDocParser::Material *p_material);
|
||||
|
||||
struct MaterialInfo {
|
||||
Vector<TextureFileMapping> textures;
|
||||
Vector<SpatialMaterial::Feature> features;
|
||||
};
|
||||
/// Extracts the material information.
|
||||
MaterialInfo extract_material_info(const FBXDocParser::Material *material) const;
|
||||
|
||||
Ref<SpatialMaterial> import_material(ImportState &state);
|
||||
};
|
||||
|
||||
#endif // FBX_MATERIAL_H
|
File diff suppressed because it is too large
Load Diff
@ -1,182 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_mesh_data.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_MESH_DATA_H
|
||||
#define FBX_MESH_DATA_H
|
||||
|
||||
#include "core/hash_map.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "fbx_bone.h"
|
||||
#include "fbx_parser/FBXMeshGeometry.h"
|
||||
#include "import_state.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
struct FBXNode;
|
||||
struct FBXMeshData;
|
||||
struct FBXBone;
|
||||
struct ImportState;
|
||||
|
||||
struct VertexWeightMapping {
|
||||
Vector<real_t> weights;
|
||||
Vector<int> bones;
|
||||
// This extra vector is used because the bone id is computed in a second step.
|
||||
// TODO Get rid of this extra step is a good idea.
|
||||
Vector<Ref<FBXBone>> bones_ref;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VertexData {
|
||||
int polygon_index;
|
||||
T data;
|
||||
};
|
||||
|
||||
// Caches mesh information and instantiates meshes for you using helper functions.
|
||||
struct FBXMeshData : Reference {
|
||||
struct MorphVertexData {
|
||||
// TODO we have only these??
|
||||
/// Each element is a vertex. Not supposed to be void.
|
||||
Vector<Vector3> vertices;
|
||||
/// Each element is a vertex. Not supposed to be void.
|
||||
Vector<Vector3> normals;
|
||||
};
|
||||
|
||||
// FIXME: remove this is a hack for testing only
|
||||
mutable const FBXDocParser::MeshGeometry *mesh_geometry = nullptr;
|
||||
|
||||
Ref<FBXNode> mesh_node = nullptr;
|
||||
/// vertex id, Weight Info
|
||||
/// later: perf we can use array here
|
||||
HashMap<int, VertexWeightMapping> vertex_weights;
|
||||
|
||||
// translate fbx mesh data from document context to FBX Mesh Geometry Context
|
||||
bool valid_weight_indexes = false;
|
||||
|
||||
MeshInstance *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, uint32_t p_compress_flags);
|
||||
|
||||
void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
|
||||
|
||||
/* mesh maximum weight count */
|
||||
bool valid_weight_count = false;
|
||||
int max_weight_count = 0;
|
||||
uint64_t armature_id = 0;
|
||||
bool valid_armature_id = false;
|
||||
MeshInstance *godot_mesh_instance = nullptr;
|
||||
|
||||
private:
|
||||
void sanitize_vertex_weights(const ImportState &state);
|
||||
|
||||
/// Make sure to reorganize the vertices so that the correct UV is taken.
|
||||
/// This step is needed because differently from the normal, that can be
|
||||
/// combined, the UV may need its own triangle because sometimes they have
|
||||
/// really different UV for the same vertex but different polygon.
|
||||
/// This function make sure to add another vertex for those UVS.
|
||||
void reorganize_vertices(
|
||||
std::vector<int> &r_polygon_indices,
|
||||
std::vector<Vector3> &r_vertices,
|
||||
HashMap<int, Vector3> &r_normals,
|
||||
HashMap<int, Vector2> &r_uv_1,
|
||||
HashMap<int, Vector2> &r_uv_2,
|
||||
HashMap<int, Color> &r_color,
|
||||
HashMap<String, MorphVertexData> &r_morphs,
|
||||
HashMap<int, HashMap<int, Vector3>> &r_normals_raw,
|
||||
HashMap<int, HashMap<int, Color>> &r_colors_raw,
|
||||
HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw,
|
||||
HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw);
|
||||
|
||||
void add_vertex(
|
||||
const ImportState &state,
|
||||
Ref<SurfaceTool> p_surface_tool,
|
||||
real_t p_scale,
|
||||
int p_vertex,
|
||||
const std::vector<Vector3> &p_vertices_position,
|
||||
const HashMap<int, Vector3> &p_normals,
|
||||
const HashMap<int, Vector2> &p_uvs_0,
|
||||
const HashMap<int, Vector2> &p_uvs_1,
|
||||
const HashMap<int, Color> &p_colors,
|
||||
const Vector3 &p_morph_value = Vector3(),
|
||||
const Vector3 &p_morph_normal = Vector3());
|
||||
|
||||
void triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const;
|
||||
|
||||
/// This function is responsible to convert the FBX polygon vertex to
|
||||
/// vertex index.
|
||||
/// The polygon vertices are stored in an array with some negative
|
||||
/// values. The negative values define the last face index.
|
||||
/// For example the following `face_array` contains two faces, the former
|
||||
/// with 3 vertices and the latter with a line:
|
||||
/// [0,2,-2,3,-5]
|
||||
/// Parsed as:
|
||||
/// [0, 2, 1, 3, 4]
|
||||
/// The negative values are computed using this formula: `(-value) - 1`
|
||||
///
|
||||
/// Returns the vertex index from the polygon vertex.
|
||||
/// Returns -1 if `p_index` is invalid.
|
||||
int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns true if this polygon_vertex_index is the end of a new polygon.
|
||||
bool is_end_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns true if this polygon_vertex_index is the begin of a new polygon.
|
||||
bool is_start_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns the number of polygons.
|
||||
int count_polygons(const std::vector<int> &p_face_indices) const;
|
||||
|
||||
/// Used to extract data from the `MappingData` aligned with vertex.
|
||||
/// Useful to extract normal/uvs/colors/tangents/etc...
|
||||
/// If the function fails somehow, it returns an hollow vector and print an error.
|
||||
template <class R, class T>
|
||||
HashMap<int, R> extract_per_vertex_data(
|
||||
int p_vertex_count,
|
||||
const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edges,
|
||||
const std::vector<int> &p_mesh_indices,
|
||||
const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data,
|
||||
R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back),
|
||||
R p_fall_back) const;
|
||||
|
||||
/// Used to extract data from the `MappingData` organized per polygon.
|
||||
/// Useful to extract the material
|
||||
/// If the function fails somehow, it returns an hollow vector and print an error.
|
||||
template <class T>
|
||||
HashMap<int, T> extract_per_polygon(
|
||||
int p_vertex_count,
|
||||
const std::vector<int> &p_face_indices,
|
||||
const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data,
|
||||
T p_fallback_value) const;
|
||||
|
||||
/// Extracts the morph data and organizes it per vertices.
|
||||
/// The returned `MorphVertexData` arrays are never something different
|
||||
/// then the `vertex_count`.
|
||||
void extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data);
|
||||
};
|
||||
|
||||
#endif // FBX_MESH_DATA_H
|
@ -1,63 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_node.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_NODE_H
|
||||
#define FBX_NODE_H
|
||||
|
||||
#include "fbx_skeleton.h"
|
||||
#include "model_abstraction.h"
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
class Spatial;
|
||||
struct PivotTransform;
|
||||
|
||||
struct FBXNode : Reference, ModelAbstraction {
|
||||
uint64_t current_node_id = 0;
|
||||
String node_name = String();
|
||||
Spatial *godot_node = nullptr;
|
||||
|
||||
// used to parent the skeleton once the tree is built.
|
||||
Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>();
|
||||
|
||||
void set_parent(Ref<FBXNode> p_parent) {
|
||||
fbx_parent = p_parent;
|
||||
}
|
||||
|
||||
void set_pivot_transform(Ref<PivotTransform> p_pivot_transform) {
|
||||
pivot_transform = p_pivot_transform;
|
||||
}
|
||||
|
||||
Ref<PivotTransform> pivot_transform = Ref<PivotTransform>(); // local and global xform data
|
||||
Ref<FBXNode> fbx_parent = Ref<FBXNode>(); // parent node
|
||||
};
|
||||
|
||||
#endif // FBX_NODE_H
|
@ -1,123 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_skeleton.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "fbx_skeleton.h"
|
||||
|
||||
#include "import_state.h"
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
void FBXSkeleton::init_skeleton(const ImportState &state) {
|
||||
int skeleton_bone_count = skeleton_bones.size();
|
||||
|
||||
if (skeleton == nullptr && skeleton_bone_count > 0) {
|
||||
skeleton = memnew(Skeleton);
|
||||
|
||||
if (fbx_node.is_valid()) {
|
||||
// cache skeleton attachment for later during node creation
|
||||
// can't be done until after node hierarchy is built
|
||||
if (fbx_node->godot_node != state.root) {
|
||||
fbx_node->skeleton_node = Ref<FBXSkeleton>(this);
|
||||
print_verbose("cached armature skeleton attachment for node " + fbx_node->node_name);
|
||||
} else {
|
||||
// root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton)
|
||||
fbx_node->godot_node->add_child(skeleton);
|
||||
skeleton->set_owner(state.root_owner);
|
||||
skeleton->set_name("Skeleton");
|
||||
print_verbose("created armature skeleton for root");
|
||||
}
|
||||
} else {
|
||||
memfree(skeleton);
|
||||
skeleton = nullptr;
|
||||
print_error("[doc] skeleton has no valid node to parent nodes to - erasing");
|
||||
skeleton_bones.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the bone name uniques.
|
||||
for (int x = 0; x < skeleton_bone_count; x++) {
|
||||
Ref<FBXBone> bone = skeleton_bones[x];
|
||||
if (bone.is_valid()) {
|
||||
// Make sure the bone name is unique.
|
||||
const String bone_name = bone->bone_name;
|
||||
int same_name_count = 0;
|
||||
for (int y = x + 1; y < skeleton_bone_count; y++) {
|
||||
Ref<FBXBone> other_bone = skeleton_bones[y];
|
||||
if (other_bone.is_valid()) {
|
||||
if (other_bone->bone_name == bone_name) {
|
||||
same_name_count += 1;
|
||||
other_bone->bone_name += "_" + itos(same_name_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<int, Ref<FBXBone>> bone_map;
|
||||
// implement fbx cluster skin logic here this is where it goes
|
||||
int bone_count = 0;
|
||||
for (int x = 0; x < skeleton_bone_count; x++) {
|
||||
Ref<FBXBone> bone = skeleton_bones[x];
|
||||
if (bone.is_valid()) {
|
||||
skeleton->add_bone(bone->bone_name);
|
||||
bone->godot_bone_id = bone_count;
|
||||
bone->fbx_skeleton = Ref<FBXSkeleton>(this);
|
||||
bone_map.insert(bone_count, bone);
|
||||
print_verbose("added bone " + itos(bone->bone_id) + " " + bone->bone_name);
|
||||
bone_count++;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?");
|
||||
|
||||
for (Map<int, Ref<FBXBone>>::Element *bone_element = bone_map.front(); bone_element; bone_element = bone_element->next()) {
|
||||
const Ref<FBXBone> bone = bone_element->value();
|
||||
int bone_index = bone_element->key();
|
||||
print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
|
||||
|
||||
skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale));
|
||||
|
||||
// lookup parent ID
|
||||
if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {
|
||||
Ref<FBXBone> parent_bone = state.fbx_bone_map[bone->parent_bone_id];
|
||||
int bone_id = skeleton->find_bone(parent_bone->bone_name);
|
||||
if (bone_id != -1) {
|
||||
skeleton->set_bone_parent(bone_index, bone_id);
|
||||
} else {
|
||||
print_error("invalid bone parent: " + parent_bone->bone_name);
|
||||
}
|
||||
} else {
|
||||
if (bone->godot_bone_id != -1) {
|
||||
skeleton->set_bone_parent(bone_index, -1); // no parent for this bone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_skeleton.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_SKELETON_H
|
||||
#define FBX_SKELETON_H
|
||||
|
||||
#include "fbx_bone.h"
|
||||
#include "fbx_node.h"
|
||||
#include "model_abstraction.h"
|
||||
|
||||
#include "core/reference.h"
|
||||
#include "scene/3d/skeleton.h"
|
||||
|
||||
struct FBXNode;
|
||||
struct ImportState;
|
||||
struct FBXBone;
|
||||
|
||||
struct FBXSkeleton : Reference {
|
||||
Ref<FBXNode> fbx_node = Ref<FBXNode>();
|
||||
Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>();
|
||||
Skeleton *skeleton = nullptr;
|
||||
|
||||
void init_skeleton(const ImportState &state);
|
||||
};
|
||||
|
||||
#endif // FBX_SKELETON_H
|
@ -1,113 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_state.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_STATE_H
|
||||
#define IMPORT_STATE_H
|
||||
|
||||
#include "fbx_mesh_data.h"
|
||||
#include "tools/import_utils.h"
|
||||
#include "tools/validation_tools.h"
|
||||
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "core/bind/core_bind.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/vector.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "scene/3d/skeleton.h"
|
||||
#include "scene/3d/spatial.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "modules/fbx/fbx_parser/FBXDocument.h"
|
||||
#include "modules/fbx/fbx_parser/FBXImportSettings.h"
|
||||
#include "modules/fbx/fbx_parser/FBXMeshGeometry.h"
|
||||
#include "modules/fbx/fbx_parser/FBXParser.h"
|
||||
#include "modules/fbx/fbx_parser/FBXTokenizer.h"
|
||||
#include "modules/fbx/fbx_parser/FBXUtil.h"
|
||||
|
||||
struct FBXBone;
|
||||
struct FBXMeshData;
|
||||
struct FBXNode;
|
||||
struct FBXSkeleton;
|
||||
|
||||
struct ImportState {
|
||||
bool enable_material_import = true;
|
||||
bool enable_animation_import = true;
|
||||
bool is_blender_fbx = false;
|
||||
|
||||
Map<StringName, Ref<Texture>> cached_image_searches;
|
||||
Map<uint64_t, Ref<SpatialMaterial>> cached_materials;
|
||||
|
||||
String path = String();
|
||||
Spatial *root_owner = nullptr;
|
||||
Spatial *root = nullptr;
|
||||
real_t scale = 0.01;
|
||||
Ref<FBXNode> fbx_root_node = Ref<FBXNode>();
|
||||
// skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically.
|
||||
Map<uint64_t, Ref<FBXSkeleton>> skeleton_map = Map<uint64_t, Ref<FBXSkeleton>>();
|
||||
|
||||
// nodes on the same level get merged automatically.
|
||||
//Map<uint64_t, Skeleton *> armature_map;
|
||||
AnimationPlayer *animation_player = nullptr;
|
||||
|
||||
// Generation 4 - Raw document accessing for bone/skin/joint/kLocators
|
||||
// joints are not necessarily bones but must be merged into the skeleton
|
||||
// (bone id), bone
|
||||
Map<uint64_t, Ref<FBXBone>> fbx_bone_map = Map<uint64_t, Ref<FBXBone>>(); // this is the bone name and setup information required for joints
|
||||
// this will never contain joints only bones attached to a mesh.
|
||||
|
||||
// Generation 4 - Raw document for creating the nodes transforms in the scene
|
||||
// this is a list of the nodes in the scene
|
||||
// (id, node)
|
||||
List<Ref<FBXNode>> fbx_node_list = List<Ref<FBXNode>>();
|
||||
|
||||
// All nodes which have been created in the scene
|
||||
// this will not contain the root node of the scene
|
||||
Map<uint64_t, Ref<FBXNode>> fbx_target_map = Map<uint64_t, Ref<FBXNode>>();
|
||||
|
||||
// mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins
|
||||
Map<uint64_t, Ref<FBXNode>> MeshNodes = Map<uint64_t, Ref<FBXNode>>();
|
||||
// mesh skin map
|
||||
Map<uint64_t, Ref<Skin>> MeshSkins = Map<uint64_t, Ref<Skin>>();
|
||||
|
||||
// this is the container for the mesh weight information and eventually
|
||||
// any mesh data
|
||||
// but not the skin, just stuff important for rendering
|
||||
// skin is applied to mesh instance so not really required to be in here yet.
|
||||
// maybe later
|
||||
// fbx mesh id, FBXMeshData
|
||||
Map<uint64_t, Ref<FBXMeshData>> renderer_mesh_data = Map<uint64_t, Ref<FBXMeshData>>();
|
||||
};
|
||||
|
||||
#endif // IMPORT_STATE_H
|
@ -1,52 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* model_abstraction.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MODEL_ABSTRACTION_H
|
||||
#define MODEL_ABSTRACTION_H
|
||||
|
||||
#include "modules/fbx/fbx_parser/FBXDocument.h"
|
||||
|
||||
struct ModelAbstraction {
|
||||
mutable const FBXDocParser::Model *fbx_model = nullptr;
|
||||
|
||||
void set_model(const FBXDocParser::Model *p_model) {
|
||||
fbx_model = p_model;
|
||||
}
|
||||
|
||||
bool has_model() const {
|
||||
return fbx_model != nullptr;
|
||||
}
|
||||
|
||||
const FBXDocParser::Model *get_model() const {
|
||||
return fbx_model;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MODEL_ABSTRACTION_H
|
@ -1,294 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* pivot_transform.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "pivot_transform.h"
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
void PivotTransform::ReadTransformChain() {
|
||||
const FBXDocParser::PropertyTable *props = fbx_model->Props();
|
||||
const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
|
||||
const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
|
||||
inherit_type = inheritType; // copy the inherit type we need it in the second step.
|
||||
print_verbose("Model: " + String(fbx_model->Name().c_str()) + " Has inherit type: " + itos(fbx_model->InheritType()));
|
||||
bool ok = false;
|
||||
raw_pre_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", ok));
|
||||
if (ok) {
|
||||
pre_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_pre_rotation));
|
||||
print_verbose("valid pre_rotation: " + raw_pre_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
raw_post_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", ok));
|
||||
if (ok) {
|
||||
post_rotation = ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder_EulerXYZ, ImportUtils::deg2rad(raw_post_rotation));
|
||||
print_verbose("valid post_rotation: " + raw_post_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
const Vector3 &RotationPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationPivot", ok));
|
||||
if (ok) {
|
||||
rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot);
|
||||
}
|
||||
const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationOffset", ok));
|
||||
if (ok) {
|
||||
rotation_offset = ImportUtils::FixAxisConversions(RotationOffset);
|
||||
}
|
||||
const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingOffset", ok));
|
||||
if (ok) {
|
||||
scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset);
|
||||
}
|
||||
const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingPivot", ok));
|
||||
if (ok) {
|
||||
scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot);
|
||||
}
|
||||
const Vector3 &Translation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Translation", ok));
|
||||
if (ok) {
|
||||
translation = ImportUtils::FixAxisConversions(Translation);
|
||||
}
|
||||
raw_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Rotation", ok));
|
||||
if (ok) {
|
||||
rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation));
|
||||
}
|
||||
const Vector3 &Scaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Scaling", ok));
|
||||
if (ok) {
|
||||
scaling = Scaling;
|
||||
}
|
||||
const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricScaling", ok));
|
||||
if (ok) {
|
||||
geometric_scaling = GeometricScaling;
|
||||
} else {
|
||||
geometric_scaling = Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricRotation", ok));
|
||||
if (ok) {
|
||||
geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation));
|
||||
} else {
|
||||
geometric_rotation = Quat();
|
||||
}
|
||||
|
||||
const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok));
|
||||
if (ok) {
|
||||
geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation);
|
||||
} else {
|
||||
geometric_translation = Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
if (geometric_rotation != Quat()) {
|
||||
print_error("geometric rotation is unsupported!");
|
||||
//CRASH_COND(true);
|
||||
}
|
||||
|
||||
if (!geometric_scaling.is_equal_approx(Vector3(1, 1, 1))) {
|
||||
print_error("geometric scaling is unsupported!");
|
||||
//CRASH_COND(true);
|
||||
}
|
||||
|
||||
if (!geometric_translation.is_equal_approx(Vector3(0, 0, 0))) {
|
||||
print_error("geometric translation is unsupported.");
|
||||
//CRASH_COND(true);
|
||||
}
|
||||
}
|
||||
|
||||
Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
|
||||
Transform T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(p_translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
S.scale(p_scaling);
|
||||
// Rotation pivots
|
||||
Transform Rpre = Transform(pre_rotation);
|
||||
Transform R = Transform(p_rotation);
|
||||
Transform Rpost = Transform(post_rotation);
|
||||
|
||||
return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
}
|
||||
|
||||
Transform PivotTransform::ComputeGlobalTransform(Transform t) const {
|
||||
Vector3 pos = t.origin;
|
||||
Vector3 scale = t.basis.get_scale();
|
||||
Quat rot = t.basis.get_rotation_quat();
|
||||
return ComputeGlobalTransform(pos, rot, scale);
|
||||
}
|
||||
|
||||
Transform PivotTransform::ComputeLocalTransform(Transform t) const {
|
||||
Vector3 pos = t.origin;
|
||||
Vector3 scale = t.basis.get_scale();
|
||||
Quat rot = t.basis.get_rotation_quat();
|
||||
return ComputeLocalTransform(pos, rot, scale);
|
||||
}
|
||||
|
||||
Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
|
||||
Transform T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(p_translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
S.scale(p_scaling);
|
||||
|
||||
// Rotation pivots
|
||||
Transform Rpre = Transform(pre_rotation);
|
||||
Transform R = Transform(p_rotation);
|
||||
Transform Rpost = Transform(post_rotation);
|
||||
|
||||
Transform parent_global_xform;
|
||||
Transform parent_local_scaling_m;
|
||||
|
||||
if (parent_transform.is_valid()) {
|
||||
parent_global_xform = parent_transform->GlobalTransform;
|
||||
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
|
||||
}
|
||||
|
||||
Transform local_rotation_m, parent_global_rotation_m;
|
||||
Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
|
||||
parent_global_rotation_m.basis.set_quat(parent_global_rotation);
|
||||
local_rotation_m = Rpre * R * Rpost;
|
||||
|
||||
//Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
|
||||
|
||||
Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
|
||||
Vector3 parent_translation = parent_global_xform.get_origin();
|
||||
parent_shear_translation.origin = parent_translation;
|
||||
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
|
||||
parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
|
||||
local_shear_scaling = S;
|
||||
|
||||
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
|
||||
Transform global_rotation_scale;
|
||||
if (inherit_type == FBXDocParser::Transform_RrSs) {
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
|
||||
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
|
||||
Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
|
||||
}
|
||||
Transform local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
//Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
|
||||
|
||||
// manual hack to force SSC not to be compensated for - until we can handle it properly with tests
|
||||
return parent_global_xform * local_transform;
|
||||
}
|
||||
|
||||
void PivotTransform::ComputePivotTransform() {
|
||||
Transform T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
if (!scaling.is_equal_approx(Vector3())) {
|
||||
S.scale(scaling);
|
||||
} else {
|
||||
S.scale(Vector3(1, 1, 1));
|
||||
}
|
||||
Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this.
|
||||
|
||||
// Rotation pivots
|
||||
Transform Rpre = Transform(pre_rotation);
|
||||
Transform R = Transform(rotation);
|
||||
Transform Rpost = Transform(post_rotation);
|
||||
|
||||
Transform parent_global_xform;
|
||||
Transform parent_local_scaling_m;
|
||||
|
||||
if (parent_transform.is_valid()) {
|
||||
parent_global_xform = parent_transform->GlobalTransform;
|
||||
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
|
||||
}
|
||||
|
||||
Transform local_rotation_m, parent_global_rotation_m;
|
||||
Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
|
||||
parent_global_rotation_m.basis.set_quat(parent_global_rotation);
|
||||
local_rotation_m = Rpre * R * Rpost;
|
||||
|
||||
//Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
|
||||
|
||||
Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
|
||||
Vector3 parent_translation = parent_global_xform.get_origin();
|
||||
parent_shear_translation.origin = parent_translation;
|
||||
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
|
||||
parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
|
||||
local_shear_scaling = S;
|
||||
|
||||
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
|
||||
Transform global_rotation_scale;
|
||||
if (inherit_type == FBXDocParser::Transform_RrSs) {
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
|
||||
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
|
||||
Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
|
||||
}
|
||||
LocalTransform = Transform();
|
||||
LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
|
||||
ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset");
|
||||
|
||||
Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
|
||||
GlobalTransform = Transform();
|
||||
//GlobalTransform = parent_global_xform * LocalTransform;
|
||||
Transform global_origin = Transform(Basis(), parent_translation);
|
||||
GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale;
|
||||
|
||||
ImportUtils::debug_xform("local xform calculation", LocalTransform);
|
||||
print_verbose("scale of node: " + S.basis.get_scale_local());
|
||||
print_verbose("---------------------------------------------------------------");
|
||||
}
|
||||
|
||||
void PivotTransform::Execute() {
|
||||
ReadTransformChain();
|
||||
ComputePivotTransform();
|
||||
|
||||
ImportUtils::debug_xform("global xform: ", GlobalTransform);
|
||||
computed_global_xform = true;
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* pivot_transform.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef PIVOT_TRANSFORM_H
|
||||
#define PIVOT_TRANSFORM_H
|
||||
|
||||
#include "core/math/transform.h"
|
||||
#include "core/reference.h"
|
||||
|
||||
#include "model_abstraction.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
enum TransformationComp {
|
||||
TransformationComp_Translation,
|
||||
TransformationComp_Scaling,
|
||||
TransformationComp_Rotation,
|
||||
TransformationComp_RotationOffset,
|
||||
TransformationComp_RotationPivot,
|
||||
TransformationComp_PreRotation,
|
||||
TransformationComp_PostRotation,
|
||||
TransformationComp_ScalingOffset,
|
||||
TransformationComp_ScalingPivot,
|
||||
TransformationComp_GeometricTranslation,
|
||||
TransformationComp_GeometricRotation,
|
||||
TransformationComp_GeometricScaling,
|
||||
TransformationComp_MAXIMUM
|
||||
};
|
||||
// Abstract away pivot data so its simpler to handle
|
||||
struct PivotTransform : Reference, ModelAbstraction {
|
||||
// at the end we want to keep geometric_ everything, post and pre rotation
|
||||
// these are used during animation data processing / keyframe ingestion the rest can be simplified down / out.
|
||||
Quat pre_rotation = Quat();
|
||||
Quat post_rotation = Quat();
|
||||
Quat rotation = Quat();
|
||||
Quat geometric_rotation = Quat();
|
||||
Vector3 rotation_pivot = Vector3();
|
||||
Vector3 rotation_offset = Vector3();
|
||||
Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 scaling_pivot = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 translation = Vector3();
|
||||
Vector3 scaling = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 geometric_scaling = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 geometric_translation = Vector3();
|
||||
|
||||
Vector3 raw_rotation = Vector3();
|
||||
Vector3 raw_post_rotation = Vector3();
|
||||
Vector3 raw_pre_rotation = Vector3();
|
||||
|
||||
/* Read pivots from the document */
|
||||
void ReadTransformChain();
|
||||
|
||||
void debug_pivot_xform(String p_name) {
|
||||
print_verbose("debugging node name: " + p_name);
|
||||
print_verbose("raw rotation: " + raw_rotation * (180 / Math_PI));
|
||||
print_verbose("raw pre_rotation " + raw_pre_rotation * (180 / Math_PI));
|
||||
print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI));
|
||||
}
|
||||
|
||||
Transform ComputeGlobalTransform(Transform t) const;
|
||||
Transform ComputeLocalTransform(Transform t) const;
|
||||
Transform ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
|
||||
Transform ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
|
||||
|
||||
/* Extract into xforms and calculate once */
|
||||
void ComputePivotTransform();
|
||||
|
||||
/* Execute the command for the pivot generation */
|
||||
void Execute();
|
||||
|
||||
void set_parent(Ref<PivotTransform> p_parent) {
|
||||
parent_transform = p_parent;
|
||||
}
|
||||
|
||||
bool computed_global_xform = false;
|
||||
Ref<PivotTransform> parent_transform = Ref<PivotTransform>();
|
||||
//Transform chain[TransformationComp_MAXIMUM];
|
||||
|
||||
// cached for later use
|
||||
Transform GlobalTransform = Transform();
|
||||
Transform LocalTransform = Transform();
|
||||
Transform Local_Scaling_Matrix = Transform(); // used for inherit type.
|
||||
Transform GeometricTransform = Transform(); // 3DS max only
|
||||
FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3
|
||||
};
|
||||
|
||||
#endif // PIVOT_TRANSFORM_H
|
@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorSceneImporterFBX" inherits="EditorSceneImporter" version="3.5">
|
||||
<brief_description>
|
||||
FBX 3D asset importer.
|
||||
</brief_description>
|
||||
<description>
|
||||
This is an FBX 3D asset importer with full support for most FBX features.
|
||||
If exporting a FBX scene from Autodesk Maya, use these FBX export settings:
|
||||
[codeblock]
|
||||
- Smoothing Groups
|
||||
- Smooth Mesh
|
||||
- Triangluate (for meshes with blend shapes)
|
||||
- Bake Animation
|
||||
- Resample All
|
||||
- Deformed Models
|
||||
- Skins
|
||||
- Blend Shapes
|
||||
- Curve Filters
|
||||
- Constant Key Reducer
|
||||
- Auto Tangents Only
|
||||
- *Do not check* Constraints (as it will break the file)
|
||||
- Can check Embed Media (embeds textures into the exported FBX file)
|
||||
- Note that when importing embedded media, the texture and mesh will be a single immutable file.
|
||||
- You will have to re-export then re-import the FBX if the texture has changed.
|
||||
- Units: Centimeters
|
||||
- Up Axis: Y
|
||||
- Binary format in FBX 2017
|
||||
[/codeblock]
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
</methods>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
File diff suppressed because it is too large
Load Diff
@ -1,137 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* editor_scene_importer_fbx.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORTER_FBX_H
|
||||
#define EDITOR_SCENE_IMPORTER_FBX_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "data/import_state.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
#include "core/bind/core_bind.h"
|
||||
#include "core/dictionary.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/local_vector.h"
|
||||
#include "core/ustring.h"
|
||||
#include "core/vector.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "scene/3d/skeleton.h"
|
||||
#include "scene/3d/spatial.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
#include "fbx_parser/FBXImportSettings.h"
|
||||
#include "fbx_parser/FBXMeshGeometry.h"
|
||||
#include "fbx_parser/FBXUtil.h"
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
class EditorSceneImporterFBX : public EditorSceneImporter {
|
||||
private:
|
||||
GDCLASS(EditorSceneImporterFBX, EditorSceneImporter);
|
||||
|
||||
struct AssetImportAnimation {
|
||||
enum Interpolation {
|
||||
INTERP_LINEAR,
|
||||
INTERP_STEP,
|
||||
INTERP_CATMULLROMSPLINE,
|
||||
INTERP_CUBIC_SPLINE
|
||||
};
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
const T *ProcessDOMConnection(
|
||||
const FBXDocParser::Document *doc,
|
||||
uint64_t current_element,
|
||||
bool reverse_lookup = false) {
|
||||
const std::vector<const FBXDocParser::Connection *> &conns = reverse_lookup ? doc->GetConnectionsByDestinationSequenced(current_element) : doc->GetConnectionsBySourceSequenced(current_element);
|
||||
//print_verbose("[doc] looking for " + String(element_to_find));
|
||||
// using the temp pattern here so we can debug before it returns
|
||||
// in some cases we return too early, with 'deformer object base class' in wrong place
|
||||
// in assimp this means we can accidentally return too early...
|
||||
const T *return_obj = nullptr;
|
||||
|
||||
for (const FBXDocParser::Connection *con : conns) {
|
||||
const FBXDocParser::Object *source_object = con->SourceObject();
|
||||
const FBXDocParser::Object *dest_object = con->DestinationObject();
|
||||
if (source_object && dest_object != nullptr) {
|
||||
//print_verbose("[doc] connection name: " + String(source_object->Name().c_str()) + ", dest: " + String(dest_object->Name().c_str()));
|
||||
const T *temp = dynamic_cast<const T *>(reverse_lookup ? source_object : dest_object);
|
||||
if (temp) {
|
||||
return_obj = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (return_obj != nullptr) {
|
||||
//print_verbose("[doc] returned valid element");
|
||||
//print_verbose("Found object for bone");
|
||||
return return_obj;
|
||||
}
|
||||
|
||||
// safe to return nothing, need to use nullptr here as nullptr is used internally for FBX document.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BuildDocumentBones(Ref<FBXBone> p_parent_bone,
|
||||
ImportState &state, const FBXDocParser::Document *p_doc,
|
||||
uint64_t p_id);
|
||||
|
||||
void BuildDocumentNodes(Ref<PivotTransform> parent_transform, ImportState &state, const FBXDocParser::Document *doc, uint64_t id, Ref<FBXNode> fbx_parent);
|
||||
|
||||
Spatial *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document,
|
||||
const uint32_t p_flags,
|
||||
int p_bake_fps,
|
||||
const uint32_t p_compress_flags,
|
||||
const int32_t p_max_bone_weights,
|
||||
bool p_is_blender_fbx);
|
||||
|
||||
template <class T>
|
||||
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
|
||||
void _register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const;
|
||||
|
||||
public:
|
||||
EditorSceneImporterFBX() {}
|
||||
~EditorSceneImporterFBX() {}
|
||||
|
||||
virtual void get_extensions(List<String> *r_extensions) const;
|
||||
virtual uint32_t get_import_flags() const;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, uint32_t p_compress_flags, List<String> *r_missing_deps, Error *r_err = nullptr);
|
||||
void create_mesh_data_skin(ImportState &state, const Ref<FBXNode> &fbx_node, uint64_t mesh_id);
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
#endif // EDITOR_SCENE_IMPORTER_FBX_H
|
@ -1,283 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* ByteSwapper.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Helper class to perform various byte order swappings
|
||||
(e.g. little to big endian) */
|
||||
#ifndef BYTE_SWAPPER_H
|
||||
#define BYTE_SWAPPER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
namespace FBXDocParser {
|
||||
// --------------------------------------------------------------------------------------
|
||||
/** Defines some useful byte order swap routines.
|
||||
*
|
||||
* This is required to read big-endian model formats on little-endian machines,
|
||||
* and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ByteSwap {
|
||||
ByteSwap() {}
|
||||
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap two bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap2(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[1]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap four bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap4(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[3]);
|
||||
std::swap(szOut[1], szOut[2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap eight bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap8(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[7]);
|
||||
std::swap(szOut[1], szOut[6]);
|
||||
std::swap(szOut[2], szOut[5]);
|
||||
std::swap(szOut[3], szOut[4]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a float. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(float *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a double. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(double *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int16t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int16_t *fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint16_t *fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int32t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int32_t *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint32_t *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int64t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int64_t *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint64_t *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
//! Templatized ByteSwap
|
||||
//! \returns param tOut as swapped
|
||||
template <typename Type>
|
||||
static inline Type Swapped(Type tOut) {
|
||||
return _swapper<Type, sizeof(Type)>()(tOut);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, size_t size>
|
||||
struct _swapper;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 2> {
|
||||
T operator()(T tOut) {
|
||||
Swap2(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 4> {
|
||||
T operator()(T tOut) {
|
||||
Swap4(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 8> {
|
||||
T operator()(T tOut) {
|
||||
Swap8(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ByteSwap macros for BigEndian/LittleEndian support
|
||||
// --------------------------------------------------------------------------------------
|
||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||
#define AI_LE(t) (t)
|
||||
#define AI_BE(t) ByteSwap::Swapped(t)
|
||||
#define AI_LSWAP2(p)
|
||||
#define AI_LSWAP4(p)
|
||||
#define AI_LSWAP8(p)
|
||||
#define AI_LSWAP2P(p)
|
||||
#define AI_LSWAP4P(p)
|
||||
#define AI_LSWAP8P(p)
|
||||
#define LE_NCONST const
|
||||
#define AI_SWAP2(p) ByteSwap::Swap2(&(p))
|
||||
#define AI_SWAP4(p) ByteSwap::Swap4(&(p))
|
||||
#define AI_SWAP8(p) ByteSwap::Swap8(&(p))
|
||||
#define AI_SWAP2P(p) ByteSwap::Swap2((p))
|
||||
#define AI_SWAP4P(p) ByteSwap::Swap4((p))
|
||||
#define AI_SWAP8P(p) ByteSwap::Swap8((p))
|
||||
#define BE_NCONST
|
||||
#else
|
||||
#define AI_BE(t) (t)
|
||||
#define AI_LE(t) ByteSwap::Swapped(t)
|
||||
#define AI_SWAP2(p)
|
||||
#define AI_SWAP4(p)
|
||||
#define AI_SWAP8(p)
|
||||
#define AI_SWAP2P(p)
|
||||
#define AI_SWAP4P(p)
|
||||
#define AI_SWAP8P(p)
|
||||
#define BE_NCONST const
|
||||
#define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
|
||||
#define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
|
||||
#define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
|
||||
#define AI_LSWAP2P(p) ByteSwap::Swap2((p))
|
||||
#define AI_LSWAP4P(p) ByteSwap::Swap4((p))
|
||||
#define AI_LSWAP8P(p) ByteSwap::Swap8((p))
|
||||
#define LE_NCONST
|
||||
#endif
|
||||
|
||||
namespace Intern {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <typename T, bool doit>
|
||||
struct ByteSwapper {
|
||||
void operator()(T *inout) {
|
||||
ByteSwap::Swap(inout);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwapper<T, false> {
|
||||
void operator()(T *) {
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess, typename T, bool RuntimeSwitch>
|
||||
struct Getter {
|
||||
void operator()(T *inout, bool le) {
|
||||
le = !le;
|
||||
if (le) {
|
||||
ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout);
|
||||
} else {
|
||||
ByteSwapper<T, false>()(inout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <bool SwapEndianess, typename T>
|
||||
struct Getter<SwapEndianess, T, false> {
|
||||
void operator()(T *inout, bool /*le*/) {
|
||||
// static branch
|
||||
ByteSwapper<T, (SwapEndianess && sizeof(T) > 1)>()(inout);
|
||||
}
|
||||
};
|
||||
} // namespace Intern
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // BYTE_SWAPPER_H
|
@ -1,183 +0,0 @@
|
||||
===============================================================
|
||||
Open Asset Import Library (Assimp)
|
||||
Developers and Contributors
|
||||
===============================================================
|
||||
|
||||
The following is a non-exhaustive list of all constributors over the years.
|
||||
If you think your name should be listed here, drop us a line and we'll add you.
|
||||
|
||||
- Alexander Gessler,
|
||||
3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design).
|
||||
|
||||
- Thomas Schulze,
|
||||
X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
|
||||
|
||||
- Kim Kulling,
|
||||
Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ).
|
||||
|
||||
- R.Schmidt,
|
||||
Linux build, eclipse support.
|
||||
|
||||
- Matthias Gubisch,
|
||||
Assimp.net
|
||||
Visual Studio 9 support, bugfixes.
|
||||
|
||||
- Mark Sibly
|
||||
B3D-Loader, Assimp testing
|
||||
|
||||
- Jonathan Klein
|
||||
Ogre Loader, VC2010 fixes and CMake fixes.
|
||||
|
||||
- Sebastian Hempel,
|
||||
PyAssimp (first version)
|
||||
Compile-Bugfixes for mingw, add environment for static library support in make.
|
||||
|
||||
- Jonathan Pokrass
|
||||
Supplied a bugfix concerning the scaling in the md3 loader.
|
||||
|
||||
- Andrew Galante,
|
||||
Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
|
||||
|
||||
- Andreas Nagel
|
||||
First Assimp testing & verification under Windows Vista 64 Bit.
|
||||
|
||||
- Marius Schr<68>der
|
||||
Allowed us to use many of his models for screenshots and testing.
|
||||
|
||||
- Christian Schubert
|
||||
Supplied various XFiles for testing purposes.
|
||||
|
||||
- Tizian Wieland
|
||||
Searched the web for hundreds of test models for internal use
|
||||
|
||||
- John Connors
|
||||
Supplied patches for linux and SCons.
|
||||
|
||||
- T. R.
|
||||
The GUY who performed some of the CSM mocaps.
|
||||
|
||||
- Andy Maloney
|
||||
Contributed fixes for the documentation and the doxygen markup
|
||||
|
||||
- Zhao Lei
|
||||
Contributed several bugfixes fixing memory leaks and improving float parsing
|
||||
|
||||
- sueastside
|
||||
Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date.
|
||||
|
||||
- Tobias Rittig
|
||||
Collada testing with Cinema 4D
|
||||
|
||||
- Brad Grantham
|
||||
Improvements in OpenGL-Sample.
|
||||
|
||||
- Robert Ramirez
|
||||
Add group loading feature to Obj-Loader.
|
||||
|
||||
- Chris Maiwald
|
||||
Many bugreports, improving Assimp's portability, regular testing & feedback.
|
||||
|
||||
- Stepan Hrbek
|
||||
Bugreport and fix for a obj-materialloader crash.
|
||||
|
||||
- David Nadlinger
|
||||
D bindings, CMake install support.
|
||||
|
||||
- Dario Accornero
|
||||
Contributed several patches regarding Mac OS/XCode targets, bug reports.
|
||||
|
||||
- Martin Walser (Samhayne)
|
||||
Contributed the 'SimpleTexturedOpenGl' sample.
|
||||
|
||||
- Matthias Fauconneau
|
||||
Contributed a fix for the Q3-BSP loader.
|
||||
|
||||
- Jørgen P. Tjernø
|
||||
Contributed updated and improved xcode workspaces
|
||||
|
||||
- drparallax
|
||||
Contributed the /samples/SimpleAssimpViewX sample
|
||||
|
||||
- Carsten Fuchs
|
||||
Contributed a fix for the Normalize method in aiQuaternion.
|
||||
|
||||
- dbburgess
|
||||
Contributes a Android-specific build issue: log the hardware architecture for ARM.
|
||||
|
||||
- alfiereinre7
|
||||
Contributes a obj-fileparser fix: missing tokens in the obj-token list.
|
||||
|
||||
- Roman Kharitonov
|
||||
Contributes a fix for the configure script environment.
|
||||
|
||||
- Ed Diana
|
||||
Contributed AssimpDelphi (/port/AssimpDelphi).
|
||||
|
||||
- rdb
|
||||
Contributes a bundle of fixes and improvements for the bsp-importer.
|
||||
|
||||
- Mick P
|
||||
For contributing the De-bone postprocessing step and filing various bug reports.
|
||||
|
||||
- Rosen Diankov
|
||||
Contributed patches to build assimp debian packages using cmake.
|
||||
|
||||
- Mark Page
|
||||
Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
|
||||
|
||||
- IOhannes
|
||||
Contributed the Debian build fixes ( architecture macro ).
|
||||
|
||||
- gellule
|
||||
Several LWO and LWS fixes (pivoting).
|
||||
|
||||
- Marcel Metz
|
||||
GCC/Linux fixes for the SimpleOpenGL sample.
|
||||
|
||||
- Brian Miller
|
||||
Bugfix for a compiler fix for iOS on arm.
|
||||
|
||||
- Séverin Lemaignan
|
||||
Rewrite of PyAssimp, distutils and Python3 support
|
||||
|
||||
- albert-wang
|
||||
Bugfixes for the collada parser
|
||||
|
||||
- Ya ping Jin
|
||||
Bugfixes for uv-tanget calculation.
|
||||
|
||||
- Jonne Nauha
|
||||
Ogre Binary format support
|
||||
|
||||
- Filip Wasil, Tieto Poland Sp. z o.o.
|
||||
Android JNI asset extraction support
|
||||
|
||||
- Richard Steffen
|
||||
Contributed ExportProperties interface
|
||||
Contributed X File exporter
|
||||
Contributed Step (stp) exporter
|
||||
|
||||
- Thomas Iorns (mesilliac)
|
||||
Initial FBX Export support
|
||||
|
||||
For a more detailed list just check: https://github.com/assimp/assimp/network/members
|
||||
|
||||
|
||||
========
|
||||
Patreons
|
||||
========
|
||||
|
||||
Huge thanks to our Patreons!
|
||||
|
||||
- migenius
|
||||
- Marcus
|
||||
- Cort
|
||||
- elect
|
||||
- Steffen
|
||||
|
||||
|
||||
===================
|
||||
Commercial Sponsors
|
||||
===================
|
||||
|
||||
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support
|
@ -1,291 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXAnimation.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXAnimation.cpp
|
||||
* @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode,
|
||||
* Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack
|
||||
*/
|
||||
|
||||
#include "FBXCommon.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document & /*doc*/) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr KeyTime = GetRequiredElement(sc, "KeyTime");
|
||||
const ElementPtr KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
|
||||
|
||||
// note preserved keys and values for legacy FBXConverter.cpp
|
||||
// we can remove this once the animation system is written
|
||||
// and clean up this code so we do not have copies everywhere.
|
||||
ParseVectorDataArray(keys, KeyTime);
|
||||
ParseVectorDataArray(values, KeyValueFloat);
|
||||
|
||||
if (keys.size() != values.size()) {
|
||||
DOMError("the number of key times does not match the number of keyframe values", KeyTime);
|
||||
}
|
||||
|
||||
// put the two lists into the map, underlying container is really just a dictionary
|
||||
// these will always match, if not an error will throw and the file will not import
|
||||
// this is useful because we then can report something and fix this later if it becomes an issue
|
||||
// at this point we do not need a different count of these elements so this makes the
|
||||
// most sense to do.
|
||||
for (size_t x = 0; x < keys.size(); x++) {
|
||||
keyvalues[keys[x]] = values[x];
|
||||
}
|
||||
|
||||
const ElementPtr KeyAttrDataFloat = sc->GetElement("KeyAttrDataFloat");
|
||||
if (KeyAttrDataFloat) {
|
||||
ParseVectorDataArray(attributes, KeyAttrDataFloat);
|
||||
}
|
||||
|
||||
const ElementPtr KeyAttrFlags = sc->GetElement("KeyAttrFlags");
|
||||
if (KeyAttrFlags) {
|
||||
ParseVectorDataArray(flags, KeyAttrFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::~AnimationCurve() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
|
||||
const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
|
||||
size_t whitelist_size /*= 0*/) :
|
||||
Object(id, element, name), target(), doc(doc) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// find target node
|
||||
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *object = con->DestinationObject();
|
||||
|
||||
if (!object) {
|
||||
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
target = object;
|
||||
prop = con->PropertyName();
|
||||
break;
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::~AnimationCurveNode() {
|
||||
curves.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationMap &AnimationCurveNode::Curves() const {
|
||||
/* Lazy loaded animation curves, will only load if required */
|
||||
if (curves.empty()) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// So the advantage of having this STL boilerplate is that it's dead simple once you get it.
|
||||
// The other advantage is casting is guaranteed to be safe and nullptr will be returned in the last step if it fails.
|
||||
Object *ob = con->SourceObject();
|
||||
AnimationCurve *anim_curve = dynamic_cast<AnimationCurve *>(ob);
|
||||
ERR_CONTINUE_MSG(!anim_curve, "Failed to convert animation curve from object");
|
||||
|
||||
curves.insert(std::make_pair(con->PropertyName(), anim_curve));
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name), doc(doc) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// note: the props table here bears little importance and is usually absent
|
||||
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::~AnimationLayer() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist,
|
||||
size_t whitelist_size /*= 0*/) const {
|
||||
AnimationCurveNodeList nodes;
|
||||
|
||||
// resolve attached animation nodes
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
|
||||
nodes.reserve(conns.size());
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurveNode *anim = dynamic_cast<AnimationCurveNode *>(ob);
|
||||
if (!anim) {
|
||||
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target_prop_whitelist) {
|
||||
const char *s = anim->TargetProperty().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes.push_back(anim);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
|
||||
props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
|
||||
|
||||
// resolve attached animation layers
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
|
||||
layers.reserve(conns.size());
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationLayer *anim = dynamic_cast<const AnimationLayer *>(ob);
|
||||
|
||||
if (!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
layers.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::~AnimationStack() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,423 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXBinaryTokenizer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
/** @file FBXBinaryTokenizer.cpp
|
||||
* @brief Implementation of a fake lexer for binary fbx files -
|
||||
* we emit tokens so the parser needs almost no special handling
|
||||
* for binary files.
|
||||
*/
|
||||
|
||||
#include "ByteSwapper.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FBXDocParser {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset) :
|
||||
sbegin(sbegin),
|
||||
send(send),
|
||||
type(type),
|
||||
line(offset),
|
||||
column(BINARY_MARKER) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
|
||||
#endif
|
||||
// calc length
|
||||
// measure from sBegin to sEnd and validate?
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// signal tokenization error
|
||||
void TokenizeError(const std::string &message, size_t offset) {
|
||||
print_error("[FBX-Tokenize] " + String(message.c_str()) + ", offset " + itos(offset));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Offset(const char *begin, const char *cursor) {
|
||||
//ai_assert(begin <= cursor);
|
||||
|
||||
return cursor - begin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string &message, const char *begin, const char *cursor) {
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t ReadWord(const char *input, const char *&cursor, const char *end) {
|
||||
const size_t k_to_read = sizeof(uint32_t);
|
||||
if (Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadWord, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint32_t word;
|
||||
::memcpy(&word, cursor, 4);
|
||||
AI_SWAP4(word);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint64_t ReadDoubleWord(const char *input, const char *&cursor, const char *end) {
|
||||
const size_t k_to_read = sizeof(uint64_t);
|
||||
if (Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadDoubleWord, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
|
||||
::memcpy(&dword, cursor, sizeof(uint64_t));
|
||||
AI_SWAP8(dword);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return dword;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint8_t ReadByte(const char *input, const char *&cursor, const char *end) {
|
||||
if (Offset(cursor, end) < sizeof(uint8_t)) {
|
||||
TokenizeError("cannot ReadByte, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint8_t word; /* = *reinterpret_cast< const uint8_t* >( cursor )*/
|
||||
::memcpy(&word, cursor, sizeof(uint8_t));
|
||||
++cursor;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const char *input,
|
||||
const char *&cursor, const char *end, bool long_length = false, bool allow_null = false) {
|
||||
const uint32_t len_len = long_length ? 4 : 1;
|
||||
if (Offset(cursor, end) < len_len) {
|
||||
TokenizeError("cannot ReadString, out of bounds reading length", input, cursor);
|
||||
}
|
||||
|
||||
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
|
||||
|
||||
if (Offset(cursor, end) < length) {
|
||||
TokenizeError("cannot ReadString, length is out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
sbegin_out = cursor;
|
||||
cursor += length;
|
||||
|
||||
send_out = cursor;
|
||||
|
||||
if (!allow_null) {
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
if (sbegin_out[i] == '\0') {
|
||||
TokenizeError("failed ReadString, unexpected NUL character in string", input, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) {
|
||||
if (Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
|
||||
}
|
||||
|
||||
const char type = *cursor;
|
||||
sbegin_out = cursor++;
|
||||
|
||||
switch (type) {
|
||||
// 16 bit int
|
||||
case 'Y':
|
||||
cursor += 2;
|
||||
break;
|
||||
|
||||
// 1 bit bool flag (yes/no)
|
||||
case 'C':
|
||||
cursor += 1;
|
||||
break;
|
||||
|
||||
// 32 bit int
|
||||
case 'I':
|
||||
// <- fall through
|
||||
|
||||
// float
|
||||
case 'F':
|
||||
cursor += 4;
|
||||
break;
|
||||
|
||||
// double
|
||||
case 'D':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// 64 bit int
|
||||
case 'L':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// note: do not write cursor += ReadWord(...cursor) as this would be UB
|
||||
|
||||
// raw binary data
|
||||
case 'R': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
cursor += length;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b':
|
||||
// TODO: what is the 'b' type code? Right now we just skip over it /
|
||||
// take the full range we could get
|
||||
cursor = end;
|
||||
break;
|
||||
|
||||
// array of *
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
case 'i':
|
||||
case 'c': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
const uint32_t encoding = ReadWord(input, cursor, end);
|
||||
|
||||
const uint32_t comp_len = ReadWord(input, cursor, end);
|
||||
|
||||
// compute length based on type and check against the stored value
|
||||
if (encoding == 0) {
|
||||
uint32_t stride = 0;
|
||||
switch (type) {
|
||||
case 'f':
|
||||
case 'i':
|
||||
stride = 4;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'l':
|
||||
stride = 8;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
stride = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
//ai_assert(stride > 0);
|
||||
if (length * stride != comp_len) {
|
||||
TokenizeError("cannot ReadData, calculated data stride differs from what the file claims", input, cursor);
|
||||
}
|
||||
}
|
||||
// zip/deflate algorithm (encoding==1)? take given length. anything else? die
|
||||
else if (encoding != 1) {
|
||||
TokenizeError("cannot ReadData, unknown encoding", input, cursor);
|
||||
}
|
||||
cursor += comp_len;
|
||||
break;
|
||||
}
|
||||
|
||||
// string
|
||||
case 'S': {
|
||||
const char *sb, *se;
|
||||
// 0 characters can legally happen in such strings
|
||||
ReadString(sb, se, input, cursor, end, true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
|
||||
}
|
||||
|
||||
if (cursor > end) {
|
||||
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
|
||||
}
|
||||
|
||||
// the type code is contained in the returned range
|
||||
send_out = cursor;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) {
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// we may get 0 if reading reached the end of the file -
|
||||
// fbx files have a mysterious extra footer which I don't know
|
||||
// how to extract any information from, but at least it always
|
||||
// starts with a 0.
|
||||
if (!end_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (end_offset > Offset(input, end)) {
|
||||
TokenizeError("block offset is out of range", input, cursor);
|
||||
} else if (end_offset < Offset(input, cursor)) {
|
||||
TokenizeError("block offset is negative out of range", input, cursor);
|
||||
}
|
||||
|
||||
// the second data word contains the number of properties in the scope
|
||||
const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// the third data word contains the length of the property list
|
||||
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// now comes the name of the scope/key
|
||||
const char *sbeg, *send;
|
||||
ReadString(sbeg, send, input, cursor, end);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
|
||||
|
||||
// now come the individual properties
|
||||
const char *begin_cursor = cursor;
|
||||
for (unsigned int i = 0; i < prop_count; ++i) {
|
||||
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
|
||||
|
||||
if (i != prop_count - 1) {
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Offset(begin_cursor, cursor) != prop_length) {
|
||||
TokenizeError("property length not reached, something is wrong", input, cursor);
|
||||
}
|
||||
|
||||
// at the end of each nested block, there is a NUL record to indicate
|
||||
// that the sub-scope exists (i.e. to distinguish between P: and P : {})
|
||||
// this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
|
||||
const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t) * 3 + 1) : (sizeof(uint32_t) * 3 + 1);
|
||||
|
||||
if (Offset(input, cursor) < end_offset) {
|
||||
if (end_offset - Offset(input, cursor) < sentinel_block_length) {
|
||||
TokenizeError("insufficient padding bytes at block end", input, cursor);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor)));
|
||||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while (Offset(input, cursor) < end_offset - sentinel_block_length) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
|
||||
|
||||
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
|
||||
if (cursor[i] != '\0') {
|
||||
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
|
||||
}
|
||||
}
|
||||
cursor += sentinel_block_length;
|
||||
}
|
||||
|
||||
if (Offset(input, cursor) != end_offset) {
|
||||
TokenizeError("scope length not reached, something is wrong", input, cursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) {
|
||||
if (length < 0x1b) {
|
||||
//TokenizeError("file is too short",0);
|
||||
}
|
||||
|
||||
if (strncmp(input, "Kaydara FBX Binary", 18)) {
|
||||
TokenizeError("magic bytes not found", 0);
|
||||
}
|
||||
|
||||
const char *cursor = input + 18;
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
const uint32_t version = ReadWord(input, cursor, input + length);
|
||||
print_verbose("FBX Version: " + itos(version));
|
||||
//ASSIMP_LOG_DEBUG_F("FBX version: ", version);
|
||||
const bool is64bits = version >= 7500;
|
||||
const char *end = input + length;
|
||||
while (cursor < end) {
|
||||
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,110 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXCommon.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXCommon.h
|
||||
* Some useful constants and enums for dealing with FBX files.
|
||||
*/
|
||||
#ifndef FBX_COMMON_H
|
||||
#define FBX_COMMON_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace FBXDocParser {
|
||||
const std::string NULL_RECORD = { // 13 null bytes
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
||||
}; // who knows why
|
||||
const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
|
||||
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||
|
||||
// rotation order. We'll probably use EulerXYZ for everything
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0,
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
|
||||
RotOrder_SphericXYZ,
|
||||
|
||||
RotOrder_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
Transform_RSrs = 1,
|
||||
Transform_Rrs = 2,
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_COMMON_H
|
@ -1,279 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDeformer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/math/transform.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::~Deformer() {
|
||||
}
|
||||
|
||||
Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
// used something.fbx as this is a cache name.
|
||||
props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true);
|
||||
}
|
||||
|
||||
Constraint::~Constraint() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name), valid_transformAssociateModel(false) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
// for( auto element : sc.Elements())
|
||||
// {
|
||||
// std::cout << "cluster element: " << element.first << std::endl;
|
||||
// }
|
||||
//
|
||||
// element: Indexes
|
||||
// element: Transform
|
||||
// element: TransformAssociateModel
|
||||
// element: TransformLink
|
||||
// element: UserData
|
||||
// element: Version
|
||||
// element: Weights
|
||||
|
||||
const ElementPtr Indexes = sc->GetElement("Indexes");
|
||||
const ElementPtr Weights = sc->GetElement("Weights");
|
||||
|
||||
const ElementPtr TransformAssociateModel = sc->GetElement("TransformAssociateModel");
|
||||
if (TransformAssociateModel != nullptr) {
|
||||
//Transform t = ReadMatrix(*TransformAssociateModel);
|
||||
link_mode = SkinLinkMode_Additive;
|
||||
valid_transformAssociateModel = true;
|
||||
} else {
|
||||
link_mode = SkinLinkMode_Normalized;
|
||||
valid_transformAssociateModel = false;
|
||||
}
|
||||
|
||||
const ElementPtr Transform = GetRequiredElement(sc, "Transform", element);
|
||||
const ElementPtr TransformLink = GetRequiredElement(sc, "TransformLink", element);
|
||||
|
||||
// todo: check if we need this
|
||||
//const Element& TransformAssociateModel = GetRequiredElement(sc, "TransformAssociateModel", &element);
|
||||
|
||||
transform = ReadMatrix(Transform);
|
||||
transformLink = ReadMatrix(TransformLink);
|
||||
|
||||
// it is actually possible that there be Deformer's with no weights
|
||||
if (!!Indexes != !!Weights) {
|
||||
DOMError("either Indexes or Weights are missing from Cluster", element);
|
||||
}
|
||||
|
||||
if (Indexes) {
|
||||
ParseVectorDataArray(indices, Indexes);
|
||||
ParseVectorDataArray(weights, Weights);
|
||||
}
|
||||
|
||||
if (indices.size() != weights.size()) {
|
||||
DOMError("sizes of index and weight array don't match up", element);
|
||||
}
|
||||
|
||||
// read assigned node
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Model");
|
||||
for (const Connection *con : conns) {
|
||||
const Model *mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
|
||||
if (mod) {
|
||||
node = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
DOMError("failed to read target Node for Cluster", element);
|
||||
node = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::~Cluster() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name), accuracy(0.0f) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// keep this it is used for debugging and any FBX format changes
|
||||
// for (auto element : sc.Elements()) {
|
||||
// std::cout << "skin element: " << element.first << std::endl;
|
||||
// }
|
||||
|
||||
const ElementPtr Link_DeformAcuracy = sc->GetElement("Link_DeformAcuracy");
|
||||
if (Link_DeformAcuracy) {
|
||||
accuracy = ParseTokenAsFloat(GetRequiredToken(Link_DeformAcuracy, 0));
|
||||
}
|
||||
|
||||
const ElementPtr SkinType = sc->GetElement("SkinningType");
|
||||
|
||||
if (SkinType) {
|
||||
std::string skin_type = ParseTokenAsString(GetRequiredToken(SkinType, 0));
|
||||
|
||||
if (skin_type == "Linear") {
|
||||
skinType = Skin_Linear;
|
||||
} else if (skin_type == "Rigid") {
|
||||
skinType = Skin_Rigid;
|
||||
} else if (skin_type == "DualQuaternion") {
|
||||
skinType = Skin_DualQuaternion;
|
||||
} else if (skin_type == "Blend") {
|
||||
skinType = Skin_Blend;
|
||||
} else {
|
||||
print_error("[doc:skin] could not find valid skin type: " + String(skin_type.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// resolve assigned clusters
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
|
||||
//
|
||||
|
||||
clusters.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const Cluster *cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
|
||||
if (cluster) {
|
||||
clusters.push_back(cluster);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::~Skin() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
blendShapeChannels.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const BlendShapeChannel *bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
|
||||
if (bspc) {
|
||||
blendShapeChannels.push_back(bspc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::~BlendShape() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr DeformPercent = sc->GetElement("DeformPercent");
|
||||
if (DeformPercent) {
|
||||
percent = ParseTokenAsFloat(GetRequiredToken(DeformPercent, 0));
|
||||
}
|
||||
const ElementPtr FullWeights = sc->GetElement("FullWeights");
|
||||
if (FullWeights) {
|
||||
ParseVectorDataArray(fullWeights, FullWeights);
|
||||
}
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
|
||||
shapeGeometries.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const ShapeGeometry *const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
|
||||
if (sg) {
|
||||
shapeGeometries.push_back(sg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::~BlendShapeChannel() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
} // namespace FBXDocParser
|
@ -1,714 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocument.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the*
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocument.cpp
|
||||
* @brief Implementation of the FBX DOM classes
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) :
|
||||
doc(doc), element(element), id(id), flags() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::~LazyObject() {
|
||||
object.reset();
|
||||
}
|
||||
|
||||
ObjectPtr LazyObject::LoadObject() {
|
||||
if (IsBeingConstructed() || FailedToConstruct()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (object) {
|
||||
return object.get();
|
||||
}
|
||||
|
||||
TokenPtr key = element->KeyToken();
|
||||
ERR_FAIL_COND_V(!key, nullptr);
|
||||
const TokenList &tokens = element->Tokens();
|
||||
|
||||
if (tokens.size() < 3) {
|
||||
//DOMError("expected at least 3 tokens: id, name and class tag",&element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *err = nullptr;
|
||||
std::string name = ParseTokenAsString(tokens[1], err);
|
||||
if (err) {
|
||||
DOMError(err, element);
|
||||
}
|
||||
|
||||
// small fix for binary reading: binary fbx files don't use
|
||||
// prefixes such as Model:: in front of their names. The
|
||||
// loading code expects this at many places, though!
|
||||
// so convert the binary representation (a 0x0001) to the
|
||||
// double colon notation.
|
||||
if (tokens[1]->IsBinary()) {
|
||||
for (size_t i = 0; i < name.length(); ++i) {
|
||||
if (name[i] == 0x0 && name[i + 1] == 0x1) {
|
||||
name = name.substr(i + 2) + "::" + name.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string classtag = ParseTokenAsString(tokens[2], err);
|
||||
if (err) {
|
||||
DOMError(err, element);
|
||||
}
|
||||
|
||||
// prevent recursive calls
|
||||
flags |= BEING_CONSTRUCTED;
|
||||
|
||||
// this needs to be relatively fast since it happens a lot,
|
||||
// so avoid constructing strings all the time.
|
||||
const char *obtype = key->begin();
|
||||
const size_t length = static_cast<size_t>(key->end() - key->begin());
|
||||
|
||||
if (!strncmp(obtype, "Pose", length)) {
|
||||
object.reset(new FbxPose(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Geometry", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Mesh")) {
|
||||
object.reset(new MeshGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Shape")) {
|
||||
object.reset(new ShapeGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Line")) {
|
||||
object.reset(new LineGeometry(id, element, name, doc));
|
||||
}
|
||||
} else if (!strncmp(obtype, "NodeAttribute", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Camera")) {
|
||||
object.reset(new Camera(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "CameraSwitcher")) {
|
||||
object.reset(new CameraSwitcher(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Light")) {
|
||||
object.reset(new Light(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Null")) {
|
||||
object.reset(new Null(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "LimbNode")) {
|
||||
// This is an older format for bones
|
||||
// this is what blender uses I believe
|
||||
object.reset(new LimbNode(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Constraint", length)) {
|
||||
object.reset(new Constraint(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Deformer", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Cluster")) {
|
||||
object.reset(new Cluster(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Skin")) {
|
||||
object.reset(new Skin(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "BlendShape")) {
|
||||
object.reset(new BlendShape(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
|
||||
object.reset(new BlendShapeChannel(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Model", length)) {
|
||||
// Model is normal node
|
||||
|
||||
// LimbNode model is a 'bone' node.
|
||||
if (!strcmp(classtag.c_str(), "LimbNode")) {
|
||||
object.reset(new ModelLimbNode(id, element, doc, name));
|
||||
|
||||
} else if (strcmp(classtag.c_str(), "IKEffector") && strcmp(classtag.c_str(), "FKEffector")) {
|
||||
// FK and IK effectors are not supported
|
||||
object.reset(new Model(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Material", length)) {
|
||||
object.reset(new Material(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Texture", length)) {
|
||||
object.reset(new Texture(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "LayeredTexture", length)) {
|
||||
object.reset(new LayeredTexture(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Video", length)) {
|
||||
object.reset(new Video(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "AnimationStack", length)) {
|
||||
object.reset(new AnimationStack(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationLayer", length)) {
|
||||
object.reset(new AnimationLayer(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationCurve", length)) {
|
||||
object.reset(new AnimationCurve(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationCurveNode", length)) {
|
||||
object.reset(new AnimationCurveNode(id, element, name, doc));
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(nullptr, "FBX contains unsupported object: " + String(obtype));
|
||||
}
|
||||
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
|
||||
return object.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
|
||||
element(element), name(name), id(id) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::~Object() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) :
|
||||
props(props), doc(doc) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::~FileGlobalSettings() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser &parser, const ImportSettings &settings) :
|
||||
settings(settings), parser(parser), SafeToImport(false) {
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
for (unsigned int &timeStamp : creationTimeStamp) {
|
||||
timeStamp = 0;
|
||||
}
|
||||
|
||||
// we must check if we can read the header version safely, if its outdated then drop it.
|
||||
if (ReadHeader()) {
|
||||
SafeToImport = true;
|
||||
ReadPropertyTemplates();
|
||||
|
||||
ReadGlobalSettings();
|
||||
|
||||
// This order is important, connections need parsed objects to check
|
||||
// whether connections are ok or not. Objects may not be evaluated yet,
|
||||
// though, since this may require valid connections.
|
||||
ReadObjects();
|
||||
ReadConnections();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document() {
|
||||
for (PropertyTemplateMap::value_type v : templates) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for (ObjectMap::value_type &v : objects) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for (ConnectionMap::value_type &v : src_connections) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
if (metadata_properties != nullptr) {
|
||||
delete metadata_properties;
|
||||
}
|
||||
// clear globals import pointer
|
||||
globals.reset();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int LowerSupportedVersion = 7300;
|
||||
static const unsigned int UpperSupportedVersion = 7700;
|
||||
|
||||
bool Document::ReadHeader() {
|
||||
// Read ID objects from "Objects" section
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr ehead = sc->GetElement("FBXHeaderExtension");
|
||||
if (!ehead || !ehead->Compound()) {
|
||||
DOMError("no FBXHeaderExtension dictionary found");
|
||||
}
|
||||
|
||||
const ScopePtr shead = ehead->Compound();
|
||||
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
|
||||
|
||||
// While we may have some success with newer files, we don't support
|
||||
// the older 6.n fbx format
|
||||
if (fbxVersion < LowerSupportedVersion) {
|
||||
DOMWarning("unsupported, old format version, FBX 2015-2020, you must re-export in a more modern version of your original modelling application");
|
||||
return false;
|
||||
}
|
||||
if (fbxVersion > UpperSupportedVersion) {
|
||||
DOMWarning("unsupported, newer format version, supported are only FBX 2015, up to FBX 2020"
|
||||
" trying to read it nevertheless");
|
||||
}
|
||||
|
||||
const ElementPtr ecreator = shead->GetElement("Creator");
|
||||
if (ecreator) {
|
||||
creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
|
||||
}
|
||||
|
||||
//
|
||||
// Scene Info
|
||||
//
|
||||
|
||||
const ElementPtr scene_info = shead->GetElement("SceneInfo");
|
||||
|
||||
if (scene_info) {
|
||||
PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true));
|
||||
|
||||
if (fileExportProps) {
|
||||
metadata_properties = fileExportProps;
|
||||
}
|
||||
}
|
||||
|
||||
const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
|
||||
if (etimestamp && etimestamp->Compound()) {
|
||||
const ScopePtr stimestamp = etimestamp->Compound();
|
||||
creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Year"), 0));
|
||||
creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Month"), 0));
|
||||
creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Day"), 0));
|
||||
creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Hour"), 0));
|
||||
creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Minute"), 0));
|
||||
creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Second"), 0));
|
||||
creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Millisecond"), 0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadGlobalSettings() {
|
||||
ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
|
||||
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr ehead = sc->GetElement("GlobalSettings");
|
||||
if (nullptr == ehead || !ehead->Compound()) {
|
||||
DOMWarning("no GlobalSettings dictionary found");
|
||||
globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable());
|
||||
return;
|
||||
}
|
||||
|
||||
const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true);
|
||||
|
||||
//double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 );
|
||||
|
||||
if (!props) {
|
||||
DOMError("GlobalSettings dictionary contains no property table");
|
||||
}
|
||||
|
||||
globals = std::make_shared<FileGlobalSettings>(*this, props);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadObjects() {
|
||||
// read ID objects from "Objects" section
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr eobjects = sc->GetElement("Objects");
|
||||
if (!eobjects || !eobjects->Compound()) {
|
||||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, eobjects, *this);
|
||||
|
||||
const ScopePtr sobjects = eobjects->Compound();
|
||||
for (const ElementMap::value_type &iter : sobjects->Elements()) {
|
||||
// extract ID
|
||||
const TokenList &tok = iter.second->Tokens();
|
||||
|
||||
if (tok.empty()) {
|
||||
DOMError("expected ID after object key", iter.second);
|
||||
}
|
||||
|
||||
const char *err;
|
||||
const uint64_t id = ParseTokenAsID(tok[0], err);
|
||||
if (err) {
|
||||
DOMError(err, iter.second);
|
||||
}
|
||||
|
||||
// id=0 is normally implicit
|
||||
if (id == 0L) {
|
||||
DOMError("encountered object with implicitly defined id 0", iter.second);
|
||||
}
|
||||
|
||||
if (objects.find(id) != objects.end()) {
|
||||
DOMWarning("encountered duplicate object id, ignoring first occurrence", iter.second);
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, iter.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if (!strcmp(iter.first.c_str(), "AnimationStack")) {
|
||||
animationStacks.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Constraint")) {
|
||||
constraints.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Pose")) {
|
||||
bind_poses.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Material")) {
|
||||
materials.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Deformer")) {
|
||||
TokenPtr key = iter.second->KeyToken();
|
||||
ERR_CONTINUE_MSG(!key, "[parser bug] invalid token key for deformer");
|
||||
const TokenList &tokens = iter.second->Tokens();
|
||||
const std::string class_tag = ParseTokenAsString(tokens[2], err);
|
||||
|
||||
if (err) {
|
||||
DOMError(err, iter.second);
|
||||
}
|
||||
|
||||
if (class_tag == "Skin") {
|
||||
//print_verbose("registered skin:" + itos(id));
|
||||
skins.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadPropertyTemplates() {
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const ElementPtr edefs = sc->GetElement("Definitions");
|
||||
if (!edefs || !edefs->Compound()) {
|
||||
DOMWarning("no Definitions dictionary found");
|
||||
return;
|
||||
}
|
||||
|
||||
const ScopePtr sdefs = edefs->Compound();
|
||||
const ElementCollection otypes = sdefs->GetCollection("ObjectType");
|
||||
for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
||||
const ElementPtr el = (*it).second;
|
||||
const ScopePtr sc_2 = el->Compound();
|
||||
if (!sc_2) {
|
||||
DOMWarning("expected nested scope in ObjectType, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList &tok = el->Tokens();
|
||||
if (tok.empty()) {
|
||||
DOMWarning("expected name for ObjectType element, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &oname = ParseTokenAsString(tok[0]);
|
||||
|
||||
const ElementCollection templs = sc_2->GetCollection("PropertyTemplate");
|
||||
for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) {
|
||||
const ElementPtr el_2 = (*iter).second;
|
||||
const ScopePtr sc_3 = el_2->Compound();
|
||||
if (!sc_3) {
|
||||
DOMWarning("expected nested scope in PropertyTemplate, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList &tok_2 = el_2->Tokens();
|
||||
if (tok_2.empty()) {
|
||||
DOMWarning("expected name for PropertyTemplate element, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &pname = ParseTokenAsString(tok_2[0]);
|
||||
|
||||
const ElementPtr Properties70 = sc_3->GetElement("Properties70");
|
||||
if (Properties70) {
|
||||
// PropertyTable(const ElementPtr element, const PropertyTable* templateProps);
|
||||
const PropertyTable *props = new PropertyTable(Properties70, nullptr);
|
||||
|
||||
templates[oname + "." + pname] = props;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections() {
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
|
||||
// read property templates from "Definitions" section
|
||||
const ElementPtr econns = sc->GetElement("Connections");
|
||||
if (!econns || !econns->Compound()) {
|
||||
DOMError("no Connections dictionary found");
|
||||
}
|
||||
|
||||
uint64_t insertionOrder = 0l;
|
||||
const ScopePtr sconns = econns->Compound();
|
||||
const ElementCollection conns = sconns->GetCollection("C");
|
||||
for (ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||
const ElementPtr el = (*it).second;
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(el, 0));
|
||||
|
||||
// PP = property-property connection, ignored for now
|
||||
// (tokens: "PP", ID1, "Property1", ID2, "Property2")
|
||||
if (type == "PP") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el, 1));
|
||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el, 2));
|
||||
|
||||
// OO = object-object connection
|
||||
// OP = object-property connection, in which case the destination property follows the object ID
|
||||
const std::string &prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el, 3)) : "");
|
||||
|
||||
if (objects.find(src) == objects.end()) {
|
||||
DOMWarning("source object for connection does not exist", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// dest may be 0 (root node) but we added a dummy object before
|
||||
if (objects.find(dest) == objects.end()) {
|
||||
DOMWarning("destination object for connection does not exist", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add new connection
|
||||
const Connection *const c = new Connection(insertionOrder++, src, dest, prop, *this);
|
||||
src_connections.insert(ConnectionMap::value_type(src, c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest, c));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const AnimationStack *> &Document::AnimationStacks() const {
|
||||
if (!animationStacksResolved.empty() || animationStacks.empty()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
animationStacksResolved.reserve(animationStacks.size());
|
||||
for (uint64_t id : animationStacks) {
|
||||
LazyObject *lazy = GetObject(id);
|
||||
|
||||
// Two things happen here:
|
||||
// We cast internally an Object PTR to an Animation Stack PTR
|
||||
// We return invalid weak_ptrs for objects which are invalid
|
||||
|
||||
const AnimationStack *stack = lazy->Get<AnimationStack>();
|
||||
ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure");
|
||||
|
||||
// We push back the weak reference :) to keep things simple, as ownership is on the parser side so it won't be cleaned up.
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Document::GetObject(uint64_t id) const {
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
#define MAX_CLASSNAMES 6
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap &conns) const {
|
||||
std::vector<const Connection *> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first, range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
|
||||
const ConnectionMap &conns,
|
||||
const char *const *classnames,
|
||||
size_t count) const
|
||||
|
||||
{
|
||||
size_t lengths[MAX_CLASSNAMES];
|
||||
|
||||
const size_t c = count;
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
lengths[i] = strlen(classnames[i]);
|
||||
}
|
||||
|
||||
std::vector<const Connection *> temp;
|
||||
const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first, range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
TokenPtr key = (is_src ? (*it).second->LazyDestinationObject() : (*it).second->LazySourceObject())->GetElement()->KeyToken();
|
||||
|
||||
const char *obtype = key->begin();
|
||||
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
//ai_assert(classnames[i]);
|
||||
if (static_cast<size_t>(std::distance(key->begin(), key->end())) == lengths[i] && !strncmp(classnames[i], obtype, lengths[i])) {
|
||||
obtype = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (obtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source) const {
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t src, const char *classname) const {
|
||||
const char *arr[] = { classname };
|
||||
return GetConnectionsBySourceSequenced(src, arr, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source,
|
||||
const char *const *classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(), classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char *classname) const {
|
||||
const char *arr[] = { classname };
|
||||
return GetConnectionsByDestinationSequenced(dest, arr, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char *const *classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(), classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop,
|
||||
const Document &doc) :
|
||||
insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::~Connection() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Connection::LazySourceObject() const {
|
||||
LazyObject *const lazy = doc.GetObject(src);
|
||||
return lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Connection::LazyDestinationObject() const {
|
||||
LazyObject *const lazy = doc.GetObject(dest);
|
||||
return lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object *Connection::SourceObject() const {
|
||||
LazyObject *lazy = doc.GetObject(src);
|
||||
//ai_assert(lazy);
|
||||
return lazy->LoadObject();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object *Connection::DestinationObject() const {
|
||||
LazyObject *lazy = doc.GetObject(dest);
|
||||
//ai_assert(lazy);
|
||||
return lazy->LoadObject();
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocumentUtil.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.cpp
|
||||
* @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
|
||||
*/
|
||||
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
void DOMError(const std::string &message) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const Token *token) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Token> token) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const Element *element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMError(message, element->KeyToken());
|
||||
}
|
||||
print_error("[FBX-DOM] " + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMError(message, element->KeyToken());
|
||||
}
|
||||
print_error("[FBX-DOM] " + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const Token *token) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const Element *element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMWarning(message, element->KeyToken());
|
||||
return;
|
||||
}
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMWarning(message, element->KeyToken());
|
||||
return;
|
||||
}
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// fetch a property table and the corresponding property template
|
||||
const PropertyTable *GetPropertyTable(const Document &doc,
|
||||
const std::string &templateName,
|
||||
const ElementPtr element,
|
||||
const ScopePtr sc,
|
||||
bool no_warn /*= false*/) {
|
||||
// todo: make this an abstraction
|
||||
const ElementPtr Properties70 = sc->GetElement("Properties70");
|
||||
const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr);
|
||||
|
||||
if (templateName.length()) {
|
||||
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
||||
if (it != doc.Templates().end()) {
|
||||
templateProps = (*it).second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Properties70 || !Properties70->Compound()) {
|
||||
if (!no_warn) {
|
||||
DOMWarning("property table (Properties70) not found", element);
|
||||
}
|
||||
if (templateProps) {
|
||||
return new const PropertyTable(templateProps);
|
||||
} else {
|
||||
return new const PropertyTable();
|
||||
}
|
||||
}
|
||||
|
||||
return new PropertyTable(Properties70, templateProps);
|
||||
}
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
@ -1,142 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocumentUtil.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.h
|
||||
* @brief FBX internal utilities used by the DOM reading code
|
||||
*/
|
||||
#ifndef FBX_DOCUMENT_UTIL_H
|
||||
#define FBX_DOCUMENT_UTIL_H
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct Token;
|
||||
struct Element;
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
// Parser errors
|
||||
void DOMError(const std::string &message);
|
||||
void DOMError(const std::string &message, const Token *token);
|
||||
void DOMError(const std::string &message, const Element *element);
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Element> element);
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Token> token);
|
||||
|
||||
// Parser warnings
|
||||
void DOMWarning(const std::string &message);
|
||||
void DOMWarning(const std::string &message, const Token *token);
|
||||
void DOMWarning(const std::string &message, const Element *element);
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
|
||||
|
||||
// fetch a property table and the corresponding property template
|
||||
const PropertyTable *GetPropertyTable(const Document &doc,
|
||||
const std::string &templateName,
|
||||
const ElementPtr element,
|
||||
const ScopePtr sc,
|
||||
bool no_warn = false);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
const T *ProcessSimpleConnection(const Connection &con,
|
||||
bool is_object_property_conn,
|
||||
const char *name,
|
||||
const ElementPtr element,
|
||||
const char **propNameOut = nullptr) {
|
||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-object connection, ignoring",
|
||||
element);
|
||||
return nullptr;
|
||||
} else if (!is_object_property_conn && con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-property connection, ignoring",
|
||||
element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (is_object_property_conn && propNameOut) {
|
||||
// note: this is ok, the return value of PropertyValue() is guaranteed to
|
||||
// remain valid and unchanged as long as the document exists.
|
||||
*propNameOut = con.PropertyName().c_str();
|
||||
}
|
||||
|
||||
// Cast Object to AnimationPlayer for example using safe functions, which return nullptr etc
|
||||
Object *ob = con.SourceObject();
|
||||
ERR_FAIL_COND_V_MSG(!ob, nullptr, "Failed to load object from SourceObject ptr");
|
||||
return dynamic_cast<const T *>(ob);
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_DOCUMENT_UTIL_H
|
@ -1,174 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXImportSettings.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImportSettings.h
|
||||
* @brief FBX importer runtime configuration
|
||||
*/
|
||||
#ifndef FBX_IMPORT_SETTINGS_H
|
||||
#define FBX_IMPORT_SETTINGS_H
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
|
||||
struct ImportSettings {
|
||||
ImportSettings() :
|
||||
strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) {
|
||||
// empty
|
||||
}
|
||||
|
||||
/** enable strict mode:
|
||||
* - only accept fbx 2012, 2013 files
|
||||
* - on the slightest error, give up.
|
||||
*
|
||||
* Basically, strict mode means that the fbx file will actually
|
||||
* be validated. Strict mode is off by default. */
|
||||
bool strictMode;
|
||||
|
||||
/** specifies whether all geometry layers are read and scanned for
|
||||
* usable data channels. The FBX spec indicates that many readers
|
||||
* will only read the first channel and that this is in some way
|
||||
* the recommended way- in reality, however, it happens a lot that
|
||||
* vertex data is spread among multiple layers. The default
|
||||
* value for this option is true.*/
|
||||
bool readAllLayers;
|
||||
|
||||
/** specifies whether all materials are read, or only those that
|
||||
* are referenced by at least one mesh. Reading all materials
|
||||
* may make FBX reading a lot slower since all objects
|
||||
* need to be processed .
|
||||
* This bit is ignored unless readMaterials=true*/
|
||||
bool readAllMaterials;
|
||||
|
||||
/** import materials (true) or skip them and assign a default
|
||||
* material. The default value is true.*/
|
||||
bool readMaterials;
|
||||
|
||||
/** import embedded textures? Default value is true.*/
|
||||
bool readTextures;
|
||||
|
||||
/** import cameras? Default value is true.*/
|
||||
bool readCameras;
|
||||
|
||||
/** import light sources? Default value is true.*/
|
||||
bool readLights;
|
||||
|
||||
/** import animations (i.e. animation curves, the node
|
||||
* skeleton is always imported). Default value is true. */
|
||||
bool readAnimations;
|
||||
|
||||
/** read bones (vertex weights and deform info).
|
||||
* Default value is true. */
|
||||
bool readWeights;
|
||||
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
* can make animation import a lot slower. The default value
|
||||
* is true.
|
||||
*
|
||||
* The naming scheme for the generated nodes is:
|
||||
* <OriginalName>_$AssimpFbx$_<TransformName>
|
||||
*
|
||||
* where <TransformName> is one of
|
||||
* RotationPivot
|
||||
* RotationOffset
|
||||
* PreRotation
|
||||
* PostRotation
|
||||
* ScalingPivot
|
||||
* ScalingOffset
|
||||
* Translation
|
||||
* Scaling
|
||||
* Rotation
|
||||
**/
|
||||
bool preservePivots;
|
||||
|
||||
/** do not import animation curves that specify a constant
|
||||
* values matching the corresponding node transformation.
|
||||
* The default value is true. */
|
||||
bool optimizeEmptyAnimationCurves;
|
||||
|
||||
/** use legacy naming for embedded textures eg: (*0, *1, *2)
|
||||
*/
|
||||
bool useLegacyEmbeddedTextureNaming;
|
||||
|
||||
/** Empty bones shall be removed
|
||||
*/
|
||||
bool removeEmptyBones;
|
||||
|
||||
/** Set to true to perform a conversion from cm to meter after the import
|
||||
*/
|
||||
bool convertToMeters;
|
||||
};
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_IMPORT_SETTINGS_H
|
@ -1,407 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMaterial.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMaterial.cpp
|
||||
* @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
|
||||
*/
|
||||
|
||||
#include "ByteSwapper.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include <algorithm> // std::transform
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr ShadingModel = sc->GetElement("ShadingModel");
|
||||
const ElementPtr MultiLayer = sc->GetElement("MultiLayer");
|
||||
|
||||
if (MultiLayer) {
|
||||
multilayer = !!ParseTokenAsInt(GetRequiredToken(MultiLayer, 0));
|
||||
}
|
||||
|
||||
if (ShadingModel) {
|
||||
shading = ParseTokenAsString(GetRequiredToken(ShadingModel, 0));
|
||||
} else {
|
||||
DOMWarning("shading mode not specified, assuming phong", element);
|
||||
shading = "phong";
|
||||
}
|
||||
|
||||
std::string templateName;
|
||||
|
||||
if (shading == "phong") {
|
||||
templateName = "Material.Phong";
|
||||
} else if (shading == "lambert") {
|
||||
templateName = "Material.Lambert";
|
||||
} else if (shading == "unknown") {
|
||||
templateName = "Material.StingRay";
|
||||
} else {
|
||||
DOMWarning("shading mode not recognized: " + shading, element);
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, templateName, element, sc);
|
||||
|
||||
// resolve texture links
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (const Connection *con : conns) {
|
||||
// texture link to properties, not objects
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture *tex = dynamic_cast<const Texture *>(ob);
|
||||
if (!tex) {
|
||||
LayeredTexture *layeredTexture = dynamic_cast<LayeredTexture *>(ob);
|
||||
|
||||
if (!layeredTexture) {
|
||||
DOMWarning("source object for texture link is not a texture or layered texture, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &prop = con->PropertyName();
|
||||
if (layeredTextures.find(prop) != layeredTextures.end()) {
|
||||
DOMWarning("duplicate layered texture link: " + prop, element);
|
||||
}
|
||||
|
||||
layeredTextures[prop] = layeredTexture;
|
||||
layeredTexture->fillTexture(doc);
|
||||
} else {
|
||||
const std::string &prop = con->PropertyName();
|
||||
if (textures.find(prop) != textures.end()) {
|
||||
DOMWarning("duplicate texture link: " + prop, element);
|
||||
}
|
||||
|
||||
textures[prop] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::~Material() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr Type = sc->GetElement("Type");
|
||||
const ElementPtr FileName = sc->GetElement("FileName");
|
||||
const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
|
||||
const ElementPtr ModelUVTranslation = sc->GetElement("ModelUVTranslation");
|
||||
const ElementPtr ModelUVScaling = sc->GetElement("ModelUVScaling");
|
||||
const ElementPtr Texture_Alpha_Source = sc->GetElement("Texture_Alpha_Source");
|
||||
const ElementPtr Cropping = sc->GetElement("Cropping");
|
||||
|
||||
if (Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
}
|
||||
|
||||
if (FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
|
||||
}
|
||||
|
||||
if (RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
|
||||
}
|
||||
|
||||
if (ModelUVTranslation) {
|
||||
uvTrans = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 1)));
|
||||
}
|
||||
|
||||
if (ModelUVScaling) {
|
||||
uvScaling = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 1)));
|
||||
}
|
||||
|
||||
if (Cropping) {
|
||||
crop[0] = ParseTokenAsInt(GetRequiredToken(Cropping, 0));
|
||||
crop[1] = ParseTokenAsInt(GetRequiredToken(Cropping, 1));
|
||||
crop[2] = ParseTokenAsInt(GetRequiredToken(Cropping, 2));
|
||||
crop[3] = ParseTokenAsInt(GetRequiredToken(Cropping, 3));
|
||||
} else {
|
||||
// vc8 doesn't support the crop() syntax in initialization lists
|
||||
// (and vc9 WARNS about the new (i.e. compliant) behaviour).
|
||||
crop[0] = crop[1] = crop[2] = crop[3] = 0;
|
||||
}
|
||||
|
||||
if (Texture_Alpha_Source) {
|
||||
alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc);
|
||||
|
||||
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
|
||||
bool ok;
|
||||
const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok);
|
||||
if (ok) {
|
||||
uvScaling.x = scaling.x;
|
||||
uvScaling.y = scaling.y;
|
||||
}
|
||||
|
||||
const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok);
|
||||
if (ok) {
|
||||
uvTrans.x = trans.x;
|
||||
uvTrans.y = trans.y;
|
||||
}
|
||||
|
||||
// resolve video links
|
||||
if (doc.Settings().readTextures) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (const Connection *con : conns) {
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Video *const video = dynamic_cast<const Video *>(ob);
|
||||
if (video) {
|
||||
media = video;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
|
||||
Object(id, element, name), blendMode(BlendMode_Modulate), alpha(1) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
ElementPtr BlendModes = sc->GetElement("BlendModes");
|
||||
ElementPtr Alphas = sc->GetElement("Alphas");
|
||||
|
||||
if (BlendModes != nullptr) {
|
||||
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0));
|
||||
}
|
||||
if (Alphas != nullptr) {
|
||||
alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0));
|
||||
}
|
||||
}
|
||||
|
||||
LayeredTexture::~LayeredTexture() {
|
||||
}
|
||||
|
||||
void LayeredTexture::fillTexture(const Document &doc) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (size_t i = 0; i < conns.size(); ++i) {
|
||||
const Connection *con = conns.at(i);
|
||||
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture *const tex = dynamic_cast<const Texture *>(ob);
|
||||
|
||||
textures.push_back(tex);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), contentLength(0), content(nullptr) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr Type = sc->GetElement("Type");
|
||||
// File Version 7500 Crashes if this is not checked fully.
|
||||
// As of writing this comment 7700 exists, in August 2020
|
||||
ElementPtr FileName = nullptr;
|
||||
if (HasElement(sc, "Filename")) {
|
||||
FileName = (ElementPtr)sc->GetElement("Filename");
|
||||
} else if (HasElement(sc, "FileName")) {
|
||||
FileName = (ElementPtr)sc->GetElement("FileName");
|
||||
} else {
|
||||
print_error("file has invalid video material returning...");
|
||||
return;
|
||||
}
|
||||
const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
|
||||
const ElementPtr Content = sc->GetElement("Content");
|
||||
|
||||
if (Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
}
|
||||
|
||||
if (FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
|
||||
}
|
||||
|
||||
if (RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
|
||||
}
|
||||
|
||||
if (Content && !Content->Tokens().empty()) {
|
||||
//this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
|
||||
try {
|
||||
const Token *token = GetRequiredToken(Content, 0);
|
||||
const char *data = token->begin();
|
||||
if (!token->IsBinary()) {
|
||||
if (*data != '"') {
|
||||
DOMError("embedded content is not surrounded by quotation marks", element);
|
||||
} else {
|
||||
size_t targetLength = 0;
|
||||
auto numTokens = Content->Tokens().size();
|
||||
// First time compute size (it could be large like 64Gb and it is good to allocate it once)
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
|
||||
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
|
||||
size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
|
||||
const char *base64data = dataToken->begin() + 1;
|
||||
const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
|
||||
if (outLength == 0) {
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
targetLength += outLength;
|
||||
}
|
||||
if (targetLength == 0) {
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
content = new uint8_t[targetLength];
|
||||
contentLength = static_cast<uint64_t>(targetLength);
|
||||
size_t dst_offset = 0;
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
|
||||
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
|
||||
ERR_FAIL_COND(!dataToken);
|
||||
size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
|
||||
const char *base64data = dataToken->begin() + 1;
|
||||
dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
|
||||
}
|
||||
if (targetLength != dst_offset) {
|
||||
delete[] content;
|
||||
contentLength = 0;
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
}
|
||||
} else if (static_cast<size_t>(token->end() - data) < 5) {
|
||||
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", element);
|
||||
} else if (*data != 'R') {
|
||||
DOMWarning("video content is not raw binary data, ignoring", element);
|
||||
} else {
|
||||
// read number of elements
|
||||
uint32_t len = 0;
|
||||
::memcpy(&len, data + 1, sizeof(len));
|
||||
AI_SWAP4(len);
|
||||
|
||||
contentLength = len;
|
||||
|
||||
content = new uint8_t[len];
|
||||
::memcpy(content, data + 5, len);
|
||||
}
|
||||
} catch (...) {
|
||||
// //we don't need the content data for contents that has already been loaded
|
||||
// ASSIMP_LOG_VERBOSE_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ",
|
||||
// runtimeError.what());
|
||||
}
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "Video.FbxVideo", element, sc);
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
if (content) {
|
||||
delete[] content;
|
||||
}
|
||||
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,486 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMeshGeometry.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMeshGeometry.cpp
|
||||
* @brief Assimp::FBX::MeshGeometry implementation
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name), skin() {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
for (const Connection *con : conns) {
|
||||
const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if (sk) {
|
||||
skin = sk;
|
||||
}
|
||||
const BlendShape *bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry",
|
||||
element);
|
||||
if (bsp) {
|
||||
blendShapes.push_back(bsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::~Geometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const BlendShape *> &Geometry::get_blend_shapes() const {
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Skin *Geometry::DeformerSkin() const {
|
||||
return skin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
print_verbose("mesh name: " + String(name.c_str()));
|
||||
|
||||
ScopePtr sc = element->Compound();
|
||||
ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash");
|
||||
ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertices, didn't populate the mesh");
|
||||
|
||||
// must have Mesh elements:
|
||||
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
|
||||
const ElementPtr PolygonVertexIndex = GetRequiredElement(sc, "PolygonVertexIndex", element);
|
||||
|
||||
if (HasElement(sc, "Edges")) {
|
||||
const ElementPtr element_edges = GetRequiredElement(sc, "Edges", element);
|
||||
ParseVectorDataArray(m_edges, element_edges);
|
||||
}
|
||||
|
||||
// read mesh data into arrays
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_face_indices, PolygonVertexIndex);
|
||||
|
||||
ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertices in FBX file, did you mean to delete it?");
|
||||
ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?");
|
||||
|
||||
// Retrieve layer elements, for all of the mesh
|
||||
const ElementCollection &Layer = sc->GetCollection("Layer");
|
||||
|
||||
// Store all layers
|
||||
std::vector<std::tuple<int, std::string>> valid_layers;
|
||||
|
||||
// now read the sub mesh information from the geometry (normals, uvs, etc)
|
||||
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
|
||||
const ScopePtr layer = GetRequiredScope(it->second);
|
||||
const ElementCollection &LayerElement = layer->GetCollection("LayerElement");
|
||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||
std::string layer_name = eit->first;
|
||||
ElementPtr element_layer = eit->second;
|
||||
const ScopePtr layer_element = GetRequiredScope(element_layer);
|
||||
|
||||
// Actual usable 'type' LayerElementUV, LayerElementNormal, etc
|
||||
const ElementPtr Type = GetRequiredElement(layer_element, "Type");
|
||||
const ElementPtr TypedIndex = GetRequiredElement(layer_element, "TypedIndex");
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
|
||||
|
||||
// we only need the layer name and the typed index.
|
||||
valid_layers.push_back(std::tuple<int, std::string>(typedIndex, type));
|
||||
}
|
||||
}
|
||||
|
||||
// get object / mesh directly from the FBX by the element ID.
|
||||
const ScopePtr top = GetRequiredScope(element);
|
||||
|
||||
// iterate over all layers for the mesh (uvs, normals, smoothing groups, colors, etc)
|
||||
for (size_t x = 0; x < valid_layers.size(); x++) {
|
||||
const int layer_id = std::get<0>(valid_layers[x]);
|
||||
const std::string &layer_type_name = std::get<1>(valid_layers[x]);
|
||||
|
||||
// Get collection of elements from the XLayerMap (example: LayerElementUV)
|
||||
// this must contain our proper elements.
|
||||
|
||||
// This is stupid, because it means we select them ALL not just the one we want.
|
||||
// but it's fine we can match by id.
|
||||
|
||||
const ElementCollection &candidates = top->GetCollection(layer_type_name);
|
||||
|
||||
ElementMap::const_iterator iter;
|
||||
for (iter = candidates.first; iter != candidates.second; ++iter) {
|
||||
const ScopePtr layer_scope = GetRequiredScope(iter->second);
|
||||
TokenPtr layer_token = GetRequiredToken(iter->second, 0);
|
||||
const int index = ParseTokenAsInt(layer_token);
|
||||
|
||||
ERR_FAIL_COND_MSG(layer_scope == nullptr, "prevented crash, layer scope is invalid");
|
||||
|
||||
if (index == layer_id) {
|
||||
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(layer_scope, "MappingInformationType"), 0));
|
||||
|
||||
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(layer_scope, "ReferenceInformationType"), 0));
|
||||
|
||||
if (layer_type_name == "LayerElementUV") {
|
||||
if (index == 0) {
|
||||
m_uv_0 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
|
||||
} else if (index == 1) {
|
||||
m_uv_1 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
|
||||
}
|
||||
} else if (layer_type_name == "LayerElementMaterial") {
|
||||
m_material_allocation_ids = resolve_vertex_data_array<int>(layer_scope, MappingInformationType, ReferenceInformationType, "Materials");
|
||||
} else if (layer_type_name == "LayerElementNormal") {
|
||||
m_normals = resolve_vertex_data_array<Vector3>(layer_scope, MappingInformationType, ReferenceInformationType, "Normals");
|
||||
} else if (layer_type_name == "LayerElementColor") {
|
||||
m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors", "ColorIndex");
|
||||
// NOTE: this is a useful sanity check to ensure you're getting any color data which is not default.
|
||||
// const Color first_color_check = m_colors.data[0];
|
||||
// bool colors_are_all_the_same = true;
|
||||
// size_t i = 1;
|
||||
// for(i = 1; i < m_colors.data.size(); i++)
|
||||
// {
|
||||
// const Color current_color = m_colors.data[i];
|
||||
// if(current_color.is_equal_approx(first_color_check))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// colors_are_all_the_same = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(colors_are_all_the_same)
|
||||
// {
|
||||
// print_error("Color serialisation is not working for vertex colors some should be different in the test asset.");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// print_verbose("Color array has unique colors at index: " + itos(i));
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print_verbose("Mesh statistics \nuv_0: " + m_uv_0.debug_info() + "\nuv_1: " + m_uv_1.debug_info() + "\nvertices: " + itos(m_vertices.size()));
|
||||
|
||||
// Compose the edge of the mesh.
|
||||
// You can see how the edges are stored into the FBX here: https://gist.github.com/AndreaCatania/da81840f5aa3b2feedf189e26c5a87e6
|
||||
for (size_t i = 0; i < m_edges.size(); i += 1) {
|
||||
ERR_FAIL_INDEX_MSG((size_t)m_edges[i], m_face_indices.size(), "The edge is pointing to a weird location in the face indices. The FBX is corrupted.");
|
||||
int polygon_vertex_0 = m_face_indices[m_edges[i]];
|
||||
int polygon_vertex_1;
|
||||
if (polygon_vertex_0 < 0) {
|
||||
// The polygon_vertex_0 points to the end of a polygon, so it's
|
||||
// connected with the beginning of polygon in the edge list.
|
||||
|
||||
// Fist invert the vertex.
|
||||
polygon_vertex_0 = ~polygon_vertex_0;
|
||||
|
||||
// Search the start vertex of the polygon.
|
||||
// Iterate from the polygon_vertex_index backward till the start of
|
||||
// the polygon is found.
|
||||
ERR_FAIL_COND_MSG(m_edges[i] - 1 < 0, "The polygon is not yet started and we already need the final vertex. This FBX is corrupted.");
|
||||
bool found_it = false;
|
||||
for (int x = m_edges[i] - 1; x >= 0; x -= 1) {
|
||||
if (x == 0) {
|
||||
// This for sure is the start.
|
||||
polygon_vertex_1 = m_face_indices[x];
|
||||
found_it = true;
|
||||
break;
|
||||
} else if (m_face_indices[x] < 0) {
|
||||
// This is the end of the previous polygon, so the next is
|
||||
// the start of the polygon we need.
|
||||
polygon_vertex_1 = m_face_indices[x + 1];
|
||||
found_it = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// As the algorithm above, this check is useless. Because the first
|
||||
// ever vertex is always considered the beginning of a polygon.
|
||||
ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted.");
|
||||
|
||||
} else {
|
||||
ERR_FAIL_INDEX_MSG((size_t)(m_edges[i] + 1), m_face_indices.size(), "FBX The other FBX edge seems to point to an invalid vertices. This FBX file is corrupted.");
|
||||
// Take the next vertex
|
||||
polygon_vertex_1 = m_face_indices[m_edges[i] + 1];
|
||||
}
|
||||
|
||||
if (polygon_vertex_1 < 0) {
|
||||
// We don't care if the `polygon_vertex_1` is the end of the polygon,
|
||||
// for `polygon_vertex_1` so we can just invert it.
|
||||
polygon_vertex_1 = ~polygon_vertex_1;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(polygon_vertex_0 == polygon_vertex_1, "The vertices of this edge can't be the same, Is this a point???. This FBX file is corrupted.");
|
||||
|
||||
// Just create the edge.
|
||||
edge_map.push_back({ polygon_vertex_0, polygon_vertex_1 });
|
||||
}
|
||||
}
|
||||
|
||||
MeshGeometry::~MeshGeometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
const std::vector<Vector3> &MeshGeometry::get_vertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
const std::vector<MeshGeometry::Edge> &MeshGeometry::get_edge_map() const {
|
||||
return edge_map;
|
||||
}
|
||||
|
||||
const std::vector<int> &MeshGeometry::get_polygon_indices() const {
|
||||
return m_face_indices;
|
||||
}
|
||||
|
||||
const std::vector<int> &MeshGeometry::get_edges() const {
|
||||
return m_edges;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector3> &MeshGeometry::get_normals() const {
|
||||
return m_normals;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_0() const {
|
||||
//print_verbose("get uv_0 " + m_uv_0.debug_info() );
|
||||
return m_uv_0;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_1() const {
|
||||
//print_verbose("get uv_1 " + m_uv_1.debug_info() );
|
||||
return m_uv_1;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Color> &MeshGeometry::get_colors() const {
|
||||
return m_colors;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<int> &MeshGeometry::get_material_allocation_id() const {
|
||||
return m_material_allocation_ids;
|
||||
}
|
||||
|
||||
int MeshGeometry::get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b) {
|
||||
for (size_t i = 0; i < p_map.size(); i += 1) {
|
||||
if ((p_map[i].vertex_0 == p_vertex_a && p_map[i].vertex_1 == p_vertex_b) || (p_map[i].vertex_1 == p_vertex_a && p_map[i].vertex_0 == p_vertex_b)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MeshGeometry::Edge MeshGeometry::get_edge(const std::vector<Edge> &p_map, int p_id) {
|
||||
ERR_FAIL_INDEX_V_MSG((size_t)p_id, p_map.size(), Edge({ -1, -1 }), "ID not found.");
|
||||
return p_map[p_id];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array(
|
||||
const ScopePtr source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const std::string &dataElementName,
|
||||
const std::string &indexOverride) {
|
||||
ERR_FAIL_COND_V_MSG(source == nullptr, MappingData<T>(), "Invalid scope operator preventing memory corruption");
|
||||
|
||||
// UVIndex, MaterialIndex, NormalIndex, etc..
|
||||
std::string indexDataElementName;
|
||||
|
||||
if (indexOverride != "") {
|
||||
// Colors should become ColorIndex
|
||||
indexDataElementName = indexOverride;
|
||||
} else {
|
||||
// Some indexes will exist.
|
||||
indexDataElementName = dataElementName + "Index";
|
||||
}
|
||||
|
||||
// goal: expand everything to be per vertex
|
||||
|
||||
ReferenceType l_ref_type = ReferenceType::direct;
|
||||
|
||||
// Read the reference type into the enumeration
|
||||
if (ReferenceInformationType == "IndexToDirect") {
|
||||
l_ref_type = ReferenceType::index_to_direct;
|
||||
} else if (ReferenceInformationType == "Index") {
|
||||
// set non legacy index to direct mapping
|
||||
l_ref_type = ReferenceType::index;
|
||||
} else if (ReferenceInformationType == "Direct") {
|
||||
l_ref_type = ReferenceType::direct;
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(MappingData<T>(), "invalid reference type has the FBX format changed?");
|
||||
}
|
||||
|
||||
MapType l_map_type = MapType::none;
|
||||
|
||||
if (MappingInformationType == "None") {
|
||||
l_map_type = MapType::none;
|
||||
} else if (MappingInformationType == "ByVertice") {
|
||||
l_map_type = MapType::vertex;
|
||||
} else if (MappingInformationType == "ByPolygonVertex") {
|
||||
l_map_type = MapType::polygon_vertex;
|
||||
} else if (MappingInformationType == "ByPolygon") {
|
||||
l_map_type = MapType::polygon;
|
||||
} else if (MappingInformationType == "ByEdge") {
|
||||
l_map_type = MapType::edge;
|
||||
} else if (MappingInformationType == "AllSame") {
|
||||
l_map_type = MapType::all_the_same;
|
||||
} else {
|
||||
print_error("invalid mapping type: " + String(MappingInformationType.c_str()));
|
||||
}
|
||||
|
||||
// create mapping data
|
||||
MeshGeometry::MappingData<T> tempData;
|
||||
tempData.map_type = l_map_type;
|
||||
tempData.ref_type = l_ref_type;
|
||||
|
||||
// parse data into array
|
||||
ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName));
|
||||
|
||||
// index array won't always exist
|
||||
const ElementPtr element = GetOptionalElement(source, indexDataElementName);
|
||||
if (element) {
|
||||
ParseVectorDataArray(tempData.index, element);
|
||||
}
|
||||
|
||||
return tempData;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const ScopePtr sc = element->Compound();
|
||||
if (nullptr == sc) {
|
||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||
}
|
||||
const ElementPtr Indexes = GetRequiredElement(sc, "Indexes", element);
|
||||
const ElementPtr Normals = GetRequiredElement(sc, "Normals", element);
|
||||
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
|
||||
ParseVectorDataArray(m_indices, Indexes);
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_normals, Normals);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::~ShapeGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &ShapeGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &ShapeGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const ScopePtr sc = element->Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
||||
}
|
||||
const ElementPtr Points = GetRequiredElement(sc, "Points", element);
|
||||
const ElementPtr PointsIndex = GetRequiredElement(sc, "PointsIndex", element);
|
||||
ParseVectorDataArray(m_vertices, Points);
|
||||
ParseVectorDataArray(m_indices, PointsIndex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::~LineGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &LineGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<int> &LineGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,264 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMeshGeometry.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef FBX_MESH_GEOMETRY_H
|
||||
#define FBX_MESH_GEOMETRY_H
|
||||
|
||||
#include "core/color.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector3.h"
|
||||
#include "core/vector.h"
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define AI_MAX_NUMBER_OF_TEXTURECOORDS 4
|
||||
#define AI_MAX_NUMBER_OF_COLOR_SETS 8
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
/*
|
||||
* DOM base class for all kinds of FBX geometry
|
||||
*/
|
||||
class Geometry : public Object {
|
||||
public:
|
||||
Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
virtual ~Geometry();
|
||||
|
||||
/** Get the Skin attached to this geometry or NULL */
|
||||
const Skin *DeformerSkin() const;
|
||||
|
||||
const std::vector<const BlendShape *> &get_blend_shapes() const;
|
||||
|
||||
size_t get_blend_shape_count() const {
|
||||
return blendShapes.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const Skin *skin = nullptr;
|
||||
std::vector<const BlendShape *> blendShapes;
|
||||
};
|
||||
|
||||
typedef std::vector<int> MatIndexArray;
|
||||
|
||||
/// Map Geometry stores the FBX file information.
|
||||
///
|
||||
/// # FBX doc.
|
||||
/// ## Reference type declared:
|
||||
/// - Direct (directly related to the mapping information type)
|
||||
/// - IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
|
||||
///
|
||||
/// ## Map Type:
|
||||
/// * None The mapping is undetermined.
|
||||
/// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex).
|
||||
/// * If you have direct reference type vertices[x]
|
||||
/// * If you have IndexToDirect reference type the UV
|
||||
/// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
|
||||
/// * ByPolygon There can be only one mapping coordinate for the whole polygon.
|
||||
/// * One mapping per polygon polygon x has this normal x
|
||||
/// * For each vertex of the polygon then set the normal to x
|
||||
/// * ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
|
||||
/// * AllSame There can be only one mapping coordinate for the whole surface.
|
||||
class MeshGeometry : public Geometry {
|
||||
public:
|
||||
enum class MapType {
|
||||
none = 0, // No mapping type. Stored as "None".
|
||||
vertex, // Maps per vertex. Stored as "ByVertice".
|
||||
polygon_vertex, // Maps per polygon vertex. Stored as "ByPolygonVertex".
|
||||
polygon, // Maps per polygon. Stored as "ByPolygon".
|
||||
edge, // Maps per edge. Stored as "ByEdge".
|
||||
all_the_same // Uaps to everything. Stored as "AllSame".
|
||||
};
|
||||
|
||||
enum class ReferenceType {
|
||||
direct = 0,
|
||||
index = 1,
|
||||
index_to_direct = 2
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MappingData {
|
||||
MapType map_type = MapType::none;
|
||||
ReferenceType ref_type = ReferenceType::direct;
|
||||
std::vector<T> data;
|
||||
/// The meaning of the indices depends from the `MapType`.
|
||||
/// If `ref_type` is `direct` this map is hollow.
|
||||
std::vector<int> index;
|
||||
|
||||
String debug_info() const {
|
||||
return "indexes: " + itos(index.size()) + " data: " + itos(data.size());
|
||||
}
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
int vertex_0 = 0, vertex_1 = 0;
|
||||
Edge(int v0, int v1) :
|
||||
vertex_0(v0), vertex_1(v1) {}
|
||||
Edge() {}
|
||||
};
|
||||
|
||||
public:
|
||||
MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
virtual ~MeshGeometry();
|
||||
|
||||
const std::vector<Vector3> &get_vertices() const;
|
||||
const std::vector<Edge> &get_edge_map() const;
|
||||
const std::vector<int> &get_polygon_indices() const;
|
||||
const std::vector<int> &get_edges() const;
|
||||
const MappingData<Vector3> &get_normals() const;
|
||||
const MappingData<Vector2> &get_uv_0() const;
|
||||
const MappingData<Vector2> &get_uv_1() const;
|
||||
const MappingData<Color> &get_colors() const;
|
||||
const MappingData<int> &get_material_allocation_id() const;
|
||||
|
||||
/// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't
|
||||
// matter.
|
||||
static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b);
|
||||
// Returns the edge point bu that ID, or the edge with -1 vertices if the
|
||||
// id is not valid.
|
||||
static Edge get_edge(const std::vector<Edge> &p_map, int p_id);
|
||||
|
||||
private:
|
||||
// Read directly from the FBX file.
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<Edge> edge_map;
|
||||
std::vector<int> m_face_indices;
|
||||
std::vector<int> m_edges;
|
||||
MappingData<Vector3> m_normals;
|
||||
MappingData<Vector2> m_uv_0; // first uv coordinates
|
||||
MappingData<Vector2> m_uv_1; // second uv coordinates
|
||||
MappingData<Color> m_colors; // colors for the mesh
|
||||
MappingData<int> m_material_allocation_ids; // slot of material used
|
||||
|
||||
template <class T>
|
||||
MappingData<T> resolve_vertex_data_array(
|
||||
const ScopePtr source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const std::string &dataElementName,
|
||||
const std::string &indexOverride = "");
|
||||
};
|
||||
|
||||
/*
|
||||
* DOM class for FBX geometry of type "Shape"
|
||||
*/
|
||||
class ShapeGeometry : public Geometry {
|
||||
public:
|
||||
/** The class constructor */
|
||||
ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~ShapeGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<Vector3> &GetVertices() const;
|
||||
|
||||
/** Get a list of all vertex normals or an empty array if
|
||||
* no normals are specified. */
|
||||
const std::vector<Vector3> &GetNormals() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<unsigned int> &GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<Vector3> m_normals;
|
||||
std::vector<unsigned int> m_indices;
|
||||
};
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Line"
|
||||
*/
|
||||
class LineGeometry : public Geometry {
|
||||
public:
|
||||
/** The class constructor */
|
||||
LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~LineGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<Vector3> &GetVertices() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<int> &GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<int> m_indices;
|
||||
};
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_MESH_GEOMETRY_H
|
@ -1,179 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXModel.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXModel.cpp
|
||||
* @brief Assimp::FBX::Model implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), shading("Y") {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr Shading = sc->GetElement("Shading");
|
||||
const ElementPtr Culling = sc->GetElement("Culling");
|
||||
|
||||
if (Shading) {
|
||||
shading = GetRequiredToken(Shading, 0)->StringContents();
|
||||
}
|
||||
|
||||
if (Culling) {
|
||||
culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
|
||||
ResolveLinks(element, doc);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::~Model() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Model(id, element, doc, name){
|
||||
|
||||
};
|
||||
|
||||
ModelLimbNode::~ModelLimbNode() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Model::ResolveLinks(const ElementPtr element, const Document &doc) {
|
||||
const char *const arr[] = { "Geometry", "Material", "NodeAttribute" };
|
||||
|
||||
// resolve material
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), arr, 3);
|
||||
|
||||
materials.reserve(conns.size());
|
||||
geometry.reserve(conns.size());
|
||||
attributes.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
// material and geometry links should be Object-Object connections
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
//DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Material *const mat = dynamic_cast<const Material *>(ob);
|
||||
if (mat) {
|
||||
materials.push_back(mat);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Geometry *const geo = dynamic_cast<const Geometry *>(ob);
|
||||
if (geo) {
|
||||
geometry.push_back(geo);
|
||||
continue;
|
||||
}
|
||||
|
||||
const NodeAttribute *const att = dynamic_cast<const NodeAttribute *>(ob);
|
||||
if (att) {
|
||||
attributes.push_back(att);
|
||||
continue;
|
||||
}
|
||||
|
||||
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Model::IsNull() const {
|
||||
const std::vector<const NodeAttribute *> &attrs = GetAttributes();
|
||||
for (const NodeAttribute *att : attrs) {
|
||||
const Null *null_tag = dynamic_cast<const Null *>(att);
|
||||
if (null_tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,184 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXNodeAttribute.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), props() {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
|
||||
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
||||
// the property table is by design absent and no warning should be generated
|
||||
// for it.
|
||||
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
||||
props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::~NodeAttribute() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr CameraId = sc->GetElement("CameraId");
|
||||
const ElementPtr CameraName = sc->GetElement("CameraName");
|
||||
const ElementPtr CameraIndexName = sc->GetElement("CameraIndexName");
|
||||
|
||||
if (CameraId) {
|
||||
cameraId = ParseTokenAsInt(GetRequiredToken(CameraId, 0));
|
||||
}
|
||||
|
||||
if (CameraName) {
|
||||
cameraName = GetRequiredToken(CameraName, 0)->StringContents();
|
||||
}
|
||||
|
||||
if (CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||
cameraIndexName = GetRequiredToken(CameraIndexName, 0)->StringContents();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::~CameraSwitcher() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::~Camera() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::~Light() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::~Null() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
//std::cout << "limb node: " << name << std::endl;
|
||||
//const Scope &sc = GetRequiredScope(element);
|
||||
|
||||
//const ElementPtr const TypeFlag = sc["TypeFlags"];
|
||||
|
||||
// keep this it can dump new properties for you
|
||||
// for( auto element : sc.Elements())
|
||||
// {
|
||||
// std::cout << "limbnode element: " << element.first << std::endl;
|
||||
// }
|
||||
|
||||
// if(TypeFlag)
|
||||
// {
|
||||
// // std::cout << "type flag: " << GetRequiredToken(*TypeFlag, 0).StringContents() << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::~LimbNode() {
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,111 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXParseTools.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_PARSE_TOOLS_H
|
||||
#define FBX_PARSE_TOOLS_H
|
||||
|
||||
#include "core/error_macros.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsNewLine(char_t c) {
|
||||
return c == '\n' || c == '\r';
|
||||
}
|
||||
template <class char_t>
|
||||
inline bool IsSpace(char_t c) {
|
||||
return (c == (char_t)' ' || c == (char_t)'\t');
|
||||
}
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsSpaceOrNewLine(char_t c) {
|
||||
return IsNewLine(c) || IsSpace(c);
|
||||
}
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsLineEnd(char_t c) {
|
||||
return (c == (char_t)'\r' || c == (char_t)'\n' || c == (char_t)'\0' || c == (char_t)'\f');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Special version of the function, providing higher accuracy and safety
|
||||
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) {
|
||||
unsigned int cur = 0;
|
||||
uint64_t value = 0;
|
||||
|
||||
errored = *in < '0' || *in > '9';
|
||||
ERR_FAIL_COND_V_MSG(errored, 0, "The string cannot be converted parser error");
|
||||
|
||||
for (;;) {
|
||||
if (*in < '0' || *in > '9') {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint64_t new_value = (value * (uint64_t)10) + ((uint64_t)(*in - '0'));
|
||||
|
||||
// numeric overflow, we rely on you
|
||||
if (new_value < value) {
|
||||
//WARN_PRINT( "Converting the string \" " + in + " \" into a value resulted in overflow." );
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = new_value;
|
||||
|
||||
++in;
|
||||
++cur;
|
||||
|
||||
if (max_inout && *max_inout == cur) {
|
||||
if (out) { /* skip to end */
|
||||
while (*in >= '0' && *in <= '9') {
|
||||
++in;
|
||||
}
|
||||
*out = in;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (out) {
|
||||
*out = in;
|
||||
}
|
||||
|
||||
if (max_inout) {
|
||||
*max_inout = cur;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif // FBX_PARSE_TOOLS_H
|
File diff suppressed because it is too large
Load Diff
@ -1,264 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXParser.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXParser.h
|
||||
* @brief FBX parsing code
|
||||
*/
|
||||
#ifndef FBX_PARSER_H
|
||||
#define FBX_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "core/color.h"
|
||||
#include "core/math/transform.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
class Scope;
|
||||
class Parser;
|
||||
class Element;
|
||||
|
||||
typedef Element *ElementPtr;
|
||||
typedef Scope *ScopePtr;
|
||||
|
||||
typedef std::vector<ScopePtr> ScopeList;
|
||||
typedef std::multimap<std::string, ElementPtr> ElementMap;
|
||||
typedef std::pair<ElementMap::const_iterator, ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
#define new_Scope new Scope
|
||||
#define new_Element new Element
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* AnimationCurve: 23, "AnimCurve::", "" {
|
||||
* [..]
|
||||
* }
|
||||
* @endverbatim
|
||||
*
|
||||
* As can be seen in this sample, elements can contain nested #Scope
|
||||
* as their trailing member. **/
|
||||
class Element {
|
||||
public:
|
||||
Element(TokenPtr key_token, Parser &parser);
|
||||
~Element();
|
||||
|
||||
ScopePtr Compound() const {
|
||||
return compound;
|
||||
}
|
||||
|
||||
TokenPtr KeyToken() const {
|
||||
return key_token;
|
||||
}
|
||||
|
||||
const TokenList &Tokens() const {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private:
|
||||
TokenList tokens;
|
||||
ScopePtr compound = nullptr;
|
||||
std::vector<ScopePtr> compound_scope;
|
||||
TokenPtr key_token = nullptr;
|
||||
};
|
||||
|
||||
/** FBX data entity that consists of a 'scope', a collection
|
||||
* of not necessarily unique #Element instances.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* GlobalSettings: {
|
||||
* Version: 1000
|
||||
* Properties70:
|
||||
* [...]
|
||||
* }
|
||||
* @endverbatim */
|
||||
class Scope {
|
||||
public:
|
||||
Scope(Parser &parser, bool topLevel = false);
|
||||
~Scope();
|
||||
|
||||
ElementPtr GetElement(const std::string &index) const {
|
||||
ElementMap::const_iterator it = elements.find(index);
|
||||
return it == elements.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
ElementPtr FindElementCaseInsensitive(const std::string &elementName) const {
|
||||
for (auto element = elements.begin(); element != elements.end(); ++element) {
|
||||
if (element->first.compare(elementName)) {
|
||||
return element->second;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing to reference / expired.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ElementCollection GetCollection(const std::string &index) const {
|
||||
return elements.equal_range(index);
|
||||
}
|
||||
|
||||
const ElementMap &Elements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementMap elements;
|
||||
};
|
||||
|
||||
/** FBX parsing class, takes a list of input tokens and generates a hierarchy
|
||||
* of nested #Scope instances, representing the fbx DOM.*/
|
||||
class Parser {
|
||||
public:
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser(const TokenList &tokens, bool is_binary);
|
||||
~Parser();
|
||||
|
||||
ScopePtr GetRootScope() const {
|
||||
return root;
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return is_binary;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
||||
TokenPtr AdvanceToNextToken();
|
||||
TokenPtr LastToken() const;
|
||||
TokenPtr CurrentToken() const;
|
||||
|
||||
private:
|
||||
ScopeList scopes;
|
||||
const TokenList &tokens;
|
||||
|
||||
TokenPtr last = nullptr, current = nullptr;
|
||||
TokenList::const_iterator cursor;
|
||||
ScopePtr root = nullptr;
|
||||
|
||||
const bool is_binary;
|
||||
};
|
||||
|
||||
/* token parsing - this happens when building the DOM out of the parse-tree*/
|
||||
uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out);
|
||||
size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out);
|
||||
float ParseTokenAsFloat(const TokenPtr t, const char *&err_out);
|
||||
int ParseTokenAsInt(const TokenPtr t, const char *&err_out);
|
||||
int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out);
|
||||
std::string ParseTokenAsString(const TokenPtr t, const char *&err_out);
|
||||
|
||||
/* wrapper around ParseTokenAsXXX() with DOMError handling */
|
||||
uint64_t ParseTokenAsID(const TokenPtr t);
|
||||
size_t ParseTokenAsDim(const TokenPtr t);
|
||||
float ParseTokenAsFloat(const TokenPtr t);
|
||||
int ParseTokenAsInt(const TokenPtr t);
|
||||
int64_t ParseTokenAsInt64(const TokenPtr t);
|
||||
std::string ParseTokenAsString(const TokenPtr t);
|
||||
|
||||
/* read data arrays */
|
||||
void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr ep);
|
||||
void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el);
|
||||
bool HasElement(const ScopePtr sc, const std::string &index);
|
||||
|
||||
// extract a required element from a scope, abort if the element cannot be found
|
||||
ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
|
||||
ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
|
||||
ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
|
||||
// extract required compound scope
|
||||
ScopePtr GetRequiredScope(const ElementPtr el);
|
||||
// get token at a particular index
|
||||
TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a 4x4 matrix from an array of 16 floats
|
||||
Transform ReadMatrix(const ElementPtr element);
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_PARSER_H
|
@ -1,105 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXPose.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
class FbxPoseNode;
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FbxPose::FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
//const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
|
||||
const ElementCollection &PoseNodes = sc->GetCollection("PoseNode");
|
||||
for (ElementMap::const_iterator it = PoseNodes.first; it != PoseNodes.second; ++it) {
|
||||
std::string entry_name = (*it).first;
|
||||
ElementPtr some_element = (*it).second;
|
||||
FbxPoseNode *pose_node = new FbxPoseNode(some_element, doc, entry_name);
|
||||
pose_nodes.push_back(pose_node);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FbxPose::~FbxPose() {
|
||||
pose_nodes.clear();
|
||||
// empty
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,246 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXProperties.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.cpp
|
||||
* @brief Implementation of the FBX dynamic properties system
|
||||
*/
|
||||
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::Property() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::~Property() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
|
||||
PropertyPtr ReadTypedProperty(const ElementPtr element) {
|
||||
//ai_assert(element.KeyToken().StringContents() == "P");
|
||||
|
||||
const TokenList &tok = element->Tokens();
|
||||
//ai_assert(tok.size() >= 5);
|
||||
|
||||
const std::string &s = ParseTokenAsString(tok[1]);
|
||||
const char *const cs = s.c_str();
|
||||
if (!strcmp(cs, "KString")) {
|
||||
return new TypedProperty<std::string>(ParseTokenAsString(tok[4]));
|
||||
} else if (!strcmp(cs, "bool") || !strcmp(cs, "Bool")) {
|
||||
return new TypedProperty<bool>(ParseTokenAsInt(tok[4]) != 0);
|
||||
} else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
|
||||
return new TypedProperty<int>(ParseTokenAsInt(tok[4]));
|
||||
} else if (!strcmp(cs, "ULongLong")) {
|
||||
return new TypedProperty<uint64_t>(ParseTokenAsID(tok[4]));
|
||||
} else if (!strcmp(cs, "KTime")) {
|
||||
return new TypedProperty<int64_t>(ParseTokenAsInt64(tok[4]));
|
||||
} else if (!strcmp(cs, "Vector3D") ||
|
||||
!strcmp(cs, "ColorRGB") ||
|
||||
!strcmp(cs, "Vector") ||
|
||||
!strcmp(cs, "Color") ||
|
||||
!strcmp(cs, "Lcl Translation") ||
|
||||
!strcmp(cs, "Lcl Rotation") ||
|
||||
!strcmp(cs, "Lcl Scaling")) {
|
||||
return new TypedProperty<Vector3>(Vector3(
|
||||
ParseTokenAsFloat(tok[4]),
|
||||
ParseTokenAsFloat(tok[5]),
|
||||
ParseTokenAsFloat(tok[6])));
|
||||
} else if (!strcmp(cs, "double") || !strcmp(cs, "Number") || !strcmp(cs, "Float") || !strcmp(cs, "float") || !strcmp(cs, "FieldOfView") || !strcmp(cs, "UnitScaleFactor")) {
|
||||
return new TypedProperty<float>(ParseTokenAsFloat(tok[4]));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// peek into an element and check if it contains a FBX property, if so return its name.
|
||||
std::string PeekPropertyName(const Element &element) {
|
||||
//ai_assert(element.KeyToken().StringContents() == "P");
|
||||
const TokenList &tok = element.Tokens();
|
||||
if (tok.size() < 4) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ParseTokenAsString(tok[0]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable() :
|
||||
templateProps(), element() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable(const PropertyTable *templateProps) :
|
||||
templateProps(templateProps), element() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) :
|
||||
templateProps(templateProps), element(element) {
|
||||
const ScopePtr scope = GetRequiredScope(element);
|
||||
ERR_FAIL_COND(!scope);
|
||||
for (const ElementMap::value_type &v : scope->Elements()) {
|
||||
if (v.first != "P") {
|
||||
DOMWarning("expected only P elements in property table", v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &name = PeekPropertyName(*v.second);
|
||||
if (!name.length()) {
|
||||
DOMWarning("could not read property name", v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
LazyPropertyMap::const_iterator it = lazyProps.find(name);
|
||||
if (it != lazyProps.end()) {
|
||||
DOMWarning("duplicate property name, will hide previous value: " + name, v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
// since the above checks for duplicates we can be sure to insert the only match here.
|
||||
lazyProps[name] = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::~PropertyTable() {
|
||||
for (PropertyMap::value_type &v : props) {
|
||||
delete v.second;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyPtr PropertyTable::Get(const std::string &name) const {
|
||||
PropertyMap::const_iterator it = props.find(name);
|
||||
if (it == props.end()) {
|
||||
// hasn't been parsed yet?
|
||||
LazyPropertyMap::const_iterator lit = lazyProps.find(name);
|
||||
if (lit != lazyProps.end()) {
|
||||
props[name] = ReadTypedProperty(lit->second);
|
||||
it = props.find(name);
|
||||
|
||||
//ai_assert(it != props.end());
|
||||
}
|
||||
|
||||
if (it == props.end()) {
|
||||
// check property template
|
||||
if (templateProps) {
|
||||
return templateProps->Get(name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
|
||||
DirectPropertyMap result;
|
||||
|
||||
// Loop through all the lazy properties (which is all the properties)
|
||||
for (const LazyPropertyMap::value_type &element : lazyProps) {
|
||||
// Skip parsed properties
|
||||
if (props.end() != props.find(element.first)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
Property *prop = ReadTypedProperty(element.second);
|
||||
|
||||
// Element could not be read. Skip it.
|
||||
if (!prop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add to result
|
||||
result[element.first] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,223 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXProperties.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.h
|
||||
* @brief FBX dynamic properties
|
||||
*/
|
||||
#ifndef FBX_PROPERTIES_H
|
||||
#define FBX_PROPERTIES_H
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
// Forward declarations
|
||||
class Element;
|
||||
|
||||
/** Represents a dynamic property. Type info added by deriving classes,
|
||||
* see #TypedProperty.
|
||||
Example:
|
||||
@verbatim
|
||||
P: "ShininessExponent", "double", "Number", "",0.5
|
||||
@endvebatim
|
||||
*/
|
||||
class Property {
|
||||
protected:
|
||||
Property();
|
||||
|
||||
public:
|
||||
virtual ~Property();
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
const T *As() const {
|
||||
return dynamic_cast<const T *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedProperty : public Property {
|
||||
public:
|
||||
explicit TypedProperty(const T &value) :
|
||||
value(value) {
|
||||
// empty
|
||||
}
|
||||
|
||||
const T &Value() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
#define new_Property new Property
|
||||
typedef Property *PropertyPtr;
|
||||
typedef std::map<std::string, PropertyPtr> DirectPropertyMap;
|
||||
typedef std::map<std::string, PropertyPtr> PropertyMap;
|
||||
typedef std::map<std::string, ElementPtr> LazyPropertyMap;
|
||||
|
||||
/**
|
||||
* Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
|
||||
*/
|
||||
class PropertyTable {
|
||||
public:
|
||||
// in-memory property table with no source element
|
||||
PropertyTable();
|
||||
PropertyTable(const PropertyTable *templateProps);
|
||||
PropertyTable(const ElementPtr element, const PropertyTable *templateProps);
|
||||
~PropertyTable();
|
||||
|
||||
PropertyPtr Get(const std::string &name) const;
|
||||
|
||||
// PropertyTable's need not be coupled with FBX elements so this can be NULL
|
||||
ElementPtr GetElement() const {
|
||||
return element;
|
||||
}
|
||||
|
||||
const PropertyMap &GetProperties() const {
|
||||
return props;
|
||||
}
|
||||
|
||||
const LazyPropertyMap &GetLazyProperties() const {
|
||||
return lazyProps;
|
||||
}
|
||||
|
||||
const PropertyTable *TemplateProps() const {
|
||||
return templateProps;
|
||||
}
|
||||
|
||||
DirectPropertyMap GetUnparsedProperties() const;
|
||||
|
||||
private:
|
||||
LazyPropertyMap lazyProps;
|
||||
mutable PropertyMap props;
|
||||
const PropertyTable *templateProps = nullptr;
|
||||
const ElementPtr element = nullptr;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable *in, const std::string &name, const T &defaultValue) {
|
||||
PropertyPtr prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>();
|
||||
if (nullptr == tprop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
|
||||
PropertyPtr prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
if (!useTemplate) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
const PropertyTable *templ = in->TemplateProps();
|
||||
if (nullptr == templ) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
prop = templ->Get(name);
|
||||
if (nullptr == prop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>();
|
||||
if (nullptr == tprop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
|
||||
result = true;
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_PROPERTIES_H
|
@ -1,253 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXTokenizer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.cpp
|
||||
* @brief Implementation of the FBX broadphase lexer
|
||||
*/
|
||||
|
||||
// tab width for logging columns
|
||||
#define ASSIMP_FBX_TAB_WIDTH 4
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column) :
|
||||
sbegin(p_sbegin),
|
||||
send(p_send),
|
||||
type(p_type),
|
||||
line(p_line),
|
||||
column(p_column) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::~Token() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string &message, unsigned int line, unsigned int column) {
|
||||
print_error("[FBX-Tokenize]" + String(message.c_str()) + " " + itos(line) + ":" + itos(column));
|
||||
}
|
||||
|
||||
// process a potential data token up to 'cur', adding it to 'output_tokens'.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *&end,
|
||||
unsigned int line,
|
||||
unsigned int column,
|
||||
TokenType type = TokenType_DATA,
|
||||
bool must_have_token = false) {
|
||||
if (start && end) {
|
||||
// sanity check:
|
||||
// tokens should have no whitespace outside quoted text and [start,end] should
|
||||
// properly delimit the valid range.
|
||||
bool in_double_quotes = false;
|
||||
for (const char *c = start; c != end + 1; ++c) {
|
||||
if (*c == '\"') {
|
||||
in_double_quotes = !in_double_quotes;
|
||||
}
|
||||
|
||||
if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
|
||||
TokenizeError("unexpected whitespace in token", line, column);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_double_quotes) {
|
||||
TokenizeError("non-terminated double quotes", line, column);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(start, end + 1, type, line, column));
|
||||
} else if (must_have_token) {
|
||||
TokenizeError("unexpected character, expected data token", line, column);
|
||||
}
|
||||
|
||||
start = end = nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
|
||||
// line and column numbers numbers are one-based
|
||||
unsigned int line = 1;
|
||||
unsigned int column = 1;
|
||||
|
||||
bool comment = false;
|
||||
bool in_double_quotes = false;
|
||||
bool pending_data_token = false;
|
||||
|
||||
const char *token_begin = nullptr, *token_end = nullptr;
|
||||
|
||||
// input (starting string), *cur the current string, column +=
|
||||
// modified to fix strlen() and stop buffer overflow
|
||||
for (size_t x = 0; x < length; x++) {
|
||||
const char c = input[x];
|
||||
const char *cur = &input[x];
|
||||
column += (c == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1);
|
||||
|
||||
if (IsLineEnd(c)) {
|
||||
comment = false;
|
||||
|
||||
column = 0;
|
||||
++line;
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_double_quotes) {
|
||||
if (c == '\"') {
|
||||
in_double_quotes = false;
|
||||
token_end = cur;
|
||||
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
pending_data_token = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '\"':
|
||||
if (token_begin) {
|
||||
TokenizeError("unexpected double-quote", line, column);
|
||||
}
|
||||
token_begin = cur;
|
||||
in_double_quotes = true;
|
||||
continue;
|
||||
|
||||
case ';':
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
comment = true;
|
||||
continue;
|
||||
|
||||
case '{':
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur, cur + 1, TokenType_OPEN_BRACKET, line, column));
|
||||
continue;
|
||||
|
||||
case '}':
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur, cur + 1, TokenType_CLOSE_BRACKET, line, column));
|
||||
continue;
|
||||
|
||||
case ',':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_DATA, true);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cur, cur + 1, TokenType_COMMA, line, column));
|
||||
continue;
|
||||
|
||||
case ':':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_KEY, true);
|
||||
} else {
|
||||
TokenizeError("unexpected colon", line, column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsSpaceOrNewLine(c)) {
|
||||
if (token_begin) {
|
||||
// peek ahead and check if the next token is a colon in which
|
||||
// case this counts as KEY token.
|
||||
TokenType type = TokenType_DATA;
|
||||
for (const char *peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) {
|
||||
if (*peek == ':') {
|
||||
type = TokenType_KEY;
|
||||
cur = peek;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column, type);
|
||||
}
|
||||
|
||||
pending_data_token = false;
|
||||
} else {
|
||||
token_end = cur;
|
||||
if (!token_begin) {
|
||||
token_begin = cur;
|
||||
}
|
||||
|
||||
pending_data_token = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
@ -1,204 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXTokenizer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.h
|
||||
* @brief FBX lexer
|
||||
*/
|
||||
#ifndef FBX_TOKENIZER_H
|
||||
#define FBX_TOKENIZER_H
|
||||
|
||||
#include "FBXParseTools.h"
|
||||
#include "core/ustring.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FBXDocParser {
|
||||
/** Rough classification for text FBX tokens used for constructing the
|
||||
* basic scope hierarchy. */
|
||||
enum TokenType {
|
||||
// {
|
||||
TokenType_OPEN_BRACKET = 0,
|
||||
|
||||
// }
|
||||
TokenType_CLOSE_BRACKET,
|
||||
|
||||
// '"blablubb"', '2', '*14' - very general token class,
|
||||
// further processing happens at a later stage.
|
||||
TokenType_DATA,
|
||||
|
||||
//
|
||||
TokenType_BINARY_DATA,
|
||||
|
||||
// ,
|
||||
TokenType_COMMA,
|
||||
|
||||
// blubb:
|
||||
TokenType_KEY
|
||||
};
|
||||
|
||||
/** Represents a single token in a FBX file. Tokens are
|
||||
* classified by the #TokenType enumerated types.
|
||||
*
|
||||
* Offers iterator protocol. Tokens are immutable. */
|
||||
class Token {
|
||||
private:
|
||||
static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
|
||||
|
||||
public:
|
||||
/** construct a textual token */
|
||||
Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column);
|
||||
|
||||
/** construct a binary token */
|
||||
Token(const char *p_sbegin, const char *p_send, TokenType p_type, size_t p_offset);
|
||||
~Token();
|
||||
|
||||
public:
|
||||
std::string StringContents() const {
|
||||
return std::string(begin(), end());
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return column == BINARY_MARKER;
|
||||
}
|
||||
|
||||
const char *begin() const {
|
||||
return sbegin;
|
||||
}
|
||||
|
||||
const char *end() const {
|
||||
return send;
|
||||
}
|
||||
|
||||
TokenType Type() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
size_t Offset() const {
|
||||
return offset;
|
||||
}
|
||||
|
||||
unsigned int Line() const {
|
||||
return static_cast<unsigned int>(line);
|
||||
}
|
||||
|
||||
unsigned int Column() const {
|
||||
return column;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DEBUG_ENABLED
|
||||
// full string copy for the sole purpose that it nicely appears
|
||||
// in msvc's debugger window.
|
||||
std::string contents;
|
||||
#endif
|
||||
|
||||
const char *sbegin = nullptr;
|
||||
const char *send = nullptr;
|
||||
const TokenType type;
|
||||
|
||||
union {
|
||||
size_t line;
|
||||
size_t offset;
|
||||
};
|
||||
const unsigned int column = 0;
|
||||
};
|
||||
|
||||
// Fixed leak by using shared_ptr for tokens
|
||||
typedef Token *TokenPtr;
|
||||
typedef std::vector<TokenPtr> TokenList;
|
||||
|
||||
#define new_Token new Token
|
||||
|
||||
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
|
||||
*
|
||||
* Skips over comments and generates line and column numbers.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Textual input buffer to be processed, 0-terminated.
|
||||
* @print_error if something goes wrong */
|
||||
void Tokenize(TokenList &output_tokens, const char *input, size_t length);
|
||||
|
||||
/** Tokenizer function for binary FBX files.
|
||||
*
|
||||
* Emits a token list suitable for direct parsing.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Binary input buffer to be processed.
|
||||
* @param length Length of input buffer, in bytes. There is no 0-terminal.
|
||||
* @print_error if something goes wrong */
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length);
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_TOKENIZER_H
|
@ -1,223 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXUtil.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.cpp
|
||||
* @brief Implementation of internal FBX utility functions
|
||||
*/
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char *TokenTypeString(TokenType t) {
|
||||
switch (t) {
|
||||
case TokenType_OPEN_BRACKET:
|
||||
return "TOK_OPEN_BRACKET";
|
||||
|
||||
case TokenType_CLOSE_BRACKET:
|
||||
return "TOK_CLOSE_BRACKET";
|
||||
|
||||
case TokenType_DATA:
|
||||
return "TOK_DATA";
|
||||
|
||||
case TokenType_COMMA:
|
||||
return "TOK_COMMA";
|
||||
|
||||
case TokenType_KEY:
|
||||
return "TOK_KEY";
|
||||
|
||||
case TokenType_BINARY_DATA:
|
||||
return "TOK_BINARY_DATA";
|
||||
}
|
||||
|
||||
//ai_assert(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
static const uint8_t base64DecodeTable[128] = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
|
||||
uint8_t DecodeBase64(char ch) {
|
||||
const auto idx = static_cast<uint8_t>(ch);
|
||||
if (idx > 127) {
|
||||
return 255;
|
||||
}
|
||||
return base64DecodeTable[idx];
|
||||
}
|
||||
|
||||
size_t ComputeDecodedSizeBase64(const char *in, size_t inLength) {
|
||||
if (inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
|
||||
const size_t full_length = (inLength * 3) >> 2; // div by 4
|
||||
if (full_length < equals) {
|
||||
return 0;
|
||||
}
|
||||
return full_length - equals;
|
||||
}
|
||||
|
||||
size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength) {
|
||||
if (maxOutLength == 0 || inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
|
||||
size_t dst_offset = 0;
|
||||
int val = 0, valb = -8;
|
||||
for (size_t src_offset = 0; src_offset < realLength; ++src_offset) {
|
||||
const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
|
||||
if (table_value == 255) {
|
||||
return 0;
|
||||
}
|
||||
val = (val << 6) + table_value;
|
||||
valb += 6;
|
||||
if (valb >= 0) {
|
||||
out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
|
||||
valb -= 8;
|
||||
val &= 0xFFF;
|
||||
}
|
||||
}
|
||||
return dst_offset;
|
||||
}
|
||||
|
||||
static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
char EncodeBase64(char byte) {
|
||||
return to_base64_string[(size_t)byte];
|
||||
}
|
||||
|
||||
/** Encodes a block of 4 bytes to base64 encoding
|
||||
* @param bytes Bytes to encode.
|
||||
* @param out_string String to write encoded values to.
|
||||
* @param string_pos Position in out_string.
|
||||
*/
|
||||
void EncodeByteBlock(const char *bytes, std::string &out_string, size_t string_pos) {
|
||||
char b0 = (bytes[0] & 0xFC) >> 2;
|
||||
char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
|
||||
char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
|
||||
char b3 = (bytes[2] & 0x3F);
|
||||
|
||||
out_string[string_pos + 0] = EncodeBase64(b0);
|
||||
out_string[string_pos + 1] = EncodeBase64(b1);
|
||||
out_string[string_pos + 2] = EncodeBase64(b2);
|
||||
out_string[string_pos + 3] = EncodeBase64(b3);
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const char *data, size_t length) {
|
||||
// calculate extra bytes needed to get a multiple of 3
|
||||
size_t extraBytes = 3 - length % 3;
|
||||
|
||||
// number of base64 bytes
|
||||
size_t encodedBytes = 4 * (length + extraBytes) / 3;
|
||||
|
||||
std::string encoded_string(encodedBytes, '=');
|
||||
|
||||
// read blocks of 3 bytes
|
||||
for (size_t ib3 = 0; ib3 < length / 3; ib3++) {
|
||||
const size_t iByte = ib3 * 3;
|
||||
const size_t iEncodedByte = ib3 * 4;
|
||||
const char *currData = &data[iByte];
|
||||
|
||||
EncodeByteBlock(currData, encoded_string, iEncodedByte);
|
||||
}
|
||||
|
||||
// if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
|
||||
if (extraBytes > 0) {
|
||||
char finalBytes[4] = { 0, 0, 0, 0 };
|
||||
memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
|
||||
|
||||
const size_t iEncodedByte = encodedBytes - 4;
|
||||
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
|
||||
|
||||
// add '=' at the end
|
||||
for (size_t i = 0; i < 4 * extraBytes / 3; i++) {
|
||||
encoded_string[encodedBytes - i - 1] = '=';
|
||||
}
|
||||
}
|
||||
return encoded_string;
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
@ -1,123 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXUtil.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.h
|
||||
* @brief FBX utility functions for internal use
|
||||
*/
|
||||
#ifndef FBX_UTIL_H
|
||||
#define FBX_UTIL_H
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
namespace Util {
|
||||
|
||||
/** Get a string representation for a #TokenType. */
|
||||
const char *TokenTypeString(TokenType t);
|
||||
|
||||
/** Decode a single Base64-encoded character.
|
||||
*
|
||||
* @param ch Character to decode (from base64 to binary).
|
||||
* @return decoded byte value*/
|
||||
uint8_t DecodeBase64(char ch);
|
||||
|
||||
/** Compute decoded size of a Base64-encoded string
|
||||
*
|
||||
* @param in Characters to decode.
|
||||
* @param inLength Number of characters to decode.
|
||||
* @return size of the decoded data (number of bytes)*/
|
||||
size_t ComputeDecodedSizeBase64(const char *in, size_t inLength);
|
||||
|
||||
/** Decode a Base64-encoded string
|
||||
*
|
||||
* @param in Characters to decode.
|
||||
* @param inLength Number of characters to decode.
|
||||
* @param out Pointer where we will store the decoded data.
|
||||
* @param maxOutLength Size of output buffer.
|
||||
* @return size of the decoded data (number of bytes)*/
|
||||
size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength);
|
||||
|
||||
char EncodeBase64(char byte);
|
||||
|
||||
/** Encode bytes in base64-encoding
|
||||
*
|
||||
* @param data Binary data to encode.
|
||||
* @param inLength Number of bytes to encode.
|
||||
* @return base64-encoded string*/
|
||||
std::string EncodeBase64(const char *data, size_t length);
|
||||
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_UTIL_H
|
@ -1,76 +0,0 @@
|
||||
Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
******************************************************************************
|
||||
|
||||
AN EXCEPTION applies to all files in the ./test/models-nonbsd folder.
|
||||
These are 3d models for testing purposes, from various free sources
|
||||
on the internet. They are - unless otherwise stated - copyright of
|
||||
their respective creators, which may impose additional requirements
|
||||
on the use of their work. For any of these models, see
|
||||
<model-name>.source.txt for more legal information. Contact us if you
|
||||
are a copyright holder and believe that we credited you improperly or
|
||||
if you don't want your files to appear in the repository.
|
||||
|
||||
|
||||
******************************************************************************
|
||||
|
||||
Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
http://code.google.com/p/poly2tri/
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -1,197 +0,0 @@
|
||||
# Open Source FBX Specification for the Importer
|
||||
|
||||
The goal of this document is to make everything in FBX clearly stated, any errors will be corrected over time this
|
||||
is a first draft.
|
||||
|
||||
## fbx parser - originally from assimp
|
||||
|
||||
- Folder: /modules/fbx/fbx_parser
|
||||
- Upstream: assimp
|
||||
- Original Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
This can never be updated from upstream, we have heavily modified the parser to provide memory safety and add some
|
||||
functionality. If anything we should give this parser back to assimp at some point as it has a lot of new features.
|
||||
|
||||
# Updating assimp fbx parser
|
||||
|
||||
Don't. it's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed.
|
||||
|
||||
Many days were put into rewriting the parser to use safe code and safe memory accessors.
|
||||
|
||||
# File Headers
|
||||
|
||||
FBX Binaries start with the header "Kaydara FBX Binary"
|
||||
|
||||
FBX ASCII documents contain a larger header, sometimes with copyright information for a file.
|
||||
|
||||
Detecting these is pretty simple.
|
||||
|
||||
# What is an OP link?
|
||||
It's an object to property link. It lists the properties for that object in some cases. Source and destination based by
|
||||
ID.
|
||||
|
||||
# What is a OO link?
|
||||
Its an object to object link, it contains the ID source and destination ID.
|
||||
|
||||
# FBX Node connections
|
||||
|
||||
Nodes in FBX are connected using OO links, This means Object to Object.
|
||||
|
||||
FBX has a single other kind of link which is Object Property, this is used for Object to Property Links, this can be
|
||||
extra attributes, defaults, or even some simple settings.
|
||||
|
||||
# Bones / Joints / Locators
|
||||
|
||||
Bones in FBX are nodes, they initially have the Model:: Type, then have links to SubDeformer the sub deformer
|
||||
is part of the skin there is also an explicit Skin link, which then links to the geometry using OO links in the
|
||||
document.
|
||||
|
||||
# Rotation Order in FBX compared to Godot
|
||||
|
||||
**Godot uses the rotation order:** YXZ
|
||||
|
||||
**FBX has dynamic rotation order to prevent gimbal lock with complex animations**
|
||||
|
||||
```cpp
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
RotOrder_SphericXYZ // nobody uses this - as far as we can tell
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
# Pivot transforms
|
||||
|
||||
### Pivot description:
|
||||
- Maya and 3DS max consider everything to be in node space (bones joints, skins, lights, cameras, etc)
|
||||
- Everything is a node, this means essentially nodes are auto or variants
|
||||
- They are local to the node in the tree.
|
||||
- They are used to calculate where a node is in space
|
||||
```c++
|
||||
// For a better reference you can check editor_scene_importer_fbx.h
|
||||
// references: GenFBXTransform / read the data in
|
||||
// references: ComputePivotTransform / run the calculation
|
||||
// This is the local pivot transform for the node, not the global transforms
|
||||
Transform ComputePivotTransform(
|
||||
Transform chain[TransformationComp_MAXIMUM],
|
||||
Transform &geometric_transform) {
|
||||
|
||||
// Maya pivots
|
||||
Transform T = chain[TransformationComp_Translation];
|
||||
Transform Roff = chain[TransformationComp_RotationOffset];
|
||||
Transform Rp = chain[TransformationComp_RotationPivot];
|
||||
Transform Rpre = chain[TransformationComp_PreRotation];
|
||||
Transform R = chain[TransformationComp_Rotation];
|
||||
Transform Rpost = chain[TransformationComp_PostRotation];
|
||||
Transform Soff = chain[TransformationComp_ScalingOffset];
|
||||
Transform Sp = chain[TransformationComp_ScalingPivot];
|
||||
Transform S = chain[TransformationComp_Scaling];
|
||||
|
||||
// 3DS Max Pivots
|
||||
Transform OT = chain[TransformationComp_GeometricTranslation];
|
||||
Transform OR = chain[TransformationComp_GeometricRotation];
|
||||
Transform OS = chain[TransformationComp_GeometricScaling];
|
||||
|
||||
// Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node)
|
||||
geometric_transform = OT * OR * OS;
|
||||
// Calculate standard maya pivots
|
||||
return T * Roff * Rp * Rpre * R * Rpost.inverse() * Rp.inverse() * Soff * Sp * S * Sp.inverse();
|
||||
}
|
||||
```
|
||||
|
||||
# Transform inheritance for FBX Nodes
|
||||
|
||||
The goal of below is to explain why they implement this in the first place.
|
||||
|
||||
The use case is to make nodes have an option to override their local scaling or to make scaling influenced by orientation, which i would imagine would be useful for when you need to rotate a node and the child to scale based on the orientation rather than setting on the rotation matrix planes.
|
||||
```cpp
|
||||
// not modified the formatting here since this code must remain clear
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
// Parent Rotation * Local Rotation * Parent Scale * Local Scale -- Parent Rotation Offset * Parent ScalingOffset (Local scaling is offset by rotation of parent node)
|
||||
Transform_RSrs = 1, // Parent Rotation * Parent Scale * Local Rotation * Local Scale -- Parent * Local (normal mode)
|
||||
Transform_Rrs = 2, // Parent Rotation * Local Rotation * Local Scale -- Node transform scale is the only relevant component
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
// Local scaling is offset by rotation of parent node
|
||||
Transform_RSrs = 1,
|
||||
// Parent * Local (normal mode)
|
||||
Transform_Rrs = 2,
|
||||
// Node transform scale is the only relevant component
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
```
|
||||
|
||||
# Axis in FBX
|
||||
|
||||
Godot has one format for the declared axis
|
||||
|
||||
AXIS X, AXIS Y, -AXIS Z
|
||||
|
||||
FBX supports any format you can think of. As it has to support Maya and 3DS Max.
|
||||
|
||||
#### FBX File Header
|
||||
```json
|
||||
GlobalSettings: {
|
||||
Version: 1000
|
||||
Properties70: {
|
||||
P: "UpAxis", "int", "Integer", "",1
|
||||
P: "UpAxisSign", "int", "Integer", "",1
|
||||
P: "FrontAxis", "int", "Integer", "",2
|
||||
P: "FrontAxisSign", "int", "Integer", "",1
|
||||
P: "CoordAxis", "int", "Integer", "",0
|
||||
P: "CoordAxisSign", "int", "Integer", "",1
|
||||
P: "OriginalUpAxis", "int", "Integer", "",1
|
||||
P: "OriginalUpAxisSign", "int", "Integer", "",1
|
||||
P: "UnitScaleFactor", "double", "Number", "",1
|
||||
P: "OriginalUnitScaleFactor", "double", "Number", "",1
|
||||
P: "AmbientColor", "ColorRGB", "Color", "",0,0,0
|
||||
P: "DefaultCamera", "KString", "", "", "Producer Perspective"
|
||||
P: "TimeMode", "enum", "", "",6
|
||||
P: "TimeProtocol", "enum", "", "",2
|
||||
P: "SnapOnFrameMode", "enum", "", "",0
|
||||
P: "TimeSpanStart", "KTime", "Time", "",0
|
||||
P: "TimeSpanStop", "KTime", "Time", "",92372316000
|
||||
P: "CustomFrameRate", "double", "Number", "",-1
|
||||
P: "TimeMarker", "Compound", "", ""
|
||||
P: "CurrentTimeMarker", "int", "Integer", "",-1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### FBX FILE declares axis dynamically using FBX header
|
||||
Coord is X
|
||||
Up is Y
|
||||
Front is Z
|
||||
|
||||
#### GODOT - constant reference point
|
||||
Coord is X positive,
|
||||
Y is up positive,
|
||||
Front is -Z negative
|
||||
|
||||
### Explaining MeshGeometry indexing
|
||||
|
||||
Reference type declared:
|
||||
- Direct (directly related to the mapping information type)
|
||||
- IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
|
||||
|
||||
ControlPoint is a vertex
|
||||
* None The mapping is undetermined.
|
||||
* ByVertex There will be one mapping coordinate for each surface control point/vertex.
|
||||
* If you have direct reference type vertices [x]
|
||||
* If you have IndexToDirect reference type the UV
|
||||
* ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
|
||||
* ByPolygon There can be only one mapping coordinate for the whole polygon.
|
||||
* One mapping per polygon polygon x has this normal x
|
||||
* For each vertex of the polygon then set the normal to x
|
||||
* ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
|
||||
* AllSame There can be only one mapping coordinate for the whole surface.
|
@ -1,58 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "register_types.h"
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor_scene_importer_fbx.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
static void _editor_init() {
|
||||
Ref<EditorSceneImporterFBX> import_fbx;
|
||||
import_fbx.instance();
|
||||
ResourceImporterScene::get_singleton()->add_importer(import_fbx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void register_fbx_types() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
|
||||
ClassDB::register_class<EditorSceneImporterFBX>();
|
||||
|
||||
ClassDB::set_current_api(prev_api);
|
||||
|
||||
EditorNode::add_init_callback(_editor_init);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_fbx_types() {
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_REGISTER_TYPES_H
|
||||
#define FBX_REGISTER_TYPES_H
|
||||
|
||||
void register_fbx_types();
|
||||
void unregister_fbx_types();
|
||||
|
||||
#endif // FBX_REGISTER_TYPES_H
|
@ -1,151 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "import_utils.h"
|
||||
|
||||
Vector3 ImportUtils::deg2rad(const Vector3 &p_rotation) {
|
||||
return p_rotation / 180.0 * Math_PI;
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::rad2deg(const Vector3 &p_rotation) {
|
||||
return p_rotation / Math_PI * 180.0;
|
||||
}
|
||||
|
||||
Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
|
||||
Basis ret;
|
||||
|
||||
// FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
|
||||
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
|
||||
switch (mode) {
|
||||
case FBXDocParser::Model::RotOrder_EulerXYZ:
|
||||
ret.set_euler_zyx(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerXZY:
|
||||
ret.set_euler_yzx(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYZX:
|
||||
ret.set_euler_xzy(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYXZ:
|
||||
ret.set_euler_zxy(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZXY:
|
||||
ret.set_euler_yxz(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZYX:
|
||||
ret.set_euler_xyz(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_SphericXYZ:
|
||||
// TODO do this.
|
||||
break;
|
||||
|
||||
default:
|
||||
// If you land here, Please integrate all enums.
|
||||
CRASH_NOW_MSG("This is not unreachable.");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Quat ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
|
||||
return ImportUtils::EulerToBasis(mode, p_rotation);
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation) {
|
||||
// FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
|
||||
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
|
||||
switch (mode) {
|
||||
case FBXDocParser::Model::RotOrder_EulerXYZ:
|
||||
return p_rotation.get_euler_zyx();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerXZY:
|
||||
return p_rotation.get_euler_yzx();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYZX:
|
||||
return p_rotation.get_euler_xzy();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYXZ:
|
||||
return p_rotation.get_euler_zxy();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZXY:
|
||||
return p_rotation.get_euler_yxz();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZYX:
|
||||
return p_rotation.get_euler_xyz();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_SphericXYZ:
|
||||
// TODO
|
||||
return Vector3();
|
||||
|
||||
default:
|
||||
// If you land here, Please integrate all enums.
|
||||
CRASH_NOW_MSG("This is not unreachable.");
|
||||
return Vector3();
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation) {
|
||||
return BasisToEuler(mode, p_rotation);
|
||||
}
|
||||
|
||||
Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) {
|
||||
Transform unscaled = Transform(p_initial.basis, p_initial.origin * p_scale);
|
||||
ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform(), "det is zero unscaled?");
|
||||
return unscaled;
|
||||
}
|
||||
|
||||
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) {
|
||||
ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necessary");
|
||||
// Using long double to make sure that normal is computed for even really tiny objects.
|
||||
typedef long double ldouble;
|
||||
ldouble x = 0.0;
|
||||
ldouble y = 0.0;
|
||||
ldouble z = 0.0;
|
||||
for (size_t i = 0; i < p_vertices.size(); i += 1) {
|
||||
const Vector3 current = p_vertices[i];
|
||||
const Vector3 next = p_vertices[(i + 1) % p_vertices.size()];
|
||||
x += (ldouble(current.y) - ldouble(next.y)) * (ldouble(current.z) + ldouble(next.z));
|
||||
y += (ldouble(current.z) - ldouble(next.z)) * (ldouble(current.x) + ldouble(next.x));
|
||||
z += (ldouble(current.x) - ldouble(next.x)) * (ldouble(current.y) + ldouble(next.y));
|
||||
}
|
||||
const ldouble l2 = x * x + y * y + z * z;
|
||||
if (l2 == 0.0) {
|
||||
return (p_vertices[0] - p_vertices[1]).normalized().cross((p_vertices[0] - p_vertices[2]).normalized()).normalized();
|
||||
} else {
|
||||
const double l = Math::sqrt(double(l2));
|
||||
return Vector3(x / l, y / l, z / l);
|
||||
}
|
||||
}
|
@ -1,401 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_UTILS_FBX_IMPORTER_H
|
||||
#define IMPORT_UTILS_FBX_IMPORTER_H
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
|
||||
#include "data/import_state.h"
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
/**
|
||||
* Import Utils
|
||||
* Conversion tools / glue code to convert from FBX to Godot
|
||||
*/
|
||||
class ImportUtils {
|
||||
public:
|
||||
/// Convert a vector from degrees to radians.
|
||||
static Vector3 deg2rad(const Vector3 &p_rotation);
|
||||
|
||||
/// Convert a vector from radians to degrees.
|
||||
static Vector3 rad2deg(const Vector3 &p_rotation);
|
||||
|
||||
/// Converts rotation order vector (in rad) to quaternion.
|
||||
static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
|
||||
|
||||
/// Converts rotation order vector (in rad) to quaternion.
|
||||
static Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
|
||||
|
||||
/// Converts basis into rotation order vector (in rad).
|
||||
static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
|
||||
|
||||
/// Converts quaternion into rotation order vector (in rad).
|
||||
static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation);
|
||||
|
||||
static void debug_xform(String name, const Transform &t) {
|
||||
print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
|
||||
static String FBXNodeToName(const std::string &name) {
|
||||
// strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
|
||||
// this causes ambiguities, well possible between empty identifiers,
|
||||
// such as "Model::" and ""). Make sure the behaviour is consistent
|
||||
// across multiple calls to FixNodeName().
|
||||
|
||||
// We must remove this from the name
|
||||
// Some bones have this
|
||||
// SubDeformer::
|
||||
// Meshes, Joints have this, some other IK elements too.
|
||||
// Model::
|
||||
|
||||
String node_name = String(name.c_str());
|
||||
|
||||
if (node_name.substr(0, 7) == "Model::") {
|
||||
node_name = node_name.substr(7, node_name.length() - 7);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 13) == "SubDeformer::") {
|
||||
node_name = node_name.substr(13, node_name.length() - 13);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 11) == "AnimStack::") {
|
||||
node_name = node_name.substr(11, node_name.length() - 11);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 15) == "AnimCurveNode::") {
|
||||
node_name = node_name.substr(15, node_name.length() - 15);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 11) == "AnimCurve::") {
|
||||
node_name = node_name.substr(11, node_name.length() - 11);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 10) == "Geometry::") {
|
||||
node_name = node_name.substr(10, node_name.length() - 10);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 10) == "Material::") {
|
||||
node_name = node_name.substr(10, node_name.length() - 10);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 9) == "Texture::") {
|
||||
node_name = node_name.substr(9, node_name.length() - 9);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
static std::string FBXAnimMeshName(const std::string &name) {
|
||||
if (name.length()) {
|
||||
size_t indexOf = name.find_first_of("::");
|
||||
if (indexOf != std::string::npos && indexOf < name.size() - 2) {
|
||||
return name.substr(indexOf + 2);
|
||||
}
|
||||
}
|
||||
return name.length() ? name : "AnimMesh";
|
||||
}
|
||||
|
||||
static Vector3 safe_import_vector3(const Vector3 &p_vec) {
|
||||
Vector3 vector = p_vec;
|
||||
if (Math::is_equal_approx(0, vector.x)) {
|
||||
vector.x = 0;
|
||||
}
|
||||
|
||||
if (Math::is_equal_approx(0, vector.y)) {
|
||||
vector.y = 0;
|
||||
}
|
||||
|
||||
if (Math::is_equal_approx(0, vector.z)) {
|
||||
vector.z = 0;
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
static void debug_xform(String name, const Basis &t) {
|
||||
//print_verbose(name + " rotation: " + (t.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
|
||||
static Vector3 FixAxisConversions(Vector3 input) {
|
||||
return Vector3(input.x, input.y, input.z);
|
||||
}
|
||||
|
||||
static void AlignMeshAxes(std::vector<Vector3> &vertex_data) {
|
||||
for (size_t x = 0; x < vertex_data.size(); x++) {
|
||||
vertex_data[x] = FixAxisConversions(vertex_data[x]);
|
||||
}
|
||||
}
|
||||
|
||||
struct AssetImportFbx {
|
||||
enum ETimeMode {
|
||||
TIME_MODE_DEFAULT = 0,
|
||||
TIME_MODE_120 = 1,
|
||||
TIME_MODE_100 = 2,
|
||||
TIME_MODE_60 = 3,
|
||||
TIME_MODE_50 = 4,
|
||||
TIME_MODE_48 = 5,
|
||||
TIME_MODE_30 = 6,
|
||||
TIME_MODE_30_DROP = 7,
|
||||
TIME_MODE_NTSC_DROP_FRAME = 8,
|
||||
TIME_MODE_NTSC_FULL_FRAME = 9,
|
||||
TIME_MODE_PAL = 10,
|
||||
TIME_MODE_CINEMA = 11,
|
||||
TIME_MODE_1000 = 12,
|
||||
TIME_MODE_CINEMA_ND = 13,
|
||||
TIME_MODE_CUSTOM = 14,
|
||||
TIME_MODE_TIME_MODE_COUNT = 15
|
||||
};
|
||||
enum UpAxis {
|
||||
UP_VECTOR_AXIS_X = 1,
|
||||
UP_VECTOR_AXIS_Y = 2,
|
||||
UP_VECTOR_AXIS_Z = 3
|
||||
};
|
||||
enum FrontAxis {
|
||||
FRONT_PARITY_EVEN = 1,
|
||||
FRONT_PARITY_ODD = 2,
|
||||
};
|
||||
|
||||
enum CoordAxis {
|
||||
COORD_RIGHT = 0,
|
||||
COORD_LEFT = 1
|
||||
};
|
||||
};
|
||||
|
||||
/** Get fbx fps for time mode meta data
|
||||
*/
|
||||
static float get_fbx_fps(int32_t time_mode) {
|
||||
switch (time_mode) {
|
||||
case AssetImportFbx::TIME_MODE_DEFAULT:
|
||||
return 24;
|
||||
case AssetImportFbx::TIME_MODE_120:
|
||||
return 120;
|
||||
case AssetImportFbx::TIME_MODE_100:
|
||||
return 100;
|
||||
case AssetImportFbx::TIME_MODE_60:
|
||||
return 60;
|
||||
case AssetImportFbx::TIME_MODE_50:
|
||||
return 50;
|
||||
case AssetImportFbx::TIME_MODE_48:
|
||||
return 48;
|
||||
case AssetImportFbx::TIME_MODE_30:
|
||||
return 30;
|
||||
case AssetImportFbx::TIME_MODE_30_DROP:
|
||||
return 30;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME:
|
||||
return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME:
|
||||
return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_PAL:
|
||||
return 25;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA:
|
||||
return 24;
|
||||
case AssetImportFbx::TIME_MODE_1000:
|
||||
return 1000;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA_ND:
|
||||
return 23.976f;
|
||||
case AssetImportFbx::TIME_MODE_CUSTOM:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float get_fbx_fps(const FBXDocParser::FileGlobalSettings *FBXSettings) {
|
||||
int time_mode = FBXSettings->TimeMode();
|
||||
|
||||
// get the animation FPS
|
||||
float frames_per_second = get_fbx_fps(time_mode);
|
||||
|
||||
// handle animation custom FPS time.
|
||||
if (time_mode == ImportUtils::AssetImportFbx::TIME_MODE_CUSTOM) {
|
||||
print_verbose("FBX Animation has custom FPS setting");
|
||||
frames_per_second = FBXSettings->CustomFrameRate();
|
||||
|
||||
// not our problem this is the modeller, we can print as an error so they can fix the source.
|
||||
if (frames_per_second == 0) {
|
||||
print_error("Custom animation time in file is set to 0 value, animation won't play, please edit your file to correct the FPS value");
|
||||
}
|
||||
}
|
||||
return frames_per_second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find hardcoded textures from assimp which could be in many different directories
|
||||
*/
|
||||
|
||||
/**
|
||||
* set_texture_mapping_mode
|
||||
* Helper to check the mapping mode of the texture (repeat, clamp and mirror)
|
||||
*/
|
||||
// static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
|
||||
// ERR_FAIL_COND(texture.is_null());
|
||||
// ERR_FAIL_COND(map_mode == NULL);
|
||||
// aiTextureMapMode tex_mode = map_mode[0];
|
||||
|
||||
// int32_t flags = Texture::FLAGS_DEFAULT;
|
||||
// if (tex_mode == aiTextureMapMode_Wrap) {
|
||||
// //Default
|
||||
// } else if (tex_mode == aiTextureMapMode_Clamp) {
|
||||
// flags = flags & ~Texture::FLAG_REPEAT;
|
||||
// } else if (tex_mode == aiTextureMapMode_Mirror) {
|
||||
// flags = flags | Texture::FLAG_MIRRORED_REPEAT;
|
||||
// }
|
||||
// texture->set_flags(flags);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Load or load from cache image :)
|
||||
* We need to upgrade this in the later version :) should not be hard
|
||||
*/
|
||||
//static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path){
|
||||
|
||||
// Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path);
|
||||
|
||||
// // if our cache contains this image then don't bother
|
||||
// if (match) {
|
||||
// return match->get();
|
||||
// }
|
||||
|
||||
// Vector<String> split_path = p_path.get_basename().split("*");
|
||||
// if (split_path.size() == 2) {
|
||||
// size_t texture_idx = split_path[1].to_int();
|
||||
// ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
|
||||
// aiTexture *tex = p_scene->mTextures[texture_idx];
|
||||
// String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
|
||||
// filename = filename.get_file();
|
||||
// print_verbose("Open Asset Import: Loading embedded texture " + filename);
|
||||
// if (tex->mHeight == 0) {
|
||||
// if (tex->CheckFormat("png")) {
|
||||
// Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// } else if (tex->CheckFormat("jpg")) {
|
||||
// Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// } else if (tex->CheckFormat("dds")) {
|
||||
// ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
|
||||
// }
|
||||
// } else {
|
||||
// Ref<Image> img;
|
||||
// img.instance();
|
||||
// PoolByteArray arr;
|
||||
// uint32_t size = tex->mWidth * tex->mHeight;
|
||||
// arr.resize(size);
|
||||
// memcpy(arr.write().ptr(), tex->pcData, size);
|
||||
// ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
|
||||
// //ARGB8888 to RGBA8888
|
||||
// for (int32_t i = 0; i < arr.size() / 4; i++) {
|
||||
// arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
|
||||
// arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
|
||||
// arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
|
||||
// arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
|
||||
// }
|
||||
// img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// }
|
||||
// return Ref<Image>();
|
||||
// } else {
|
||||
// Ref<Texture> texture = ResourceLoader::load(p_path);
|
||||
// ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
|
||||
// Ref<Image> image = texture->get_data();
|
||||
// ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, image);
|
||||
// return image;
|
||||
// }
|
||||
|
||||
// return Ref<Image>();
|
||||
//}
|
||||
|
||||
// /* create texture from assimp data, if found in path */
|
||||
// static bool CreateAssimpTexture(
|
||||
// AssimpImporter::ImportState &state,
|
||||
// aiString texture_path,
|
||||
// String &filename,
|
||||
// String &path,
|
||||
// AssimpImageData &image_state) {
|
||||
// filename = get_raw_string_from_assimp(texture_path);
|
||||
// path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
|
||||
// bool found = false;
|
||||
// find_texture_path(state.path, path, found);
|
||||
// if (found) {
|
||||
// image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
|
||||
// if (image_state.raw_image.is_valid()) {
|
||||
// image_state.texture.instance();
|
||||
// image_state.texture->create_from_image(image_state.raw_image);
|
||||
// image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
// /** GetAssimpTexture
|
||||
// * Designed to retrieve textures for you
|
||||
// */
|
||||
// static bool GetAssimpTexture(
|
||||
// AssimpImporter::ImportState &state,
|
||||
// aiMaterial *ai_material,
|
||||
// aiTextureType texture_type,
|
||||
// String &filename,
|
||||
// String &path,
|
||||
// AssimpImageData &image_state) {
|
||||
// aiString ai_filename = aiString();
|
||||
// if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) {
|
||||
// return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
// Apply the transforms so the basis will have scale 1.
|
||||
Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale);
|
||||
|
||||
/// Uses the Newell's method to compute any polygon normal.
|
||||
/// The polygon must be at least size of 3 or bigger.
|
||||
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices);
|
||||
|
||||
#endif // IMPORT_UTILS_FBX_IMPORTER_H
|
@ -1,48 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* validation_tools.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 "validation_tools.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/print_string.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
ValidationTracker::Entries *ValidationTracker::entries_singleton = memnew(ValidationTracker::Entries);
|
||||
|
||||
// for printing our CSV to dump validation problems of files
|
||||
// later we can make some agnostic tooling for this but this is fine for the time being.
|
||||
void ValidationTracker::Entries::add_validation_error(String asset_path, String message) {
|
||||
print_error(message);
|
||||
// note: implementation is static
|
||||
validation_entries[asset_path].push_back(message);
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
@ -1,94 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* validation_tools.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_VALIDATION_TOOLS_H
|
||||
#define FBX_VALIDATION_TOOLS_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/local_vector.h"
|
||||
#include "core/map.h"
|
||||
#include "core/ustring.h"
|
||||
#include <core/io/json.h>
|
||||
#include <core/os/file_access.h>
|
||||
#include <scene/3d/path.h>
|
||||
|
||||
class ValidationTracker {
|
||||
protected:
|
||||
struct Entries {
|
||||
Map<String, LocalVector<String>> validation_entries = Map<String, LocalVector<String>>();
|
||||
|
||||
// for printing our CSV to dump validation problems of files
|
||||
// later we can make some agnostic tooling for this but this is fine for the time being.
|
||||
void add_validation_error(String asset_path, String message);
|
||||
void print_to_csv() {
|
||||
print_verbose("Exporting assset validation log please wait");
|
||||
String massive_log_file;
|
||||
|
||||
String csv_header = "file_path, error message, extra data\n";
|
||||
massive_log_file += csv_header;
|
||||
|
||||
for (Map<String, LocalVector<String>>::Element *element = validation_entries.front(); element; element = element->next()) {
|
||||
for (unsigned int x = 0; x < element->value().size(); x++) {
|
||||
const String &line_entry = element->key() + ", " + element->value()[x].c_escape() + "\n";
|
||||
massive_log_file += line_entry;
|
||||
}
|
||||
}
|
||||
|
||||
String path = "asset_validation_errors.csv";
|
||||
Error err;
|
||||
FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err);
|
||||
if (!file || err) {
|
||||
if (file) {
|
||||
memdelete(file);
|
||||
}
|
||||
print_error("ValidationTracker Error - failed to create file - path: %s\n" + path);
|
||||
return;
|
||||
}
|
||||
|
||||
file->store_string(massive_log_file);
|
||||
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
|
||||
print_error("ValidationTracker Error - failed to write to file - path: %s\n" + path);
|
||||
}
|
||||
file->close();
|
||||
memdelete(file);
|
||||
}
|
||||
};
|
||||
// asset path, error messages
|
||||
static Entries *entries_singleton;
|
||||
|
||||
public:
|
||||
static Entries *get_singleton() {
|
||||
return entries_singleton;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
#endif // FBX_VALIDATION_TOOLS_H
|
Loading…
Reference in New Issue
Block a user